/*
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.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import javax.swing.border.Border;
import javax.swing.event.ListDataListener;
import javax.swing.text.Document;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.behavior.IBehavior;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.IModelComparator;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.convert.ConversionException;
import org.apache.wicket.util.convert.IConverter;
import org.apache.wicket.util.string.AppendingStringBuffer;
import org.apache.wicket.util.string.Strings;
import org.apache.wicket.validation.IValidationError;
import com.servoy.base.util.ITagResolver;
import com.servoy.j2db.FormManager;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.IMainContainer;
import com.servoy.j2db.IScriptExecuter;
import com.servoy.j2db.IServiceProvider;
import com.servoy.j2db.dataprocessing.CustomValueList;
import com.servoy.j2db.dataprocessing.GlobalMethodValueList;
import com.servoy.j2db.dataprocessing.IDisplayData;
import com.servoy.j2db.dataprocessing.IEditListener;
import com.servoy.j2db.dataprocessing.IValueList;
import com.servoy.j2db.persistence.Column;
import com.servoy.j2db.persistence.IColumnTypes;
import com.servoy.j2db.persistence.ISupportTextSetup;
import com.servoy.j2db.scripting.JSEvent;
import com.servoy.j2db.server.headlessclient.MainPage;
import com.servoy.j2db.server.headlessclient.mask.MaskBehavior;
import com.servoy.j2db.ui.IComponent;
import com.servoy.j2db.ui.IEventExecutor;
import com.servoy.j2db.ui.IFieldComponent;
import com.servoy.j2db.ui.IFormattingComponent;
import com.servoy.j2db.ui.ILabel;
import com.servoy.j2db.ui.IProviderStylePropertyChanges;
import com.servoy.j2db.ui.IStylePropertyChanges;
import com.servoy.j2db.ui.ISupportInputSelection;
import com.servoy.j2db.ui.ISupportOnRender;
import com.servoy.j2db.ui.ISupportSimulateBounds;
import com.servoy.j2db.ui.ISupportSimulateBoundsProvider;
import com.servoy.j2db.ui.ISupportSpecialClientProperty;
import com.servoy.j2db.ui.ISupportValueList;
import com.servoy.j2db.ui.ISupportWebBounds;
import com.servoy.j2db.ui.scripting.AbstractRuntimeField;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.FormatParser;
import com.servoy.j2db.util.FormatParser.ParsedFormat;
import com.servoy.j2db.util.IDestroyable;
import com.servoy.j2db.util.RoundHalfUpDecimalFormat;
import com.servoy.j2db.util.StateFullSimpleDateFormat;
import com.servoy.j2db.util.Text;
import com.servoy.j2db.util.UIUtils;
import com.servoy.j2db.util.Utils;
import com.servoy.j2db.util.text.FixedMaskFormatter;
/**
* Represents a text (single line) field in the webbrowser.
*
* @author jcompagner
*/
public class WebDataField extends TextField<Object>
implements IFieldComponent, IDisplayData, IProviderStylePropertyChanges, ISupportWebBounds, IRightClickListener, ISupportValueList, ISupportInputSelection,
ISupportSpecialClientProperty, IFormattingComponent, ISupportSimulateBoundsProvider, IDestroyable, ISupportOnRender
{
/**
* @author jcompagner
*
*/
private final class NumberValidationModel extends AbstractReadOnlyModel<CharSequence>
{
private final boolean decimal;
NumberValidationModel(boolean decimal)
{
this.decimal = decimal;
}
@SuppressWarnings("nls")
@Override
public CharSequence getObject()
{
DecimalFormatSymbols dfs = RoundHalfUpDecimalFormat.getDecimalFormatSymbols(application.getLocale());
AppendingStringBuffer sb = new AppendingStringBuffer();
sb.append("return Servoy.Validation.numbersonly(event,");
sb.append(decimal);
sb.append(",'");
sb.append(dfs.getDecimalSeparator());
sb.append("','");
sb.append(dfs.getGroupingSeparator());
sb.append("','");
sb.append(dfs.getCurrencySymbol());
sb.append("','");
sb.append(dfs.getPercent());
sb.append("',this,");
sb.append(parsedFormat.getMaxLength() == null ? -1 : parsedFormat.getMaxLength().intValue());
sb.append(");");
return sb;
}
}
/**
* @author jcompagner
*
*/
private interface ITestFormatsCallback
{
/**
* @param displayValue
* @param editValue
*/
void differentEditAndDisplay(String displayValue, String editValue);
}
private static final long serialVersionUID = 1L;
private static final String NO_COLOR = "NO_COLOR"; //$NON-NLS-1$
// private Cursor cursor;
private boolean needEntireState;
private int dataType;
private Insets margin;
private int horizontalAlignment;
private final WebEventExecutor eventExecutor;
private String inputId;
protected ParsedFormat parsedFormat = FormatParser.parseFormatProperty(null);
// private String completeFormat;
// private String editFormat;
// protected String displayFormat;
FocusIfInvalidAttributeModifier focusIfInvalidAttributeModifier;
protected IConverter converter;
protected IValueList list;
private final AbstractRuntimeField<IFieldComponent> scriptable;
protected final IApplication application;
public WebDataField(IApplication application, AbstractRuntimeField<IFieldComponent> scriptable, String id, IValueList list)
{
this(application, scriptable, id);
this.list = list;
this.horizontalAlignment = ISupportTextSetup.LEFT;
}
public WebDataField(IApplication application, AbstractRuntimeField<IFieldComponent> scriptable, String id)
{
this(application, scriptable, id, (IComponent)null);
}
/**
* @param id
*/
public WebDataField(final IApplication application, final AbstractRuntimeField<IFieldComponent> scriptable, String id, final IComponent enclosingComponent)
{
super(id);
this.horizontalAlignment = ISupportTextSetup.LEFT;
this.application = application;
boolean useAJAX = Utils.getAsBoolean(application.getRuntimeProperties().get("useAJAX")); //$NON-NLS-1$
eventExecutor = new WebEventExecutor(this, useAJAX)
{
@Override
protected Object getSource(Object display)
{
return enclosingComponent != null ? enclosingComponent : super.getSource(display);
}
};
setOutputMarkupPlaceholderTag(true);
setVersioned(false);
add(new AttributeModifier("readonly", true, new Model<String>() //$NON-NLS-1$
{
private static final long serialVersionUID = 1L;
@Override
public String getObject()
{
return (editable ? AttributeModifier.VALUELESS_ATTRIBUTE_REMOVE : AttributeModifier.VALUELESS_ATTRIBUTE_ADD);
}
}));
add(new AttributeModifier("placeholder", true, new Model<String>() //$NON-NLS-1$
{
private static final long serialVersionUID = 1L;
@Override
public String getObject()
{
return application.getI18NMessageIfPrefixed(scriptable.getPlaceholderText());
}
})
{
@Override
public boolean isEnabled(Component component)
{
return super.isEnabled(component) && scriptable.getPlaceholderText() != null;
}
});
add(new SimpleAttributeModifier("autocomplete", "off"));
focusIfInvalidAttributeModifier = new FocusIfInvalidAttributeModifier(this);
add(focusIfInvalidAttributeModifier);
add(StyleAttributeModifierModel.INSTANCE);
add(TooltipAttributeModifier.INSTANCE);
add(new ConsumeEnterAttributeModifier(this, eventExecutor));
add(new FilterBackspaceKeyAttributeModifier(new Model<String>()
{
private static final long serialVersionUID = 1332637522687352873L;
@Override
public String getObject()
{
return editable ? null : FilterBackspaceKeyAttributeModifier.SCRIPT;
}
}));
this.scriptable = scriptable;
}
public void destroy()
{
if (list != null) list.deregister();
}
public final AbstractRuntimeField<IFieldComponent> getScriptObject()
{
return scriptable;
}
/**
* @see org.apache.wicket.Component#getLocale()
*/
@Override
public Locale getLocale()
{
return application.getLocale();
}
@Override
protected Object convertValue(String[] value) throws ConversionException
{
String tmp = value != null && value.length > 0 ? value[0] : null;
if (getConvertEmptyInputStringToNull() && Strings.isEmpty(tmp))
{
return null;
}
return tmp;
}
@Override
public void error(IValidationError error)
{
super.error(error);
setValueValid(false, getModelObject());
}
/*
* _____________________________________________________________ Methods for event handling
*/
public void addScriptExecuter(IScriptExecuter el)
{
eventExecutor.setScriptExecuter(el);
}
public IEventExecutor getEventExecutor()
{
return eventExecutor;
}
public void setEnterCmds(String[] ids, Object[][] args)
{
eventExecutor.setEnterCmds(ids, args);
}
public void setLeaveCmds(String[] ids, Object[][] args)
{
eventExecutor.setLeaveCmds(ids, args);
}
public boolean isValueValid()
{
return isValueValid;
}
private boolean isValueValid = true;
private Object previousValidValue;
private String tmpForeground = NO_COLOR;
public void setValueValid(boolean valid, Object oldVal)
{
application.getRuntimeProperties().put(IServiceProvider.RT_LASTFIELDVALIDATIONFAILED_FLAG, Boolean.valueOf(!valid));
if (!valid)
{
if (valid != isValueValid)
{
getStylePropertyChanges().setChanged();
}
requestFocusToComponent();
}
if (valid == isValueValid)
{
return;
}
isValueValid = valid;
if (!isValueValid)
{
previousValidValue = oldVal;
if (tmpForeground == NO_COLOR)
{
tmpForeground = scriptable.getFgcolor();
scriptable.setFgcolor("red"); //$NON-NLS-1$
}
}
else
{
previousValidValue = null;
if (tmpForeground != NO_COLOR)
{
scriptable.setFgcolor(tmpForeground);
tmpForeground = NO_COLOR;
}
}
}
public void notifyLastNewValueWasChange(final Object oldVal, final Object newVal)
{
if (eventExecutor.hasChangeCmd())
{
application.invokeLater(new Runnable()
{
public void run()
{
WebEventExecutor.setSelectedIndex(WebDataField.this, null, IEventExecutor.MODIFIERS_UNSPECIFIED);
eventExecutor.fireChangeCommand(previousValidValue == null ? oldVal : previousValidValue, newVal, false, WebDataField.this);
}
});
}
else
{
setValueValid(true, null);
}
// if display formats and edit formats are not the same tell the change recorder that the value is changed
// so that the display format is pushed to the web.
testFormats(new ITestFormatsCallback()
{
public void differentEditAndDisplay(String displayValue, String editValue)
{
getStylePropertyChanges().setValueChanged();
}
}, ((oldVal == null) && (newVal != null)));
}
public void setChangeCmd(String id, Object[] args)
{
eventExecutor.setChangeCmd(id, args);
}
public void setActionCmd(String id, Object[] args)
{
eventExecutor.setActionCmd(id, args);
}
private boolean wasEditable;
public void setValidationEnabled(boolean validation)
{
if (eventExecutor.getValidationEnabled() == validation)
{
// web cell based view - reinitializing a component onBeforeRender can result in readonly being set back to true while in find; when validation is reset to false, we must restore find state for the control
if (!validation && !editable && !Boolean.TRUE.equals(application.getClientProperty(IApplication.LEAVE_FIELDS_READONLY_IN_FIND_MODE)))
{
boolean prevEditState = editState;
setEditable(true);// allow search
editState = prevEditState;
}
return;
}
eventExecutor.setValidationEnabled(validation);
boolean prevEditState = editState;
if (validation)
{
setEditable(wasEditable);
}
else
{
wasEditable = editable;
if (!Boolean.TRUE.equals(application.getClientProperty(IApplication.LEAVE_FIELDS_READONLY_IN_FIND_MODE)))
{
setEditable(true);
}
}
editState = prevEditState;
}
public void setSelectOnEnter(boolean b)
{
eventExecutor.setSelectOnEnter(b);
}
//_____________________________________________________________
/**
* @see wicket.Component#getComparator()
*/
@Override
public IModelComparator getModelComparator()
{
return ComponentValueComparator.COMPARATOR;
}
/**
* @see org.apache.wicket.Component#renderHead(org.apache.wicket.markup.html.internal.HtmlHeaderContainer)
*/
@Override
public void renderHead(final HtmlHeaderContainer container)
{
super.renderHead(container);
if (eventExecutor.getValidationEnabled() && isEnabled() && isEditable())
{
container.getHeaderResponse().renderOnDomReadyJavascript("Servoy.Validation.detachDisplayEditFormat('" + getMarkupId() + "');"); //$NON-NLS-1$ //$NON-NLS-2$
testFormats(new ITestFormatsCallback()
{
public void differentEditAndDisplay(String displayValue, String editValue)
{
container.getHeaderResponse().renderOnDomReadyJavascript(
"Servoy.Validation.attachDisplayEditFormat('" + getMarkupId() + "', '" + displayValue + "','" + editValue + "');"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
}, false);
}
if (isEnabled() && isEditable() && Column.mapToDefaultType(dataType) == IColumnTypes.NUMBER)
{
container.getHeaderResponse().renderOnDomReadyJavascript(
"$(function(){$(\"#" + getMarkupId() + "\").numpadDecSeparator({useRegionalSettings: true});});"); //$NON-NLS-1$ //$NON-NLS-2$
}
if (scriptable.getPlaceholderText() != null)
{
container.getHeaderResponse().renderOnLoadJavascript("$('#" + getMarkupId() + "').placeholder();");
}
}
@SuppressWarnings("nls")
private void testFormats(ITestFormatsCallback callback, boolean isChangedFromNullValue)
{
if (isValueValid())
{
if (parsedFormat.hasEditFormat() && getConverter(getType()) instanceof FormatConverter)
{
Object value = getDefaultModelObject();
try
{
String displayValue = converter.convertToString(value, application.getLocale());
String editValue = ((FormatConverter)converter).convertToEditString(value, application.getLocale());
if (!Utils.equalObjects(displayValue, editValue))
{
callback.differentEditAndDisplay(displayValue, editValue);
}
else if (value == null)
{
callback.differentEditAndDisplay("", "");
}
}
catch (Exception e)
{
Debug.error(e);
}
}
else if (Column.mapToDefaultType(dataType) == IColumnTypes.DATETIME && !parsedFormat.isMask())
{
Object value = getDefaultModelObject();
if (((value == null) || isChangedFromNullValue) && editable)
{
callback.differentEditAndDisplay("", parsedFormat.getDisplayFormat());
}
}
}
}
@Override
protected void onRender(final MarkupStream markupStream)
{
super.onRender(markupStream);
getStylePropertyChanges().setRendered();
IModel< ? > model = getInnermostModel();
if (model instanceof RecordItemModel)
{
((RecordItemModel)model).updateRenderedValue(this);
}
}
@Override
protected void onComponentTag(ComponentTag tag)
{
super.onComponentTag(tag);
boolean useAJAX = Utils.getAsBoolean(application.getRuntimeProperties().get("useAJAX")); //$NON-NLS-1$
if (useAJAX)
{
Object oe = scriptable.getClientProperty("ajax.enabled"); //$NON-NLS-1$
if (oe != null) useAJAX = Utils.getAsBoolean(oe);
}
if (!useAJAX)
{
Form< ? > f = getForm();
if (f != null)
{
if (eventExecutor.hasRightClickCmd())
{
CharSequence urlr = urlFor(IRightClickListener.INTERFACE);
// We need a "return false;" so that the context menu is not displayed in the browser.
tag.put("oncontextmenu", f.getJsForInterfaceUrl(urlr) + " return false;"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}
/**
* @see wicket.markup.html.form.FormComponent#getInputName()
*/
@Override
public String getInputName()
{
if (inputId == null)
{
Page page = findPage();
if (page instanceof MainPage)
{
inputId = ((MainPage)page).nextInputNameId();
}
else
{
return super.getInputName();
}
}
return inputId;
}
public IStylePropertyChanges getStylePropertyChanges()
{
return scriptable.getChangesRecorder();
}
/**
* @see com.servoy.j2db.ui.IFieldComponent#setNeedEntireState(boolean)
*/
public void setNeedEntireState(boolean needEntireState)
{
this.needEntireState = needEntireState;
}
/**
* @see com.servoy.j2db.dataprocessing.IDisplayData#needEntireState()
*/
public boolean needEntireState()
{
return needEntireState;
}
/**
* @see com.servoy.j2db.ui.IFieldComponent#setMaxLength(int)
*/
private int maxLength = -1;
public void setMaxLength(int maxLength)
{
this.maxLength = maxLength;
addMaxLengthBehavior(maxLength);
}
public void addMaxLengthBehavior(int maxLength)
{
if (maxLengthBehavior != null) remove(maxLengthBehavior);
maxLengthBehavior = null;
if (maxLength > 0)
{
maxLengthBehavior = new FindModeDisabledSimpleAttributeModifier(getEventExecutor(), "maxlength", Integer.toString(maxLength).intern()); //$NON-NLS-1$
add(maxLengthBehavior);
}
}
public static IConverter getTextConverter(final ParsedFormat fp, final Locale l, final String name, final String dataProviderID)
{
if (fp.isAllUpperCase())
{
return new IConverter()
{
public String convertToString(Object value, Locale locale)
{
if (value == null) return "";
return value.toString().toUpperCase(l);
}
public Object convertToObject(String value, Locale locale)
{
if (value == null) return null;
return value.toUpperCase(l);
}
};
}
if (fp.isAllLowerCase())
{
return new IConverter()
{
public String convertToString(Object value, Locale locale)
{
if (value == null) return "";
return value.toString().toLowerCase(l);
}
public Object convertToObject(String value, Locale locale)
{
if (value == null) return null;
return value.toLowerCase(l);
}
};
}
if (fp.getDisplayFormat() != null)
{
try
{
final FixedMaskFormatter displayFormatter = new FixedMaskFormatter(fp.getDisplayFormat());
displayFormatter.setValueContainsLiteralCharacters(!fp.isRaw());
if (fp.getPlaceHolderString() != null) displayFormatter.setPlaceholder(fp.getPlaceHolderString());
else if (fp.getPlaceHolderCharacter() != 0) displayFormatter.setPlaceholderCharacter(fp.getPlaceHolderCharacter());
return new IConverter()
{
public String convertToString(Object value, Locale locale)
{
if (value == null) return ""; //$NON-NLS-1$
try
{
return displayFormatter.valueToString(value);
}
catch (ParseException e)
{
Debug.log(e);
return value.toString();
}
}
public Object convertToObject(String value, Locale locale)
{
if (value == null || "".equals(value.trim())) return null; //$NON-NLS-1$
try
{
return displayFormatter.parse(value);
}
catch (Exception e)
{
String extraMsg = ""; //$NON-NLS-1$
if (name != null)
{
extraMsg = " on component " + name; //$NON-NLS-1$
}
extraMsg += " with dataprovider: " + dataProviderID; //$NON-NLS-1$
throw new ConversionException("Can't convert from string '" + value + "' to object with format: " + fp.getEditFormat() + extraMsg, //$NON-NLS-1$//$NON-NLS-2$
e).setConverter(this);
}
}
};
}
catch (ParseException e)
{
Debug.error("format problem: " + fp.getDisplayFormat(), e); //$NON-NLS-1$
return null;
}
}
return null;
}
/**
* @see wicket.Component#getConverter()
*/
@SuppressWarnings("nls")
@Override
public IConverter getConverter(Class< ? > cls)
{
if (converter != null) return converter;
int mappedType = Column.mapToDefaultType(dataType);
String displayFormat = parsedFormat.getDisplayFormat();
if (list == null && mappedType == IColumnTypes.TEXT)
{
converter = getTextConverter(parsedFormat, getLocale(), getName(), getDataProviderID());
if (converter == null)
{
converter = super.getConverter(cls);
}
}
else if (displayFormat == null && list == null)
{
converter = super.getConverter(cls);
}
else if (mappedType == IColumnTypes.DATETIME)
{
boolean lenient = Boolean.TRUE.equals(
UIUtils.getUIProperty(this.getScriptObject(), application, IApplication.DATE_FORMATTERS_LENIENT, Boolean.TRUE));
StateFullSimpleDateFormat displayFormatter = new StateFullSimpleDateFormat(displayFormat, null, application.getLocale(), lenient);
if (!parsedFormat.isMask() && parsedFormat.getEditFormat() != null)
{
StateFullSimpleDateFormat editFormatter = new StateFullSimpleDateFormat(parsedFormat.getEditFormat(), null, application.getLocale(), lenient);
converter = new FormatConverter(this, eventExecutor, displayFormatter, editFormatter, parsedFormat);
}
else
{
converter = new FormatConverter(this, eventExecutor, displayFormatter, parsedFormat);
}
}
else if ((mappedType == IColumnTypes.INTEGER || mappedType == IColumnTypes.NUMBER) && (list == null || !list.hasRealValues()))
{
int maxLength = parsedFormat.getMaxLength() == null ? -1 : parsedFormat.getMaxLength().intValue();
// if there is no display format, but the max length is set, then generate a display format.
if (maxLength != -1 && (displayFormat == null || displayFormat.length() == 0))
{
char[] chars = new char[maxLength];
for (int i = 0; i < chars.length; i++)
chars[i] = '#';
displayFormat = new String(chars);
}
if (displayFormat != null)
{
RoundHalfUpDecimalFormat displayFormatter = new RoundHalfUpDecimalFormat(displayFormat, application.getLocale());
if (parsedFormat.getEditFormat() != null)
{
RoundHalfUpDecimalFormat editFormatter = new RoundHalfUpDecimalFormat(parsedFormat.getEditFormat(), application.getLocale());
converter = new FormatConverter(this, eventExecutor, displayFormatter, editFormatter, parsedFormat);
}
else
{
converter = new FormatConverter(this, eventExecutor, displayFormatter, parsedFormat);
}
}
}
if (list != null)
{
if (converter == null && mappedType == IColumnTypes.TEXT && list instanceof GlobalMethodValueList)
{
converter = getTextConverter(parsedFormat, getLocale(), getName(), getDataProviderID());
}
converter = new ValuelistValueConverter(list, this, converter);
}
if (converter == null) converter = super.getConverter(cls);
return converter;
}
/**
* @see org.apache.wicket.markup.html.form.FormComponent#shouldTrimInput()
*/
@Override
protected boolean shouldTrimInput()
{
if (parsedFormat.getDisplayFormat() != null && Column.mapToDefaultType(dataType) == IColumnTypes.TEXT) return false;
return parsedFormat.getEditFormat() == null || !parsedFormat.isMask();
}
protected boolean needsFormatOnchange()
{
return false;
}
@SuppressWarnings("nls")
public void installFormat(com.servoy.j2db.component.ComponentFormat componentFormat)
{
int mappedType = Column.mapToDefaultType(componentFormat.uiType);
// only add type validators the first time (not when format is set through script)
if (this.dataType == 0)
{
if (mappedType == IColumnTypes.DATETIME)
{
setType(Date.class);
}
else if (mappedType == IColumnTypes.NUMBER)
{
setType(Double.class);
if (list == null)
{
add(new FindModeDisabledSimpleAttributeModifier(getEventExecutor(), "onkeypress", new NumberValidationModel(true)));
}
}
else if (mappedType == IColumnTypes.INTEGER)
{
setType(Integer.class);
if (list == null)
{
add(new FindModeDisabledSimpleAttributeModifier(getEventExecutor(), "onkeypress", new NumberValidationModel(false)));
}
}
else if ((mappedType == IColumnTypes.MEDIA || mappedType == IColumnTypes.TEXT) && list != null) // media and list != null is binary uuid column as real in a valuelist.
{
setType(String.class);
}
}
this.dataType = componentFormat.uiType;
getStylePropertyChanges().setChanged();
converter = null;
boolean emptyCustom = (list instanceof CustomValueList) && list.getSize() == 0;
parsedFormat = componentFormat.parsedFormat;
if (formatAttributeModifier != null)
{
remove(formatAttributeModifier);
formatAttributeModifier = null;
}
if (formatPasteBehavior != null)
{
remove(formatPasteBehavior);
formatPasteBehavior = null;
}
if (formatOnChangeBehavior != null)
{
remove(formatOnChangeBehavior);
formatOnChangeBehavior = null;
}
addMaxLengthBehavior(-1);
if (!componentFormat.parsedFormat.isEmpty() && (list == null || (!list.hasRealValues() && !emptyCustom)))
{
int maxLength = parsedFormat.getMaxLength() != null ? parsedFormat.getMaxLength().intValue() : 0;
if (maxLength > 0)
{
addMaxLengthBehavior(parsedFormat.getMaxLength().intValue());
}
if (parsedFormat.isAllUpperCase())
{
formatAttributeModifier = new ReadOnlyAndEnableTestAttributeModifier("onkeypress",
"return Servoy.Validation.changeCase(this,event,true," + maxLength + ");");
formatPasteBehavior = new ReadOnlyAndEnableTestAttributeModifier("onpaste",
"Servoy.Validation.pasteHandler(this, function(el){el.value = el.value.toUpperCase();});");
if (needsFormatOnchange())
{
formatOnChangeBehavior = new ReadOnlyAndEnableTestAttributeModifier("onchange", "if (this.value) this.value = this.value.toUpperCase()");
}
}
else if (parsedFormat.isAllLowerCase())
{
formatAttributeModifier = new ReadOnlyAndEnableTestAttributeModifier("onkeypress",
"return Servoy.Validation.changeCase(this,event,false," + maxLength + ");");
formatPasteBehavior = new ReadOnlyAndEnableTestAttributeModifier("onpaste",
"Servoy.Validation.pasteHandler(this, function(el){el.value = el.value.toLowerCase();});");
if (needsFormatOnchange())
{
formatOnChangeBehavior = new ReadOnlyAndEnableTestAttributeModifier("onchange", "if (this.value) this.value = this.value.toLowerCase()");
}
}
else if (mappedType == IColumnTypes.DATETIME && parsedFormat.isMask())
{
String maskPattern = parsedFormat.getDateMask();
setType(Date.class);
String placeHolder = parsedFormat.getDisplayFormat();
if (parsedFormat.getPlaceHolderString() != null) placeHolder = parsedFormat.getPlaceHolderString();
else if (parsedFormat.getPlaceHolderCharacter() != 0) placeHolder = Character.toString(parsedFormat.getPlaceHolderCharacter());
formatAttributeModifier = new MaskBehavior(maskPattern.toString(), placeHolder, this);
}
else if (mappedType == IColumnTypes.TEXT && parsedFormat.isNumberValidator())
{
setType(String.class);
DecimalFormatSymbols dfs = RoundHalfUpDecimalFormat.getDecimalFormatSymbols(application.getLocale());
formatAttributeModifier = new FindModeDisabledSimpleAttributeModifier(getEventExecutor(), "onkeypress",
("return Servoy.Validation.numbersonly(event, true, '" + dfs.getDecimalSeparator() + "','" + dfs.getGroupingSeparator() + "','" +
dfs.getCurrencySymbol() + "','" + dfs.getPercent() + "');").intern());
formatPasteBehavior = new FindModeDisabledSimpleAttributeModifier(getEventExecutor(), "onpaste",
"Servoy.Validation.pasteHandler(this, function(el){el.value = el.value.replace(/[^0-9\\-\\,\\.\\$\\%]+/,'');});");
}
else if (mappedType == IColumnTypes.TEXT && parsedFormat.getDisplayFormat() != null)
{
setType(String.class);
String placeHolder = null;
if (parsedFormat.getPlaceHolderString() != null) placeHolder = parsedFormat.getPlaceHolderString();
else if (parsedFormat.getPlaceHolderCharacter() != 0) placeHolder = Character.toString(parsedFormat.getPlaceHolderCharacter());
formatAttributeModifier = new MaskBehavior(parsedFormat.getDisplayFormat(), placeHolder, this, parsedFormat.getAllowedCharacters());
}
if (formatAttributeModifier != null) add(formatAttributeModifier);
if (formatPasteBehavior != null) add(formatPasteBehavior);
if (formatOnChangeBehavior != null) add(formatOnChangeBehavior);
}
if (maxLength > 0 && maxLengthBehavior == null)
{
addMaxLengthBehavior(maxLength);
}
}
public Insets getMargin()
{
return margin;
}
public void setMargin(Insets margin)
{
this.margin = margin;
}
public int getHorizontalAlignment()
{
return this.horizontalAlignment;
}
/**
* @see com.servoy.j2db.ui.IFieldComponent#setHorizontalAlignment(int)
*/
public void setHorizontalAlignment(int horizontalAlignment)
{
this.horizontalAlignment = horizontalAlignment;
}
public void setCursor(Cursor cursor)
{
// this.cursor = cursor;
}
@Override
protected String getModelValue()
{
if (getDefaultModelObject() == null)
{
if (getValueList() != null)
{
int index = list.realValueIndexOf(null);
if (index != -1) return (String)getValueList().getElementAt(index);
}
return null;
}
else return getDefaultModelObjectAsString();
}
public Object getValueObject()
{
return getDefaultModelObject();
}
public void setValueObject(Object value)
{
((ChangesRecorder)getStylePropertyChanges()).testChanged(this, value);
if (getStylePropertyChanges().isChanged())
{
// this component is going to update it's contents, without the user changing the
// components contents; so remove invalid state if necessary
setValueValid(true, null);
}
}
public boolean needEditListener()
{
return false;
}
public void addEditListener(IEditListener l)
{
}
/**
* @see com.servoy.j2db.dataprocessing.IDisplayData#getDocument()
*/
public Document getDocument()
{
return null;
}
/**
* @see com.servoy.j2db.dataprocessing.IDisplay#stopUIEditing(boolean)
*/
public boolean stopUIEditing(boolean looseFocus)
{
if (!isValueValid)
{
requestFocusToComponent();
return false;
}
return true;
}
public void requestFocusToComponent()
{
if (!isReadOnly() && isEnabled())
{
// is the current main container always the right one?
IMainContainer currentContainer = ((FormManager)application.getFormManager()).getCurrentContainer();
if (currentContainer instanceof MainPage)
{
((MainPage)currentContainer).componentToFocus(this);
}
}
}
@SuppressWarnings("nls")
public void selectAll()
{
Page page = findPage();
if (page instanceof MainPage)
{
((MainPage)page).getPageContributor().addDynamicJavaScript("document.getElementById('" + getMarkupId() + "').select();");
}
}
@SuppressWarnings("nls")
public void replaceSelectedText(String s)
{
Page page = findPage();
if (page instanceof MainPage)
{
((MainPage)page).getPageContributor().addDynamicJavaScript("Servoy.Utils.replaceSelectedText('" + getMarkupId() + "','" + s + "');");
}
}
public String getSelectedText()
{
return null;
}
public IValueList getValueList()
{
return list;
}
public void setValueList(IValueList vl)
{
this.list = vl;
}
public ListDataListener getListener()
{
return null;
}
/*
* readonly/editable---------------------------------------------------
*/
private boolean editable;
public boolean isReadOnly()
{
return !editable;
}
public boolean isEditable()
{
return editable;
}
private boolean editState;
public void setReadOnly(boolean b)
{
if (b && !editable) return;
if (b)
{
setEditable(false);
editState = true;
}
else
{
setEditable(editState);
}
}
public void setEditable(boolean b)
{
editState = b;
editable = b;
toggleFocusBehavior();
}
protected void toggleFocusBehavior()
{
List<FocusIfInvalidAttributeModifier> list = this.getBehaviors(FocusIfInvalidAttributeModifier.class);
if (isReadOnly() || !isEnabled())
{
if (list.size() > 0) remove(focusIfInvalidAttributeModifier);
}
else
{
if (list.size() == 0) add(focusIfInvalidAttributeModifier);
}
}
/*
* dataprovider---------------------------------------------------
*/
public void setDataProviderID(String dataProviderID)
{
this.dataProviderID = dataProviderID;
}
public String getDataProviderID()
{
return dataProviderID;
}
private String dataProviderID;
public void setName(String n)
{
name = n;
}
private String name;
public String getName()
{
return name;
}
/*
* border---------------------------------------------------
*/
private Border border;
public void setBorder(Border border)
{
this.border = border;
}
public Border getBorder()
{
return border;
}
/*
* opaque---------------------------------------------------
*/
public void setOpaque(boolean opaque)
{
this.opaque = opaque;
}
private boolean opaque;
public boolean isOpaque()
{
return opaque;
}
/*
* titleText---------------------------------------------------
*/
private String titleText = null;
public void setTitleText(String title)
{
this.titleText = title;
}
public String getTitleText()
{
return Text.processTags(titleText, resolver);
}
private String tooltip;
public void setToolTipText(String tooltip)
{
if (Utils.stringIsEmpty(tooltip))
{
this.tooltip = null;
}
else
{
this.tooltip = tooltip;
}
}
protected ITagResolver resolver;
public void setTagResolver(ITagResolver resolver)
{
this.resolver = resolver;
}
/**
* @see com.servoy.j2db.ui.IComponent#getToolTipText()
*/
public String getToolTipText()
{
if (tooltip != null && getInnermostModel() instanceof RecordItemModel)
{
return Text.processTags(tooltip, resolver);
}
return tooltip;
}
/*
* font---------------------------------------------------
*/
public void setFont(Font font)
{
this.font = font;
}
private Font font;
public Font getFont()
{
return font;
}
private Color background;
public void setBackground(Color cbg)
{
this.background = cbg;
}
public Color getBackground()
{
return background;
}
private Color foreground;
private List<ILabel> labels;
public void setForeground(Color cfg)
{
this.foreground = cfg;
}
public Color getForeground()
{
return foreground;
}
/*
* visible---------------------------------------------------
*/
public void setComponentVisible(boolean visible)
{
if (viewable || !visible)
{
setVisible(visible);
if (labels != null)
{
for (int i = 0; i < labels.size(); i++)
{
ILabel label = labels.get(i);
label.setComponentVisible(visible);
}
}
}
}
public void addLabelFor(ILabel label)
{
if (labels == null) labels = new ArrayList<ILabel>(3);
labels.add(label);
}
public List<ILabel> getLabelsFor()
{
return labels;
}
public void setComponentEnabled(final boolean b)
{
if (accessible || !b)
{
super.setEnabled(b);
getStylePropertyChanges().setChanged();
if (labels != null)
{
for (int i = 0; i < labels.size(); i++)
{
ILabel label = labels.get(i);
label.setComponentEnabled(b);
}
}
toggleFocusBehavior();
}
}
private boolean accessible = true;
public void setAccessible(boolean b)
{
if (!b) setComponentEnabled(b);
accessible = b;
}
private boolean viewable = true;
public void setViewable(boolean b)
{
if (!b) setComponentVisible(b);
this.viewable = b;
}
public boolean isViewable()
{
return viewable;
}
/*
* location---------------------------------------------------
*/
private Point location = new Point(0, 0);
public int getAbsoluteFormLocationY()
{
WebDataRenderer parent = findParent(WebDataRenderer.class);
if (parent != null)
{
return parent.getYOffset() + getLocation().y;
}
return getLocation().y;
}
public void setLocation(Point location)
{
this.location = location;
}
public Point getLocation()
{
return location;
}
/*
* client properties for ui---------------------------------------------------
*/
public void setClientProperty(Object key, Object value)
{
if (IApplication.DATE_FORMATTERS_LENIENT.equals(key))
{
if (converter instanceof FormatConverter)
{
((FormatConverter)converter).setLenient(
Boolean.TRUE.equals(UIUtils.getUIProperty(this.getScriptObject(), application, IApplication.DATE_FORMATTERS_LENIENT, Boolean.TRUE)));
}
}
}
/*
* size---------------------------------------------------
*/
private Dimension size = new Dimension(0, 0);
private FindModeDisabledSimpleAttributeModifier maxLengthBehavior;
private IBehavior formatAttributeModifier, formatPasteBehavior, formatOnChangeBehavior;
public Dimension getSize()
{
return size;
}
public Rectangle getWebBounds()
{
Dimension d = ((ChangesRecorder)getStylePropertyChanges()).calculateWebSize(size.width, size.height, border, margin, 0, null);
return new Rectangle(location, d);
}
/**
* @see com.servoy.j2db.ui.ISupportWebBounds#getPaddingAndBorder()
*/
public Insets getPaddingAndBorder()
{
return ((ChangesRecorder)getStylePropertyChanges()).getPaddingAndBorder(size.height, border, margin, 0, null);
}
public Insets getPadding()
{
return ((ChangesRecorder)getStylePropertyChanges()).getPadding(border, margin);
}
public void setSize(Dimension size)
{
this.size = size;
}
public void setRightClickCommand(String rightClickCmd, Object[] args)
{
eventExecutor.setRightClickCmd(rightClickCmd, args);
}
public void onRightClick()
{
Form< ? > f = getForm();
if (f != null)
{
// If form validation fails, we don't execute the method.
if (f.process()) eventExecutor.onEvent(JSEvent.EventType.rightClick, null, this, IEventExecutor.MODIFIERS_UNSPECIFIED);
}
}
@Override
public String toString()
{
return scriptable.toString("value:" + getDefaultModelObjectAsString()); //$NON-NLS-1$
}
@Override
protected void onBeforeRender()
{
super.onBeforeRender();
fireOnRender(false);
}
public void fireOnRender(boolean force)
{
if (!isIgnoreOnRender && scriptable != null)
{
boolean isFocused = false;
IMainContainer currentContainer = ((FormManager)application.getFormManager()).getCurrentContainer();
if (currentContainer instanceof MainPage)
{
isFocused = this.equals(((MainPage)currentContainer).getFocusedComponent());
}
if (force) scriptable.getRenderEventExecutor().setRenderStateChanged();
scriptable.getRenderEventExecutor().fireOnRender(isFocused);
}
}
private boolean isIgnoreOnRender;
public void setIgnoreOnRender(boolean isIgnoreOnRender)
{
this.isIgnoreOnRender = isIgnoreOnRender;
}
public ISupportSimulateBounds getBoundsProvider()
{
return findParent(ISupportSimulateBounds.class);
}
}