/* 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.smart.dataui; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.image.BufferedImage; import java.text.Format; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import javax.swing.AbstractAction; import javax.swing.AbstractCellEditor; import javax.swing.BorderFactory; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JRadioButton; import javax.swing.JToggleButton; import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.text.Document; import com.servoy.base.util.ITagResolver; import com.servoy.j2db.IApplication; import com.servoy.j2db.IScriptExecuter; import com.servoy.j2db.IServiceProvider; import com.servoy.j2db.component.ComponentFormat; import com.servoy.j2db.dataprocessing.IDisplayData; import com.servoy.j2db.dataprocessing.IDisplayRelatedData; import com.servoy.j2db.dataprocessing.IEditListener; import com.servoy.j2db.dataprocessing.IRecordInternal; import com.servoy.j2db.dataprocessing.IValueList; import com.servoy.j2db.gui.editlist.JNavigableEditList; import com.servoy.j2db.gui.editlist.NavigableCellEditor; import com.servoy.j2db.gui.editlist.NavigableCellRenderer; import com.servoy.j2db.persistence.Column; import com.servoy.j2db.persistence.Field; import com.servoy.j2db.persistence.IColumnTypes; import com.servoy.j2db.smart.dataui.DataComboBox.VariableSizeJSeparator; import com.servoy.j2db.ui.IDataRenderer; 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.IScrollPane; import com.servoy.j2db.ui.ISupportCachedLocationAndSize; import com.servoy.j2db.ui.ISupportOnRender; import com.servoy.j2db.ui.ISupportValueList; import com.servoy.j2db.ui.scripting.AbstractRuntimeField; import com.servoy.j2db.ui.scripting.AbstractRuntimeScrollableValuelistComponent; import com.servoy.j2db.ui.scripting.AbstractRuntimeValuelistComponent; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.EnableScrollPanel; import com.servoy.j2db.util.ISupplyFocusChildren; 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.editlist.IEditListEditor; import com.servoy.j2db.util.editlist.JEditList; import com.servoy.j2db.util.model.ComboModelListModelWrapper; import sun.java2d.SunGraphics2D; /** * Runtime swing radio/check box choice component * @author jblok, jcompagner */ public class DataChoice extends EnableScrollPanel implements IDisplayData, IFieldComponent, IScrollPane, IDisplayRelatedData, ListDataListener, ISupplyFocusChildren<Component>, ISupportCachedLocationAndSize, ISupportValueList, IFormattingComponent, ISupportOnRender { private String dataProviderID; protected final ComboModelListModelWrapper list; protected final JEditList enclosedComponent; private JComponent rendererComponent; private JComponent editorComponent; private String tooltip; private Insets margin; private int halign; private final EventExecutor eventExecutor; protected final IApplication application; private final int choiceType; private MouseAdapter rightclickMouseAdapter = null; private IValueList vl; private final AbstractRuntimeValuelistComponent<IFieldComponent> scriptable; private Format format; private AbstractCell cellEditor; public DataChoice(IApplication app, AbstractRuntimeValuelistComponent<IFieldComponent> scriptable, IValueList vl, int choiceType, boolean multiselect) { super(); setHorizontalAlignment(SwingConstants.LEFT); if (choiceType == Field.RADIOS || choiceType == Field.CHECKS) { setBorder(null); } application = app; this.vl = vl; this.choiceType = choiceType; list = new ComboModelListModelWrapper(vl, choiceType != Field.SPINNER, (choiceType == Field.MULTISELECT_LISTBOX || choiceType == Field.LIST_BOX)); enclosedComponent = new JNavigableEditList(); enclosedComponent.getActionMap().put("enter", null); enclosedComponent.getActionMap().put("select_current", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (enclosedComponent.isEditable() && cellEditor != null) { enclosedComponent.editCellAt(enclosedComponent.getSelectedIndex(), e); cellEditor.doSelect(true, false); } } }); eventExecutor = new EventExecutor(this, enclosedComponent); enclosedComponent.addKeyListener(eventExecutor); enclosedComponent.setModel(createJListModel(list)); if (choiceType == Field.RADIOS) { enclosedComponent.setCellRenderer(new NavigableCellRenderer(new RadioCell())); cellEditor = new RadioCell(); enclosedComponent.setCellEditor(new NavigableCellEditor(cellEditor)); } else if (choiceType == Field.CHECKS) { enclosedComponent.setCellRenderer(new NavigableCellRenderer(new CheckBoxCell())); cellEditor = new CheckBoxCell(); enclosedComponent.setCellEditor(new NavigableCellEditor(cellEditor)); } else { enclosedComponent.setCellRenderer(new LabelCell(shouldPaintSelection())); cellEditor = new LabelCell(shouldPaintSelection()); enclosedComponent.setCellEditor(cellEditor); } setMultiValueSelect(multiselect); this.scriptable = scriptable; if (scriptable instanceof AbstractRuntimeScrollableValuelistComponent< ? , ? >) { ((AbstractRuntimeScrollableValuelistComponent<IFieldComponent, JComponent>)scriptable).setField(enclosedComponent); ((AbstractRuntimeScrollableValuelistComponent<IFieldComponent, JComponent>)scriptable).setList(list); } // enclosedComponent.setPrototypeCellValue(new Integer(0)); getViewport().setView(enclosedComponent); } /** * @return the choiceType */ public int getChoiceType() { return choiceType; } /** * @return the rendererComponent */ public JComponent getRendererComponent() { return rendererComponent; } /** * @return the enclosedComponent */ public JEditList getEnclosedComponent() { return enclosedComponent; } public void installFormat(ComponentFormat componentFormat) { if (!componentFormat.parsedFormat.isEmpty()) { String displayFormat = componentFormat.parsedFormat.getDisplayFormat(); try { switch (Column.mapToDefaultType(componentFormat.uiType)) { case IColumnTypes.NUMBER : format = new RoundHalfUpDecimalFormat(displayFormat, application.getLocale()); break; case IColumnTypes.INTEGER : format = new RoundHalfUpDecimalFormat(displayFormat, application.getLocale()); break; case IColumnTypes.DATETIME : format = new StateFullSimpleDateFormat(displayFormat, Boolean.TRUE.equals(UIUtils.getUIProperty(this, IApplication.DATE_FORMATTERS_LENIENT, Boolean.TRUE))); // format = new SimpleDateFormat(formatString); break; default : // TODO Jan/Johan what to do here? Should we create our own MaskFormatter? Where we can insert a mask?? break; } } catch (Exception ex) { Debug.error(ex); } } } protected ListModel createJListModel(ComboModelListModelWrapper comboModel) { return comboModel; } protected boolean isRowSelected(int idx) { return list.isRowSelected(idx); } protected void setElementAt(Object b, int idx) { list.setElementAt(b, idx); } protected boolean shouldPaintSelection() { return true; } /** * */ private void configureEditorAndRenderer() { // TODO Auto-generated method stub } protected void setMultiValueSelect(boolean multiselect) { if (choiceType == Field.RADIOS || choiceType == Field.LIST_BOX) { list.setMultiValueSelect(false); } else { list.setMultiValueSelect(multiselect); } } public final AbstractRuntimeField<IFieldComponent> getScriptObject() { return scriptable; } /* * _____________________________________________________________ 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); } private boolean wasEditable; public boolean isValueValid() { return isValueValid; } private boolean isValueValid = true; private Object previousValidValue; public void setValueValid(boolean valid, Object oldVal) { application.getRuntimeProperties().put(IServiceProvider.RT_LASTFIELDVALIDATIONFAILED_FLAG, Boolean.valueOf(!valid)); isValueValid = valid; repaint(); // foreground color changes if (!isValueValid) { previousValidValue = oldVal; application.invokeLater(new Runnable() { public void run() { enclosedComponent.requestFocus(); } }); } else { previousValidValue = null; } } public void notifyLastNewValueWasChange(Object oldVal, Object newVal) { if (previousValidValue != null) { oldVal = previousValidValue; } previousValue = newVal; eventExecutor.fireChangeCommand(oldVal, newVal, false, this); // if change cmd is not succeeded also don't call action cmd? if (isValueValid) { eventExecutor.fireActionCommand(false, this); } } public void setChangeCmd(String id, Object[] args) { eventExecutor.setChangeCmd(id, args); } public void setActionCmd(String id, Object[] args) { eventExecutor.setActionCmd(id, args); } public void setRightClickCommand(String rightClickCmd, Object[] args) { eventExecutor.setRightClickCmd(rightClickCmd, args); if (rightClickCmd != null && rightclickMouseAdapter == null) { rightclickMouseAdapter = new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) handle(e); } @Override public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger()) handle(e); } private void handle(MouseEvent e) { if (isEnabled()) { eventExecutor.fireRightclickCommand(true, DataChoice.this, e.getModifiers(), e.getPoint()); } } }; enclosedComponent.addMouseListener(rightclickMouseAdapter); addMouseListener(rightclickMouseAdapter); } } public void setValidationEnabled(boolean b) { if (eventExecutor.getValidationEnabled() == b) return; if (vl.getFallbackValueList() != null) { if (b) { list.register(vl); } else { list.register(vl.getFallbackValueList()); } } boolean prevEditState = editState; if (b) { setEditable(wasEditable); } else { wasEditable = !isReadOnly(); if (!Boolean.TRUE.equals(application.getClientProperty(IApplication.LEAVE_FIELDS_READONLY_IN_FIND_MODE))) { setEditable(true); } } eventExecutor.setValidationEnabled(b); editState = prevEditState; } public void setSelectOnEnter(boolean b) { eventExecutor.setSelectOnEnter(b); } //_____________________________________________________________ public void destroy() { list.deregister(); } public void setMaxLength(int i) { //ignore } public void setMargin(Insets i) { margin = i; } public Insets getMargin() { return margin; } /* * (non-Javadoc) * * @see java.awt.Component#setName(java.lang.String) */ @Override public void setName(String name) { super.setName(name); enclosedComponent.setName(name); } @Override public void setToolTipText(String tip) { if (tip != null && tip.indexOf("%%") != -1) //$NON-NLS-1$ { tooltip = tip; } else { super.setToolTipText(tip); enclosedComponent.setToolTipText(tip); } } @Override public void setFont(Font font) { super.setFont(font); if (enclosedComponent != null) enclosedComponent.setFont(font); } @Override public Font getFont() { if (enclosedComponent != null) { return enclosedComponent.getFont(); } return super.getFont(); } public Document getDocument() { return null; } public abstract class AbstractCell extends AbstractCellEditor implements IEditListEditor, ListCellRenderer, ActionListener { public void doSelect(boolean isCommandKeyDown, boolean isShiftDown) { if (editorComponent instanceof JToggleButton) ((JToggleButton)editorComponent).doClick(); } protected void createRenderer() { rendererComponent.setOpaque(false); ((JToggleButton)rendererComponent).setMargin(margin); ((JToggleButton)rendererComponent).setHorizontalAlignment(halign); } protected void createEditor() { editorComponent.setOpaque(false); ((JToggleButton)editorComponent).addActionListener(this); ((JToggleButton)editorComponent).setMargin(margin); ((JToggleButton)editorComponent).setHorizontalAlignment(halign); } public Component getListCellEditorComponent(JEditList editList, Object value, boolean isSelected, int index) { if (editorComponent == null) createEditor(); editorComponent.setFont(editList.getFont()); ((JToggleButton)editorComponent).setSelected(isRowSelected(index)); editorComponent.setForeground(editList.getForeground()); // editorComponent.setBackground(editList.getBackground()); if (value == null) { ((JToggleButton)editorComponent).setText(""); //$NON-NLS-1$ } else { Object formattedValue = value; if (!"".equals(formattedValue) && format != null && formattedValue != null && !(formattedValue instanceof String)) //$NON-NLS-1$ { try { formattedValue = format.format(formattedValue); } catch (IllegalArgumentException ex) { Debug.error("Error formatting value for combobox " + dataProviderID + ", " + ex); //$NON-NLS-1$//$NON-NLS-2$ } } ((JToggleButton)editorComponent).setText(resolver != null ? Text.processTags(formattedValue.toString(), resolver) : formattedValue.toString()); } return editorComponent; } public Object getCellEditorValue() { return new Boolean(((JToggleButton)editorComponent).isSelected()); } public Component getListCellRendererComponent(JList editList, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (rendererComponent == null) createRenderer(); ((JToggleButton)rendererComponent).setSelected(isRowSelected(index)); rendererComponent.setFont(editList.getFont()); rendererComponent.setEnabled(editList.isEnabled()); rendererComponent.setForeground(editList.getForeground()); // rendererComponent.setBackground(editList.getBackground()); if (value == null) { ((JToggleButton)rendererComponent).setText(""); //$NON-NLS-1$ } else { Object formattedValue = value; if (!"".equals(formattedValue) && format != null && formattedValue != null && !(formattedValue instanceof String)) //$NON-NLS-1$ { try { formattedValue = format.format(formattedValue); } catch (IllegalArgumentException ex) { Debug.error("Error formatting value for combobox " + dataProviderID + ", " + ex); //$NON-NLS-1$//$NON-NLS-2$ } } ((JToggleButton)rendererComponent).setText(resolver != null ? Text.processTags(formattedValue.toString(), resolver) : formattedValue.toString()); } return rendererComponent; } public void actionPerformed(ActionEvent e) { stopCellEditing(); } private boolean cellEditStoping; @Override public boolean stopCellEditing() { if (cellEditStoping) return true; else { try { cellEditStoping = true; return super.stopCellEditing(); } finally { cellEditStoping = false; } } } } public class RadioCell extends AbstractCell { public RadioCell() { super(); } @Override protected void createRenderer() { rendererComponent = new JRadioButton() { private final boolean initialized = true; @Override public Color getForeground() { if (initialized && DataChoice.this.isValueValid()) { return super.getForeground(); } return Color.red; } }; super.createRenderer(); } @Override protected void createEditor() { editorComponent = new JRadioButton() { private final boolean initialized = true; @Override public Color getForeground() { if (initialized && DataChoice.this.isValueValid()) { return super.getForeground(); } return Color.red; } }; super.createEditor(); } @Override public void actionPerformed(ActionEvent e) { stopCellEditing(); } } public class CheckBoxCell extends AbstractCell { public CheckBoxCell() { super(); } @Override protected void createRenderer() { rendererComponent = new JCheckBox() { private final boolean initialized = true; @Override public Color getForeground() { if (initialized && DataChoice.this.isValueValid()) { return super.getForeground(); } return Color.red; } }; super.createRenderer(); } @Override protected void createEditor() { editorComponent = new JCheckBox() { private final boolean initialized = true; @Override public Color getForeground() { if (initialized && DataChoice.this.isValueValid()) { return super.getForeground(); } return Color.red; } }; super.createEditor(); } } public class LabelCell extends AbstractCell implements MouseListener { private Border marginBorder; private final boolean paintSelection; public LabelCell(boolean paintSelection) { super(); this.paintSelection = paintSelection; } @Override protected void createRenderer() { rendererComponent = new JLabel() { private final boolean initialized = true; @Override public Color getForeground() { if (initialized && DataChoice.this.isValueValid()) { return super.getForeground(); } return Color.red; } }; if (margin != null) { marginBorder = BorderFactory.createEmptyBorder(margin.top, margin.left, margin.bottom, margin.right); ((JLabel)rendererComponent).setBorder(marginBorder); } ((JLabel)rendererComponent).setHorizontalAlignment(halign); } @Override protected void createEditor() { editorComponent = new JLabel() { private final boolean initialized = true; @Override public Color getForeground() { if (initialized && DataChoice.this.isValueValid()) { return super.getForeground(); } return Color.red; } }; editorComponent.addMouseListener(this); if (margin != null) ((JLabel)editorComponent).setBorder(marginBorder); ((JLabel)editorComponent).setHorizontalAlignment(halign); } @Override public Component getListCellEditorComponent(JEditList editList, Object value, boolean isSelected, int index) { if (IValueList.SEPARATOR.equals(value)) { return null; } if (editorComponent == null) createEditor(); editorComponent.setFont(editList.getFont()); if (isRowSelected(index) && paintSelection) { ((JLabel)editorComponent).setBackground(editList.getSelectionBackground()); editorComponent.setForeground(editList.getSelectionForeground()); editorComponent.setOpaque(true); } else { ((JLabel)editorComponent).setBackground(editList.getBackground()); editorComponent.setForeground(editList.getForeground()); editorComponent.setOpaque(false); } if (value == null) { ((JLabel)editorComponent).setText(""); //$NON-NLS-1$ } else { Object formattedValue = value; if (!"".equals(formattedValue) && format != null && formattedValue != null && !(formattedValue instanceof String)) //$NON-NLS-1$ { try { formattedValue = format.format(formattedValue); } catch (IllegalArgumentException ex) { Debug.error("Error formatting value for combobox " + dataProviderID + ", " + ex); //$NON-NLS-1$//$NON-NLS-2$ } } ((JLabel)editorComponent).setText(resolver != null ? Text.processTags(formattedValue.toString(), resolver) : formattedValue.toString()); } return editorComponent; } @Override public Object getCellEditorValue() { return paintSelection ? Boolean.valueOf(editorComponent.getBackground().equals(enclosedComponent.getSelectionBackground())) : Boolean.TRUE; } @Override public Component getListCellRendererComponent(JList editList, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (rendererComponent == null) createRenderer(); if (IValueList.SEPARATOR.equals(value)) { return new VariableSizeJSeparator(SwingConstants.HORIZONTAL, 15); } if (isRowSelected(index) && paintSelection) { ((JLabel)rendererComponent).setBackground(editList.getSelectionBackground()); rendererComponent.setForeground(editList.getSelectionForeground()); rendererComponent.setOpaque(true); } else { ((JLabel)rendererComponent).setBackground(editList.getBackground()); rendererComponent.setForeground(editList.getForeground()); rendererComponent.setOpaque(false); } rendererComponent.setFont(editList.getFont()); rendererComponent.setEnabled(editList.isEnabled()); if (value == null) { ((JLabel)rendererComponent).setText(""); //$NON-NLS-1$ } else { Object formattedValue = value; if (!"".equals(formattedValue) && format != null && formattedValue != null && !(formattedValue instanceof String)) //$NON-NLS-1$ { try { formattedValue = format.format(formattedValue); } catch (IllegalArgumentException ex) { Debug.error("Error formatting value for combobox " + dataProviderID + ", " + ex); //$NON-NLS-1$//$NON-NLS-2$ } } ((JLabel)rendererComponent).setText(resolver != null ? Text.processTags(formattedValue.toString(), resolver) : formattedValue.toString()); } rendererComponent.setBorder(marginBorder); if (cellHasFocus) { Border border = null; if (isSelected) { border = UIManager.getBorder("List.focusSelectedCellHighlightBorder"); } if (border == null) { border = UIManager.getBorder("List.focusCellHighlightBorder"); } if (margin != null) { rendererComponent.setBorder(BorderFactory.createCompoundBorder(marginBorder, border)); } else { rendererComponent.setBorder(border); } } return rendererComponent; } public void mouseClicked(MouseEvent e) { } public void mousePressed(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { doSelect(UIUtils.isCommandKeyDown(e), e.isShiftDown()); } } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } @Override public void doSelect(boolean isCommandKeyDown, boolean isShiftDown) { boolean selected = isRowSelected(enclosedComponent.getEditingRow()); if (!isCommandKeyDown && !isShiftDown && choiceType == Field.MULTISELECT_LISTBOX) { list.setMultiValueSelect(false); } if (selected) { if (!isCommandKeyDown && choiceType == Field.MULTISELECT_LISTBOX && list.getSelectedRows().size() > 1) { // clear the selection list setElementAt(Boolean.FALSE, enclosedComponent.getEditingRow()); } else { ((JLabel)editorComponent).setBackground(enclosedComponent.getBackground()); } } else { ((JLabel)editorComponent).setBackground(enclosedComponent.getSelectionBackground()); } if (isShiftDown && choiceType == Field.MULTISELECT_LISTBOX) { int clicked = enclosedComponent.getEditingRow(); int firstSelected = list.getSelectedRow(); int start = Math.min(clicked, firstSelected); int end = Math.max(clicked, firstSelected); for (int i = 0; i < list.getSize(); i++) { setElementAt((i >= start && i <= end) ? Boolean.TRUE : Boolean.FALSE, i); } } stopCellEditing(); list.setMultiValueSelect(choiceType == Field.MULTISELECT_LISTBOX); } } private boolean needEntireState; public void setNeedEntireState(boolean b) { needEntireState = b; } public void setHorizontalAlignment(int a) { halign = a; } public void notifyVisible(boolean b, List invokeLaterRunnables) { //ignore } @Override public void setVerticalScrollBarPolicy(int policy) { super.setVerticalScrollBarPolicy(policy); if (policy == VERTICAL_SCROLLBAR_NEVER) { enclosedComponent.setVisibleRowCount(0); enclosedComponent.setLayoutOrientation(JList.VERTICAL_WRAP); } } protected void setVerticalScrollBarPolicySpecial(int policy) { super.setVerticalScrollBarPolicy(policy); } @Override public void setHorizontalScrollBarPolicy(int policy) { super.setHorizontalScrollBarPolicy(policy); if (policy == HORIZONTAL_SCROLLBAR_NEVER) { enclosedComponent.setVisibleRowCount(0); enclosedComponent.setLayoutOrientation(JList.HORIZONTAL_WRAP); } } /* * _____________________________________________________________ Methods for IDisplayData */ public Object getValueObject() { Object[] rows = list.getSelectedRows().toArray(); Object[] objs = new Object[rows.length]; for (int i = 0; i < rows.length; i++) { objs[i] = list.getRealElementAt(((Integer)rows[i]).intValue()); } return getScriptObject().getChoiceValue(objs, choiceType != Field.MULTISELECT_LISTBOX && choiceType != Field.CHECKS); // Field.RADIOS || choiceType == Field.LIST_BOX || choiceType == Field.SPINNER will use plain value } private Object previousValue; protected ITagResolver resolver; public void setTagResolver(ITagResolver resolver) { this.resolver = resolver; } public void setValueObject(Object data) { try { if (editProvider != null) editProvider.setAdjusting(true); if (!Utils.equalObjects(getValueObject(), data)) { setValueValid(true, null); } if (list.getSelectedRows().size() > 0) { for (int i = 0; i < list.getSize(); i++) { list.setElementAt(Boolean.FALSE, i, true); } } if (needEntireState) { if (resolver != null) { if (tooltip != null) { enclosedComponent.setToolTipText(Text.processTags(tooltip, resolver)); } } else { if (tooltip != null) { enclosedComponent.setToolTipText(null); } } } else { if (tooltip != null) { enclosedComponent.setToolTipText(tooltip); } } if (list.getSelectedRows().size() > 0 && previousValue != null && previousValue.equals(data)) { return; } previousValue = data; if (data instanceof String) { String delim = (eventExecutor.getValidationEnabled() ? "\n" : "%\n"); //$NON-NLS-1$//$NON-NLS-2$ StringTokenizer tk = new StringTokenizer(data.toString(), delim); while (tk.hasMoreTokens()) { int row = list.realValueIndexOf(tk.nextToken()); if (row >= 0) list.setElementAt(Boolean.TRUE, row); } } else { int row = list.realValueIndexOf(data); if (row >= 0) list.setElementAt(Boolean.TRUE, row); } } finally { if (editProvider != null) editProvider.setAdjusting(false); } fireOnRender(false); } public void fireOnRender(boolean force) { if (scriptable != null) { if (force) scriptable.getRenderEventExecutor().setRenderStateChanged(); scriptable.getRenderEventExecutor().fireOnRender(hasFocus()); } } public boolean needEditListener() { return true; } private EditProvider editProvider = null; public void addEditListener(IEditListener l) { if (editProvider == null) { editProvider = new EditProvider(this); addFocusListener(editProvider); enclosedComponent.getModel().addListDataListener(this); // addListSelectionListener(editProvider); editProvider.addEditListener(l); } } public boolean needEntireState() { return needEntireState; } /* * @see IDisplayData#getDataProviderID() */ public String getDataProviderID() { return dataProviderID; } /* * @see IFieldComponent#setDataProviderID(String) */ public void setDataProviderID(String dataProviderID) { this.dataProviderID = dataProviderID; list.setDataProviderID(dataProviderID); } /* * @see IFieldComponent#setEditable(boolean) */ public void setEditable(boolean b) { editState = b; enclosedComponent.setEditable(b); } public boolean isEditable() { return !isReadOnly(); } /* * _____________________________________________________________ Methods for IDisplayRelatedData */ public void setRecord(IRecordInternal state, boolean stopEditing) { try { if (editProvider != null) editProvider.setAdjusting(true); list.fill(state); } finally { if (editProvider != null) editProvider.setAdjusting(false); } } public String getSelectedRelationName() { if (relationName == null && list != null) { relationName = list.getRelationName(); } return relationName; } private String relationName = null; private ArrayList<ILabel> labels; public String[] getAllRelationNames() { String selectedRelationName = getSelectedRelationName(); if (selectedRelationName == null) { return new String[0]; } else { return new String[] { selectedRelationName }; } } public boolean stopUIEditing(boolean looseFocus) { if (enclosedComponent.isEditing()) { if (looseFocus) { enclosedComponent.getCellEditor().stopCellEditing(); } else { editProvider.commitData(); } } if (!isValueValid) { application.invokeLater(new Runnable() { public void run() { enclosedComponent.requestFocus(); } }); return false; } return true; } @Override public void setBackground(Color c) { // if (enclosedComponent != null) enclosedComponent.setBackground(bg); super.setBackground(c); getViewport().setBackground(c); if (enclosedComponent != null) enclosedComponent.setBackground(c); if (rendererComponent != null) rendererComponent.setBackground(c); if (editorComponent != null) editorComponent.setBackground(c); } @Override public void setForeground(Color c) { // if (enclosedComponent != null) enclosedComponent.setForeground(fg); super.setForeground(c); getViewport().setForeground(c); if (enclosedComponent != null) enclosedComponent.setForeground(c); if (rendererComponent != null) rendererComponent.setForeground(c); if (editorComponent != null) editorComponent.setForeground(c); } public void setComponentVisible(boolean b_visible) { if (viewable || !b_visible) { setVisible(b_visible); } } @Override public void setVisible(boolean flag) { super.setVisible(flag); if (labels != null) { for (int i = 0; i < labels.size(); i++) { ILabel label = labels.get(i); label.setComponentVisible(flag); } } } public void addLabelFor(ILabel label) { if (labels == null) labels = new ArrayList(3); labels.add(label); } public List<ILabel> getLabelsFor() { return labels; } @Override public void setOpaque(boolean b) { // Called by the constructor of JScrollPane, so enclosed can be null. if (enclosedComponent != null) enclosedComponent.setOpaque(b); getViewport().setOpaque(b); super.setOpaque(b); } /* * readonly--------------------------------------------------- */ public boolean isReadOnly() { return !enclosedComponent.isEditable(); } private boolean editState; public void setReadOnly(boolean b) { if (b && !enclosedComponent.isEditable()) return; if (b) { enclosedComponent.setEditable(!b); editState = true; } else { enclosedComponent.setEditable(editState); } } public void setComponentEnabled(final boolean b) { if (accessible || !b) { super.setEnabled(b); enclosedComponent.setEnabled(b); if (labels != null) { for (int i = 0; i < labels.size(); i++) { ILabel label = labels.get(i); label.setComponentEnabled(b); } } } } private boolean accessible = true; public void setAccessible(boolean b) { if (!b) setComponentEnabled(b); if (!b) enclosedComponent.setEnabled(b); accessible = b; } private boolean viewable = true; public void setViewable(boolean b) { if (!b) setComponentVisible(b); this.viewable = b; } public boolean isViewable() { return viewable; } /* * titleText--------------------------------------------------- */ private String titleText = null; public void setTitleText(String title) { this.titleText = title; } public String getTitleText() { return Text.processTags(titleText, resolver); } public int getAbsoluteFormLocationY() { Container parent = getParent(); while ((parent != null) && !(parent instanceof IDataRenderer)) { parent = parent.getParent(); } if (parent != null) { return ((IDataRenderer)parent).getYOffset() + getLocation().y; } return getLocation().y; } private Point cachedLocation; public Point getCachedLocation() { return cachedLocation; } private Dimension cachedSize; public Dimension getCachedSize() { return cachedSize; } public void setCachedLocation(Point location) { this.cachedLocation = location; } public void setCachedSize(Dimension size) { this.cachedSize = size; } public IValueList getValueList() { return vl; } public ListDataListener getListener() { return null; } public void setValueList(IValueList vl) { list.register(vl); this.vl = vl; } public void requestFocusToComponent() { // if (!enclosedComponent.hasFocus()) Don't test on hasFocus (it can have focus,but other component already did requestFocus) { if (isDisplayable()) { // Must do it in a runnable or else others after a script can get focus first again.. application.invokeLater(new Runnable() { public void run() { enclosedComponent.requestFocus(); } }); } else { wantFocus = true; } } } @Override public void requestFocus() { if (enclosedComponent != null) enclosedComponent.requestFocus(); } // If component not shown or not added yet // and request focus is called it should wait for the component // to be created. boolean wantFocus = false; @Override public void addNotify() { super.addNotify(); if (wantFocus) { wantFocus = false; enclosedComponent.requestFocus(); } } public Component[] getFocusChildren() { return new Component[] { enclosedComponent }; } /** * @see javax.swing.event.ListDataListener#contentsChanged(javax.swing.event.ListDataEvent) */ public void contentsChanged(ListDataEvent e) { if (!list.isValueListChanging() && e.getIndex0() == -1 && e.getIndex1() == -1 && editProvider != null && !editProvider.isAdjusting()) { application.getFoundSetManager().getEditRecordList().prepareForSave(false); } else if (previousValue != null && list.isValueListChanging() && !(editProvider != null && editProvider.isAdjusting())) { setValueObject(previousValue); } } public void intervalAdded(ListDataEvent e) { if (previousValue != null && list.isValueListChanging() && !(editProvider != null && editProvider.isAdjusting())) { setValueObject(previousValue); } } public void intervalRemoved(ListDataEvent e) { if (previousValue != null && list.isValueListChanging() && !(editProvider != null && editProvider.isAdjusting())) { setValueObject(previousValue); } } @Override public String toString() { return scriptable.toString(); } public List getDefaultSort() { return null; } public String getId() { return (String)getClientProperty("Id"); //$NON-NLS-1$ } @Override public void paint(Graphics g) { // If we have regular SunGraphics2D object, just forward to superclass. if (g instanceof SunGraphics2D) { super.paint(g); } else { // If we are on Mac OS, we paint first to image buffer and then // to actual graphics. This is because the Aqua L&F on Mac does // not paint properly on graphics object that are not instances // of SunGraphics2D. if (Utils.isAppleMacOS()) { // Create buffered image and send it to be painted by superclass. int width = this.getWidth(); int height = this.getHeight(); BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D gr1 = (Graphics2D)img.getGraphics().create(); super.paint(gr1); gr1.dispose(); // Paint the image to the graphics that we received. Graphics2D g2d = (Graphics2D)g; g2d.drawRenderedImage(img, null); } // If we are not on Mac OS, just forward to superclass. else { super.paint(g); } } } }