package org.openswing.swing.client; import java.beans.*; import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import org.openswing.swing.form.client.*; import org.openswing.swing.form.model.client.*; import org.openswing.swing.lookup.client.*; import org.openswing.swing.mdi.client.*; import org.openswing.swing.message.receive.java.*; import org.openswing.swing.util.client.*; /** * <p>Title: OpenSwing Framework</p> * <p>Description: Lookup input Control used to digit a code. A code can be an alphanumeric or a numeric value. * When focus is lost from this control, a code validation is executed (only if the specified code is changed). * It contains also a lookup button, i.e. a button which allows to view a lookup grid of codes: * the user can select a code from the lookup grid and this code will be set in the code input field. * It optionally contains also a "+" button, used to call a controller class, related to the code registry, * i.e. the registry that allows to insert/update/delete codes referred by the lookup. * </p> * <p>Copyright: Copyright (C) 2006 Mauro Carniel</p> * * <p> This file is part of OpenSwing Framework. * This library is free software; you can redistribute it and/or * modify it under the terms of the (LGPL) Lesser General Public * License as published by the Free Software Foundation; * * GNU LESSER GENERAL PUBLIC LICENSE * Version 2.1, February 1999 * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * The author may be contacted at: * maurocarniel@tin.it</p> * * @author Mauro Carniel * @version 1.0 */ public class CodLookupControl extends BaseInputControl implements CodBoxContainer,InputControl,LookupParent,AutoCompletitionInputControl { /** separator between code input field and lookup button */ private Component buttonSeparator = javax.swing.Box.createHorizontalStrut(5); /** flag used to set if code field is editable */ private boolean enableCodBox = true; /** lookup button */ private JButton lookupButton = new JButton() { public void paint(Graphics g) { super.paint(g); int width = g.getFontMetrics().stringWidth("..."); if (isEnabled()) g.setColor(UIManager.getColor("Button.foreground")); else g.setColor(UIManager.getColor("Button.disabledForeground")); g.drawString("...", (this.getWidth()-width+1)/2, this.getHeight()/2+4); } }; /** code input field */ private CodBox codBox = new CodBox(); /** lookup controller: this class will execute the code validation and the lookup grid opening */ private LookupController validationController = null; /** class name of the controller that must be invoked by pressing the "+" button */ private String controllerClassName = null; /** method name defined in ClientFacade class, related to the controller that must be invoked by pressing the "+" button */ private String controllerMethodName = null; /** "+" button, used to call the controller class, related to the code registry */ private JButton plusButton = new JButton() { public void paint(Graphics g) { super.paint(g); int width = g.getFontMetrics().stringWidth("..."); g.drawString("+", (this.getWidth()-width+1)/2, this.getHeight()/2+4); } }; /** wait time (expressed in ms) before showing code auto completition feature for lookup controls; default value: ClientSettings.LOOKUP_AUTO_COMPLETITION_WAIT_TIME */ private long autoCompletitionWaitTime = ClientSettings.LOOKUP_AUTO_COMPLETITION_WAIT_TIME; /** used in addNotify method */ private boolean firstTime = true; private AutoCompletitionListener autoCompletitionListener = null; /** * Costructor. */ public CodLookupControl() { codBox.setContainer(this); setColumns(10); lookupButton.setText(null); lookupButton.setPreferredSize(new Dimension(21, codBox.getPreferredSize().height)); ClientUtils.addTabListener(lookupButton); lookupButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (validationController!=null) validationController.openLookupFrame(lookupButton,CodLookupControl.this); } }); plusButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (controllerClassName!=null) { try { Class.forName(controllerClassName).newInstance(); } catch (Throwable ex) { ex.printStackTrace(); } } else if (controllerMethodName!=null) { try { MDIFrame.getClientFacade().getClass().getMethod(controllerMethodName,new Class[0]).invoke(MDIFrame.getClientFacade(), new Object[0]); } catch (Throwable ex) { ex.printStackTrace(); } } } }); this.setLayout(new GridBagLayout()); this.add(codBox, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); this.add(buttonSeparator, new GridBagConstraints(1, 0, 1, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); this.add(lookupButton, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.VERTICAL, new Insets(0, 0, 0, 0), 0, 0)); lookupButton.setPreferredSize(new Dimension(lookupButton.getPreferredSize().width,codBox.getPreferredSize().height)); lookupButton.setMaximumSize(new Dimension(lookupButton.getPreferredSize().width,codBox.getPreferredSize().height)); lookupButton.setMinimumSize(new Dimension(lookupButton.getPreferredSize().width,codBox.getPreferredSize().height)); plusButton.setPreferredSize(new Dimension(lookupButton.getPreferredSize().width,codBox.getPreferredSize().height)); plusButton.setMaximumSize(new Dimension(lookupButton.getPreferredSize().width,codBox.getPreferredSize().height)); plusButton.setMinimumSize(new Dimension(lookupButton.getPreferredSize().width,codBox.getPreferredSize().height)); // setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); // this.add(codBox); // this.add(buttonSeparator); // this.add(lookupButton); if (ClientSettings.TEXT_ORIENTATION!=null) setComponentOrientation(ClientSettings.TEXT_ORIENTATION); initListeners(); } /** * @return code input field */ public JComponent getBindingComponent() { return codBox; } /** * @return code value */ public final Object getValue() { return codBox.getValue(); } /** * Select the combo item related to the specified code. * @param code used to retrieve the corresponding item and to select that item in the combo */ public final void setValue(Object code) { codBox.setValue(code); } /** * @return maximum code length */ public final int getMaxCharacters() { return codBox.getMaxCharacters(); } /** * Set the maximum code length. * @param maxCharacters maximum code length */ public final void setMaxCharacters(int maxCharacters) { this.codBox.setMaxCharacters(maxCharacters); } /** * @return code input field visibility */ public final boolean isCodBoxVisible() { return codBox.isVisible(); } /** * Set code input field visibility. * @param codBoxVisible code input field visibility */ public final void setCodBoxVisible(boolean codBoxVisible) { this.codBox.setVisible(codBoxVisible); if (!codBoxVisible) setColumns(0); } /** * @return code input field columns */ public final int getColumns() { return codBox.getColumns(); } /** * Set code input field columns. * @param columns code input field columns */ public final void setColumns(int columns) { this.codBox.setColumns(columns); StringBuffer s = new StringBuffer(columns); for(int i=0;i<columns;i++) s.append("W"); int w = getFontMetrics(getFont()).stringWidth(s.toString())+ lookupButton.getPreferredSize().width+ buttonSeparator.getPreferredSize().width+10; if (controllerMethodName!=null) w += plusButton.getPreferredSize().width; int h = new JButton("A").getPreferredSize().height; setMinimumSize(new Dimension(w,h)); setPreferredSize(new Dimension(w,h)); } /** * @return lookup controller */ public final LookupController getLookupController() { return validationController; } /** * Method that listen validation code event fired by the code input field: it validates the code. * @param code code to validate */ public final void validateCode(String code) throws RestoreFocusOnInvalidCodeException { if (autoCompletitionWaitTime>=0 && autoCompletitionListener!=null && autoCompletitionListener.isWindowVisible()) { codBox.setText(null); return; } if (validationController!=null) validationController.validateCode( codBox, code, this ); } public final void setEnabled(boolean enabled) { if (enableCodBox) this.codBox.setEditable(enabled); else this.codBox.setEditable(false); // this.codBox.setEnabled(enabled); this.lookupButton.setEnabled(enabled); this.codBox.setFocusable(enabled || ClientSettings.DISABLED_INPUT_CONTROLS_FOCUSABLE); this.lookupButton.setFocusable(enabled); } /** * @return current input control abilitation */ public final boolean isEnabled() { try { return this.codBox.isEditable(); } catch (Exception ex) { return false; } } /** * @return code input field */ public final CodBox getCodBox() { return codBox; } /** * Set lookup controller. * This method calls also addLookupListener method. * This method calls also setForm methos of the LookupController. * @param controller lookup controller. */ public final void setLookupController(LookupController controller) { this.validationController = controller; addLookupListener(controller); // set Form object in the lookup container... Form form = ClientUtils.getLinkedForm(this); if (form!=null) controller.setForm(form); } /** * Check if Form has been setted. */ public final void addNotify() { super.addNotify(); if (firstTime) { firstTime = false; // set Form object in the lookup container... if (!Beans.isDesignTime() && validationController!=null && validationController.getForm()==null) { Form form = ClientUtils.getLinkedForm(this); if (form != null) validationController.setForm(form); } if (!Beans.isDesignTime() && autoCompletitionWaitTime>=0 && autoCompletitionListener==null && getAttributeName()!=null) { autoCompletitionListener = new AutoCompletitionListener( this, new LookupAutoCompletitionDataLocator( validationController, getAttributeName() ), autoCompletitionWaitTime ); codBox.addKeyListener(autoCompletitionListener); } codBox.addKeyListener(new KeyAdapter() { public void keyReleased(KeyEvent e) { if (e.getKeyCode()==ClientSettings.LOOKUP_OPEN_KEY.getKeyCode() && e.getModifiers()+e.getModifiersEx()==ClientSettings.LOOKUP_OPEN_KEY.getModifiers()) { if (validationController!=null) validationController.openLookupFrame(codBox,CodLookupControl.this); } if (e.getKeyCode()==ClientSettings.LOOKUP_CONTROLLER_KEY.getKeyCode() && e.getModifiers()+e.getModifiersEx()==ClientSettings.LOOKUP_CONTROLLER_KEY.getModifiers()) { if (controllerClassName!=null) { try { Class.forName(controllerClassName).newInstance(); } catch (Throwable ex) { ex.printStackTrace(); } } else if (controllerMethodName!=null) { try { MDIFrame.getClientFacade().getClass().getMethod(controllerMethodName,new Class[0]).invoke(MDIFrame.getClientFacade(), new Object[0]); } catch (Throwable ex) { ex.printStackTrace(); } } } } }); } // end if } private final void addLookupListener(LookupController controller) { // lookup controller listener... controller.addLookupListener(new LookupListener() { /** * This method is called before code validation and when pressing lookup button. */ public void beforeLookupAction(ValueObject parentVO) {} /** * Callback called on code validation. * @param validated validation result */ public void codeValidated(boolean validated) { codBox.codeValidated(validated); } /** * Callback called when code is changed. * @param parentVO v.o. of the parent lookup container * @param parentChangedAttributes changed attributes of the v.o. of the parent lookup container */ public void codeChanged(ValueObject parentVO, Collection parentChangedAttributes) { try { String attrName; Iterator list = parentChangedAttributes.iterator(); Object newValue = null; while (list.hasNext()) { attrName = (String) list.next(); if (parentVO!=null) { String aux = attrName; Object obj = parentVO; while(aux.indexOf(".")!=-1) { obj = ClientUtils.getPropertyDescriptor(obj.getClass(),aux.substring(0,aux.indexOf("."))).getReadMethod().invoke(obj,new Object[0]); aux = aux.substring(aux.indexOf(".")+1); } if (obj==null) newValue = null; else if (ClientUtils.getPropertyDescriptor(obj.getClass(),aux)==null) newValue = null; else newValue = ClientUtils.getPropertyDescriptor(obj.getClass(),aux).getReadMethod().invoke(obj,new Object[0]); } else newValue = null; ValueChangeEvent e = new ValueChangeEvent(this, attrName, null, newValue); ValueChangeListener[] listeners = getValueChangeListeners(); for (int i = 0; i < listeners.length; i++) listeners[i].valueChanged(e); } } catch (Exception ex) { ex.printStackTrace(); } catch (Error er) { er.printStackTrace(); } } /** * Force the code validation. */ public void forceValidate() { codBox.forceValidate(); } }); } /** * Adds the specified focus listener to receive focus events from * this component when this component gains input focus. * If listener <code>l</code> is <code>null</code>, * no exception is thrown and no action is performed. * * @param l the focus listener * @see java.awt.event.FocusEvent * @see java.awt.event.FocusListener * @see #removeFocusListener * @see #getFocusListeners * @since JDK1.1 */ public final void addFocusListener(FocusListener listener) { try { codBox.addFocusListener(listener); } catch (Exception ex) { } } /** * Removes the specified focus listener so that it no longer * receives focus events from this component. This method performs * no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener <code>l</code> is <code>null</code>, * no exception is thrown and no action is performed. * * @param l the focus listener * @see java.awt.event.FocusEvent * @see java.awt.event.FocusListener * @see #addFocusListener * @see #getFocusListeners * @since JDK1.1 */ public final void removeFocusListener(FocusListener listener) { try { codBox.removeFocusListener(listener); } catch (Exception ex) { } } /** * Adds the specified action listener to receive * action events from this textfield. * * @param l the action listener to be added */ public final void addActionListener(ActionListener listener) { try { codBox.addActionListener(listener); } catch (Exception ex) { } } /** * Removes the specified action listener so that it no longer * receives action events from this textfield. * * @param l the action listener to be removed */ public final void removeActionListener(ActionListener listener) { try { codBox.removeActionListener(listener); } catch (Exception ex) { } } /** * @return define if the cod box allows numeric values only */ public final boolean isAllowOnlyNumbers() { return codBox.isAllowOnlyNumbers(); } /** * Define if the cod box allows numeric values only. * @param allowOnlyNumbers define if the cod box allows numeric values only */ public final void setAllowOnlyNumbers(boolean allowOnlyNumbers) { codBox.setAllowOnlyNumbers(allowOnlyNumbers); } /** * Set if code field is editable. * @param enableCodBox code field is editable */ public void setEnableCodBox(boolean enableCodBox) { this.enableCodBox = enableCodBox; if (!enableCodBox) codBox.setEnabled(enableCodBox); } /** * @return code field is editable */ public boolean isEnableCodBox() { return enableCodBox; } /** * Method called by LookupController to update parent v.o. * @param attributeName attribute name in the parent v.o. that must be updated * @param value updated value */ public void setValue(String attributeName,Object value) { if (validationController.getForm()!=null) validationController.getForm().getVOModel().setValue(attributeName,value); } /** * @return parent value object */ public ValueObject getValueObject() { if (validationController.getForm()==null) return null; if (validationController.getForm().getVOModel()==null) return null; return validationController.getForm().getVOModel().getValueObject(); } /** * @return attribute name in the parent value object related to lookup code */ public Object getLookupCodeParentValue() { if (validationController.getForm()!=null && validationController.getForm().getVOModel()!=null && getAttributeName()!=null) return validationController.getForm().getVOModel().getValue(getAttributeName()); return ""; } /** * @return class name of the controller that must be invoked by pressing the "+" button */ public final String getControllerClassName() { return controllerClassName; } /** * @return method name defined in ClientFacade class, related to the controller that must be invoked by pressing the "+" button */ public final String getControllerMethodName() { return controllerMethodName; } /** * Set the class name of the controller that must be invoked by pressing the "+" button. * @param controllerClassName class name of the controller that must be invoked by pressing the "+" button */ public final void setControllerClassName(String controllerClassName) { this.controllerClassName = controllerClassName; if (controllerMethodName!=null) this.add(plusButton, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.VERTICAL, new Insets(0, 0, 0, 0), 0, 0)); } /** * Set the method name defined in ClientFacade class, related to the controller that must be invoked by pressing the "+" button. * @param controllerMethodName method name defined in ClientFacade class, related to the controller that must be invoked by pressing the "+" button */ public final void setControllerMethodName(String controllerMethodName) { this.controllerMethodName = controllerMethodName; if (controllerMethodName!=null) this.add(plusButton, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.VERTICAL, new Insets(0, 0, 0, 0), 0, 0)); } /** * @return wait time (expressed in ms) before showing code auto completition feature for lookup controls; <code>-1</code>, to do not enable auto completition */ public final long getAutoCompletitionWaitTime() { return autoCompletitionWaitTime; } /** * Wait time before showing code auto completition feature for this lookup control. * @param autoCompletitionWaitTime wait time (expressed in ms) before showing code auto completition feature for this lookup control; default value: <code>-1</code> to do not enable auto completition */ public final void setAutoCompletitionWaitTime(long autoCompletitionWaitTime) { this.autoCompletitionWaitTime = autoCompletitionWaitTime; } /** * @return lookup button visibility */ public final boolean isLookupButtonVisible() { if (lookupButton!=null) return lookupButton.isVisible(); else return true; } /** * Set lookup button visibility. * @param lookup button visibility */ public final void setLookupButtonVisible(boolean lookupButtonVisible) { if (lookupButton!=null) this.lookupButton.setVisible(lookupButtonVisible); } /** * Set the component orientation: from left to right or from right to left. * @param o component orientation */ public final void setTextOrientation(ComponentOrientation o) { codBox.setComponentOrientation(o); } /** * @return component orientation */ public final ComponentOrientation getTextOrientation() { try { return codBox.getComponentOrientation(); } catch (Exception ex) { return null; } } }