/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2009 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.modules.gui.base.parameters;
import java.awt.Color;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;
import org.pentaho.reporting.engine.classic.core.util.beans.BeanException;
import org.pentaho.reporting.engine.classic.core.util.beans.ConverterRegistry;
/**
* Todo: Document me!
* <p/>
* Date: 14.05.2009
* Time: 20:34:42
*
* @author Thomas Morgner.
*/
public class TextComponentEditHandler implements Runnable, DocumentListener, ActionListener
{
private Class type;
private String keyName;
private JTextComponent textComponent;
private ParameterUpdateContext updateContext;
private Format formatter;
private Color color;
private boolean inProgress;
private boolean adjustingToExternalInput;
public TextComponentEditHandler(final Class type,
final String keyName,
final JTextComponent textComponent,
final ParameterUpdateContext updateContext,
final Format formatter)
{
this.type = type;
this.keyName = keyName;
this.textComponent = textComponent;
this.updateContext = updateContext;
this.formatter = formatter;
this.color = this.textComponent.getBackground();
if (color == null)
{
color = SystemColor.text;
}
}
public boolean isAdjustingToExternalInput()
{
return adjustingToExternalInput;
}
public void setAdjustingToExternalInput(final boolean adjustingToExternalInput)
{
this.adjustingToExternalInput = adjustingToExternalInput;
}
protected Class getType()
{
return type;
}
/**
* Gives notification that there was an insert into the document. The range given by the DocumentEvent bounds the
* freshly inserted region.
*
* @param e the document event
*/
public void insertUpdate(final DocumentEvent e)
{
convertParameterValue();
}
/**
* Gives notification that a portion of the document has been removed. The range is given in terms of what the view
* last saw (that is, before updating sticky positions).
*
* @param e the document event
*/
public void removeUpdate(final DocumentEvent e)
{
convertParameterValue();
}
/**
* Gives notification that an attribute or set of attributes changed.
*
* @param e the document event
*/
public void changedUpdate(final DocumentEvent e)
{
convertParameterValue();
}
private void convertParameterValue()
{
if (inProgress)
{
return;
}
inProgress = true;
SwingUtilities.invokeLater(this);
}
public void run()
{
convert(false);
}
protected void convert(final boolean autoUpdate)
{
try
{
final String text = textComponent.getText();
textComponent.setBackground(color);
updateContext.setParameterValue(keyName, convertValue(text), autoUpdate);
}
catch (BeanException e)
{
// ignore, do not update (yet).
textComponent.setBackground(Color.RED);
}
finally
{
inProgress = false;
}
}
protected Object convertValue(final String text) throws BeanException
{
if (text == null)
{
return null;
}
if (formatter != null)
{
try
{
final Object o = formatter.parseObject(text);
// this magic converts the date or number value to the real type.
// the formatter always returns doubles/bigdecimals or java.util.Dates
// but we may need sql-dates, long-objects etc ..
final String asText = ConverterRegistry.toAttributeValue(o);
return ConverterRegistry.toPropertyValue(asText, getType());
}
catch (ParseException e)
{
throw new BeanException("Failed to format object");
}
}
if (Object.class == type ||
String.class == type)
{
return text;
}
return ConverterRegistry.toPropertyValue(text, type);
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed(final ActionEvent e)
{
convert(true);
}
public static Format createFormat(final String formatString,
final Locale locale,
final TimeZone timeZone,
final Class parameterType)
{
if (formatString == null || parameterType == null)
{
return null;
}
if (Number.class.isAssignableFrom(parameterType))
{
try
{
final DecimalFormat decimalFormat = new DecimalFormat(formatString, new DecimalFormatSymbols(locale));
decimalFormat.setParseBigDecimal(true);
return decimalFormat;
}
catch (Exception e)
{
// well, seems that was not a number format then ...
}
}
if (Date.class.isAssignableFrom(parameterType))
{
try
{
final SimpleDateFormat dateFormat = new SimpleDateFormat(formatString, locale);
dateFormat.setLenient(false);
dateFormat.setTimeZone(timeZone);
return dateFormat;
}
catch (Exception e)
{
// well, seems that was not a date format either ...
}
}
return null;
}
}