/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.server.headlessclient.dataui;
import java.text.Format;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.util.convert.ConversionException;
import org.apache.wicket.util.convert.IConverter;
import com.servoy.j2db.dataprocessing.IDisplayData;
import com.servoy.j2db.ui.IComponent;
import com.servoy.j2db.ui.IProviderStylePropertyChanges;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.FormatParser.ParsedFormat;
import com.servoy.j2db.util.StateFullSimpleDateFormat;
import com.servoy.j2db.util.Utils;
/**
* A {@link IConverter} that uses {@link Format} to convert value to string or string to value.
*
* @author jcompagner
*/
final class FormatConverter implements IConverter
{
private static final long serialVersionUID = 1L;
private final FormComponent formComponent;
private final Format displayFormatter;
private final Format editFormatter;
private final WebEventExecutor eventExecutor;
private final ParsedFormat format;
FormatConverter(FormComponent field, WebEventExecutor eventExecutor, Format displayFormatter, ParsedFormat format)
{
this.formComponent = field;
this.eventExecutor = eventExecutor;
this.displayFormatter = displayFormatter;
this.editFormatter = null;
this.format = format;
}
FormatConverter(FormComponent field, WebEventExecutor eventExecutor, Format displayFormatter, Format editFormatter, ParsedFormat format)
{
this.formComponent = field;
this.eventExecutor = eventExecutor;
this.displayFormatter = displayFormatter;
this.editFormatter = editFormatter;
this.format = format;
}
/**
* @see wicket.util.convert.IConverter#convertToObject(java.lang.String, java.util.Locale)
*/
public Object convertToObject(String value, Locale locale)
{
if (format == null || value == null) return null;
try
{
if (!eventExecutor.getValidationEnabled()) return value;
if (editFormatter != null)
{
try
{
return convertString(value, editFormatter);
}
catch (ParseException pe)
{
return convertString(value, displayFormatter);
}
}
else
{
return convertString(value, displayFormatter);
}
}
catch (Exception ex)
{
String extraMsg = ""; //$NON-NLS-1$
if (formComponent instanceof IComponent && ((IComponent)formComponent).getName() != null)
{
extraMsg = " on component " + ((IComponent)formComponent).getName(); //$NON-NLS-1$
}
if (formComponent instanceof IDisplayData)
{
extraMsg += " with dataprovider: " + ((IDisplayData)formComponent).getDataProviderID(); //$NON-NLS-1$
}
throw new ConversionException("Can't convert from string '" + value + "' to object with format: " + format.getEditFormat() + extraMsg, ex).setConverter(this); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* @param str
* @return
* @throws ParseException
*/
private Object convertString(String value, Format formatter) throws ParseException
{
if (format.getDisplayFormat() != null && format.getDisplayFormat().equals(value)) return null;
String str = value;
if (format.isMask())
{
if (format.getPlaceHolderCharacter() != 0)
{
str = str.replace(format.getPlaceHolderCharacter(), ' ');
}
String placeHolder = format.getDisplayFormat().replace('y', ' ').replace('M', ' ').replace('w', ' ').replace('W', ' ').replace('D', ' ').replace(
'd', ' ').replace('F', ' ').replace('a', ' ').replace('H', ' ').replace('k', ' ').replace('K', ' ').replace('h', ' ').replace('m', ' ').replace(
's', ' ').replace('S', ' ');
if (placeHolder.endsWith(str)) return null;
}
str = value.toString().trim();
if ("".equals(str)) return null; //$NON-NLS-1$
Object result;
if (formatter instanceof StateFullSimpleDateFormat)
{
((StateFullSimpleDateFormat)formatter).setOriginal((Date)formComponent.getModelObject());
formatter.parseObject(str);
result = ((StateFullSimpleDateFormat)formatter).getMergedDate();
}
else
{
result = formatter.parseObject(str);
}
if (formComponent instanceof IProviderStylePropertyChanges && !Utils.equalObjects(value, formatter.format(result)))
{
// this can happen for example when date formatting uses lenient mode (hour 10:65 will be valid and interpreted as 11:05) - what the user entered is
// valid and represents the same date, but re-rendering the component need to happen to display it normally...
// another example is when formatting numbers with "." as grouping separator and user types "0.7" => after leaving the field it should be shown as "7"
((IProviderStylePropertyChanges)formComponent).getStylePropertyChanges().setValueChanged();
}
return result;
}
public String convertToEditString(Object value, Locale locale)
{
return convertToString(value, editFormatter);
}
/**
* @see wicket.util.convert.IConverter#convertToString(java.lang.Object, java.util.Locale)
*/
public String convertToString(Object value, Locale locale)
{
return convertToString(value, displayFormatter);
}
@SuppressWarnings("nls")
private String convertToString(Object value, Format formatter)
{
// if value is already a string (for example it was a converted by a converter) just return that.
if (value == null || value instanceof String) return (String)value;
if (!eventExecutor.getValidationEnabled() && value instanceof String) return (String)value;
try
{
return formatter.format(value);
}
catch (Exception ex)
{
String extraMsg = ""; //$NON-NLS-1$
if (formComponent instanceof IComponent && ((IComponent)formComponent).getName() != null)
{
extraMsg = " on component " + ((IComponent)formComponent).getName();
}
if (formComponent instanceof IDisplayData)
{
extraMsg += " with dataprovider: " + ((IDisplayData)formComponent).getDataProviderID();
}
String className = value != null ? value.getClass().getSimpleName() : ""; //$NON-NLS-1$
Debug.error("Can't parse the " + value + " (" + className + ") to a string with format: " + format.getDisplayFormat() + extraMsg, ex);
return value.toString();
}
}
public void setLenient(boolean lenient)
{
if (editFormatter instanceof StateFullSimpleDateFormat) ((StateFullSimpleDateFormat)editFormatter).setLenient(lenient);
if (displayFormatter instanceof StateFullSimpleDateFormat) ((StateFullSimpleDateFormat)displayFormatter).setLenient(lenient);
}
}