/* 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.ui.scripting; import java.awt.Dimension; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import javax.swing.JComponent; import com.servoy.j2db.IApplication; import com.servoy.j2db.component.ComponentFactory; import com.servoy.j2db.dataprocessing.CustomValueList; import com.servoy.j2db.dataprocessing.IDisplay; import com.servoy.j2db.dataprocessing.IDisplayData; import com.servoy.j2db.scripting.IScriptable; import com.servoy.j2db.ui.IFieldComponent; import com.servoy.j2db.ui.ILabel; import com.servoy.j2db.ui.IStylePropertyChangesRecorder; import com.servoy.j2db.ui.ISupportPlaceholderText; import com.servoy.j2db.ui.ISupportSpecialClientProperty; import com.servoy.j2db.ui.runtime.HasRuntimePlaceholder; import com.servoy.j2db.ui.runtime.HasRuntimeReadOnly; import com.servoy.j2db.ui.runtime.IRuntimeComponent; import com.servoy.j2db.ui.runtime.IRuntimeField; import com.servoy.j2db.util.IDelegate; import com.servoy.j2db.util.StringComparator; import com.servoy.j2db.util.Utils; /** * Abstract scriptable field. * * @author lvostinar */ public abstract class AbstractRuntimeField<C extends IFieldComponent> extends AbstractRuntimeRendersupportComponent<C> implements IRuntimeField, HasRuntimeReadOnly, HasRuntimePlaceholder { public AbstractRuntimeField(IStylePropertyChangesRecorder jsChangeRecorder, IApplication application) { super(jsChangeRecorder, application); } public String getDataProviderID() { return getComponent() instanceof IDisplayData ? ((IDisplayData)getComponent()).getDataProviderID() : null; } public String[] getLabelForElementNames() { List<ILabel> labels = getComponent().getLabelsFor(); if (labels != null) { ArrayList<String> al = new ArrayList<String>(labels.size()); for (int i = 0; i < labels.size(); i++) { ILabel label = labels.get(i); if (label.getName() != null && !"".equals(label.getName()) && !label.getName().startsWith(ComponentFactory.WEB_ID_PREFIX)) //$NON-NLS-1$ { al.add(label.getName()); } } return al.toArray(new String[al.size()]); } return new String[0]; } public String getTitleText() { return getComponent().getTitleText(); } public void setTitleText(String titleText) { if (!Utils.safeEquals(titleText, getTitleText())) { getComponent().setTitleText(titleText); getChangesRecorder().setChanged(); } } public int getAbsoluteFormLocationY() { return getComponent().getAbsoluteFormLocationY(); } public void requestFocus() { requestFocus(true); } public void requestFocus(boolean mustExecuteOnFocusGainedMethod) { if (!mustExecuteOnFocusGainedMethod) { getComponent().getEventExecutor().skipNextFocusGain(); } getComponent().requestFocusToComponent(); } public void setReadOnly(boolean b) { if (isReadOnly() != b) { getComponent().setReadOnly(b); getChangesRecorder().setChanged(); } } public boolean isReadOnly() { return getComponent() instanceof IDisplay && ((IDisplay)getComponent()).isReadOnly(); } @Override public void setVisible(boolean b) { if (isVisible() != b) { if (getComponent().isViewable()) { List<ILabel> labels = getComponent().getLabelsFor(); if (labels != null) { for (int i = 0; i < labels.size(); i++) { ILabel label = labels.get(i); IScriptable scriptable = label.getScriptObject(); if (scriptable instanceof IRuntimeComponent) { ((IRuntimeComponent)scriptable).setVisible(b); } else { label.setComponentVisible(b); } } } } super.setVisible(b); } } @Override public void putClientProperty(Object key, Object value) { super.putClientProperty(key, value); if (getComponent() instanceof IDelegate && ((IDelegate< ? >)getComponent()).getDelegate() instanceof JComponent) { ((JComponent)((IDelegate< ? >)getComponent()).getDelegate()).putClientProperty(key, value); } if (getComponent() instanceof ISupportSpecialClientProperty) { ((ISupportSpecialClientProperty)getComponent()).setClientProperty(key, value); } } public void setSize(int width, int height) { Dimension newSize = new Dimension(width, height); setComponentSize(newSize); getChangesRecorder().setSize(width, height, getComponent().getBorder(), getComponent().getMargin(), 0); } /** Get the value for a choice on possibly multiple values. * * Multiple values are joined with newline. * In case of find mode a search-object is created for records with at least these values. * @param strValues * @return */ public Object getChoiceValue(Object[] values, boolean keepPlainValue) { if (values == null || values.length == 0) { return null; } if ((keepPlainValue || getComponent().getEventExecutor().getValidationEnabled()) && values.length == 1) { return values[0]; } List<String> strValues = new ArrayList<String>(values.length); for (Object value : values) { strValues.add(CustomValueList.convertToString(value, application)); } Collections.sort(strValues, StringComparator.INSTANCE);//sorted to have same order to search in with LIKE (in the db) if (getComponent().getEventExecutor().getValidationEnabled()) { return Utils.stringJoin(strValues.iterator(), '\n'); } // find mode if (strValues.size() > 6) // 128 combinations { // sql gets way too large, fall back to less precise sql return '%' + Utils.stringJoin(strValues.iterator(), "%||%") + '%'; //$NON-NLS-1$ } // create a condition that matches the values, for example values = [a,b], results in sql: // where val = 'a\nb' -- just the 2 values // or val like 'a\nb\n%' -- the first 2 values // or val like '%\na\nb\n%' -- next to each other in the middle // or val like '%\na\nb' -- the last 2 values // or val like 'a\n%\nb' -- first a, last b // or val like 'a\n%\nb\n%' -- start with a // or val like '%\na\n%\nb\n%'-- a and b somewhere in the middle // or val like '%\na\n%\nb' -- end with b List<String> combinedValues = joinList(strValues, new String[] { "\n", "\n%\n" }); //$NON-NLS-1$ //$NON-NLS-2$ Iterator<String> iter = combinedValues.iterator(); StringBuilder stringRetval = new StringBuilder(); while (iter.hasNext()) { String element = iter.next(); stringRetval.append(element); stringRetval.append("||").append(element).append("\n%"); // element is first //$NON-NLS-1$ //$NON-NLS-2$ stringRetval.append("||%\n").append(element).append("\n%"); // element in the middle //$NON-NLS-1$ //$NON-NLS-2$ stringRetval.append("||%\n").append(element); // element at the end //$NON-NLS-1$ if (iter.hasNext()) { stringRetval.append("||"); //$NON-NLS-1$ } } return stringRetval.toString(); } /** * Get the real values belonging to the choice values string. * @param realVal * @return */ public List<Object> resolveChoiceValues(Object realVal) { List<Object> retval = new ArrayList<Object>(); if (realVal instanceof String) { String str = (String)realVal; // in case of find mode, take the first bit before the '||', it contains the values separated by newline. int idx = getComponent().getEventExecutor().getValidationEnabled() ? -1 : str.indexOf("||"); //$NON-NLS-1$ StringTokenizer tk = new StringTokenizer(idx < 0 ? str : str.subSequence(0, idx).toString(), "\n"); //$NON-NLS-1$ while (tk.hasMoreTokens()) { retval.add(tk.nextToken().trim()); // do a trim because "\r\n" might leave the "\r" in the token } } else { retval.add(realVal);//keep plain } return retval; } /** * Join items of the list with separators. * @param list * @param separators * @return */ private static List<String> joinList(List<String> list, String[] separators) { if (list.size() <= 1) { return list; } String last = list.get(list.size() - 1); List<String> joinedSubList = joinList(list.subList(0, list.size() - 1), separators); List<String> retval = new ArrayList<String>(joinedSubList.size() * separators.length); for (String s : joinedSubList) { for (String sep : separators) { retval.add(s + sep + last); } } return retval; } private String placeholderText = null; public String getPlaceholderText() { return placeholderText; } public void setPlaceholderText(String placeholder) { if (!Utils.safeEquals(placeholder, getPlaceholderText())) { if (getComponent() instanceof ISupportPlaceholderText) { ((ISupportPlaceholderText)getComponent()).setPlaceholderText(placeholder); } this.placeholderText = placeholder; getChangesRecorder().setChanged(); } } }