package org.openswing.swing.table.editors.client; import java.lang.reflect.*; import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.table.*; import org.openswing.swing.items.client.*; import org.openswing.swing.logger.client.*; import org.openswing.swing.message.receive.java.*; import org.openswing.swing.table.client.*; import org.openswing.swing.table.columns.client.*; import org.openswing.swing.util.client.*; /** * <p>Title: OpenSwing Framework</p> * <p>Description: Column editor used to edit a ComboVOControl, linked to a list of value objects.</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 ComboBoxVOCellEditor extends AbstractCellEditor implements TableCellEditor,ItemsParent { /** table */ private JTable table = null; /** combo-box inside the editable cell */ private JComboBox field = new JComboBox() { private KeyEvent oldEv = null; public boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { if (e.getSource()!=null && e.getSource() instanceof org.openswing.swing.table.client.Grid) { try { if (oldEv==null || !e.equals(oldEv)) { oldEv = e; field.processKeyEvent(e); oldEv = null; } } catch (Exception ex) { } } else if (e.getKeyChar()=='\t' || e.getKeyChar()=='\n') { stopCellEditing(); try { if (!table.hasFocus()) table.requestFocus(); if (table.getSelectedRow()!=-1) table.setRowSelectionInterval(table.getSelectedRow(), table.getSelectedRow()); table.setColumnSelectionInterval(table.getSelectedColumn() + 1, table.getSelectedColumn() + 1); } catch (Exception ex) { } } return true; } }; /** flag sed to set mandatory property of the cell */ private boolean required; /** combo container */ private JPanel p = new JPanel(); /** combo box model */ private DefaultComboBoxModel model = new DefaultComboBoxModel(); /** items data source */ private ItemsDataLocator itemsDataLocator = null; /** items value object */ private ValueObject itemsVO = null; /** columns associated to lookup grid */ private Column[] colProperties = new Column[0]; /** flag used to set visibility on all columns of lookup grid; default "false" */ private boolean allColumnVisible = false; /** default preferredWidth for all columns of lookup grid; default 100 pixels */ private int allColumnPreferredWidth = 100; /** collection of pairs <v.o. attribute name,Method object, related to the attribute getter method> */ private Hashtable getters = new Hashtable(); /** value objects list */ private ArrayList items = null; /** cell content */ private ItemRenderer rend = new ItemRenderer(); private String attributeName; /** current row in edit */ private int row = -1; /** mapping between items v.o. attributes and items container v.o. attributes */ private ItemsMapper itemsMapper = new ItemsMapper(); /** attribute name in the combo-box v.o. that identify the attribute name in the v.o. of the combo-box container; as default value this attribute is null; null means that "attributeName" property will be used to identify the v.o. in the combo-box, i.e. the attribute names in the combo-box v.o. and in the container v.o. must have the same name */ private String foreignKeyAttributeName; /** * @return attribute name in the combo-box v.o. that identify the combo-box item */ private String getFKAttributeName() { return foreignKeyAttributeName==null || foreignKeyAttributeName.equals("") ? attributeName : foreignKeyAttributeName; } static { UIManager.put("ComboBox.disabledForeground", UIManager.get("ComboBox.foreground")); UIManager.put("ComboBox.disabledBackground", UIManager.get("TextField.inactiveBackground")); UIManager.put("ComboBox.selectionForeground", Color.black ); UIManager.put("ComboBox.selectionBackground", ClientSettings.BACKGROUND_SEL_COLOR ); } /** * Constructor. * @param domain domain linked to the combo-box * @param required flag sed to set mandatory property of the cell */ public ComboBoxVOCellEditor( ItemsMapper itemsMapper, ItemsDataLocator itemsDataLocator, String attributeName, ValueObject itemsVO, Column[] colProperties, boolean allColumnVisible, int allColumnPreferredWidth, Hashtable getters, boolean required, ArrayList itemListeners, String foreignKeyAttributeName, int leftMargin,int rightMargin,int topMargin,int bottomMargin, ComponentOrientation orientation ) { this.itemsMapper = itemsMapper; this.itemsDataLocator = itemsDataLocator; this.attributeName = attributeName; this.itemsVO = itemsVO; this.colProperties = colProperties; this.allColumnVisible = allColumnVisible; this.allColumnPreferredWidth = allColumnPreferredWidth; this.getters = getters; this.required = required; this.foreignKeyAttributeName = foreignKeyAttributeName; if (orientation!=null) field.setComponentOrientation(orientation); if (itemsDataLocator!=null && itemsVO!=null) { Response res = itemsDataLocator.loadData(itemsVO.getClass()); if (!res.isError()) { java.util.List items = ((VOListResponse)res).getRows(); for(int i=0;i<items.size();i++) { model.addElement(items.get(i)); } field.setModel(model); field.revalidate(); field.repaint(); field.setSelectedIndex(-1); } } ItemRenderer rend = new ItemRenderer(); rend.init(getters,colProperties,leftMargin,rightMargin,topMargin,bottomMargin); field.setRenderer(rend); field.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { // update v.o. container... if (e.getStateChange()==e.SELECTED) { ComboBoxVOCellEditor.this.itemsVO = (ValueObject)e.getItem(); updateParentModel(ComboBoxVOCellEditor.this); } } }); for(int i=0;i<itemListeners.size();i++) field.addItemListener((ItemListener)itemListeners.get(i)); p.setOpaque(true); p.setLayout(new GridBagLayout()); p.add(field, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0 ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0,0,0,0), 0, 0)); } /** * Method used to reload items in combo-box. */ public final void reloadItems() { if (itemsDataLocator!=null && itemsVO!=null) { Response res = itemsDataLocator.loadData(itemsVO.getClass()); if (!res.isError()) { java.util.List items = ((VOListResponse)res).getRows(); model = new DefaultComboBoxModel(); for(int i=0;i<items.size();i++) { model.addElement(items.get(i)); } field.setModel(model); field.revalidate(); field.repaint(); field.setSelectedIndex(-1); } } } /** * Stop cell editing. This method stops cell editing (effectively committing the edit) only if the data entered is validated successfully. * @return <code>true</code> if cell editing may stop, and <code>false</code> otherwise. */ public final boolean stopCellEditing() { return validate(); } /** * Perform the validation. */ private final boolean validate() { fireEditingStopped(); return true; } public final Object getCellEditorValue() { int selIndex = field.getSelectedIndex(); if (selIndex==-1) return null; try { return ( (Method) getters.get(getFKAttributeName())).invoke( model.getElementAt(selIndex), new Object[0] ); } catch (Throwable ex) { return null; } } /** * Prepare the editor for a value. */ private final Component _prepareEditor(Object value) { if (value==null) field.setSelectedIndex(-1); if (getFKAttributeName()!=null) { Object obj = null; try { field.setSelectedIndex(-1); for (int i = 0; i < model.getSize(); i++) { obj = ( (Method) getters.get(getFKAttributeName())).invoke( model.getElementAt(i), new Object[0] ); if (value.equals(obj)) { field.setSelectedIndex(i); break; } } } catch (Throwable ex) { field.setSelectedIndex(-1); } } SwingUtilities.invokeLater(new Runnable() { public void run() { if (!field.hasFocus()) { field.requestFocus(); } } }); return field; } public final Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { this.table = table; this.row = row; if (required) { field.setBorder(BorderFactory.createLineBorder(ClientSettings.GRID_REQUIRED_CELL_BORDER)); // field.setBorder(new CompoundBorder(new RequiredBorder(),field.getBorder())); } _prepareEditor(value); return p; } /** * Update the value object of the items parent container, only for attributes defined in ItemsMapper. * @param lookupParent lookup container */ private void updateParentModel(ItemsParent itemsParent) { if (itemsVO!=null && itemsMapper!=null) { try { // update items container vo from items vo values... Enumeration itemsAttributes = itemsMapper.getItemsChangedAttributes(); String itemsAttributeName, itemsMethodName; Method itemsMethod; String attrName = null; while (itemsAttributes.hasMoreElements()) { itemsAttributeName = (String) itemsAttributes.nextElement(); if (itemsAttributeName.length()==0) { // there has been defined a link between the whole items v.o. and an attribute in the container v.o. // related to an inner v.o. if (!itemsMapper.setParentAttribute( itemsParent, itemsAttributeName, itemsVO.getClass(), itemsVO)) Logger.error(this.getClass().getName(), "updateParentModel", "Error while setting items container value object.", null); } else { itemsMethodName = "get" + String.valueOf(Character.toUpperCase(itemsAttributeName.charAt(0))) + itemsAttributeName.substring(1); itemsMethod = itemsVO.getClass().getMethod(itemsMethodName, new Class[0]); if (!itemsMapper.setParentAttribute( itemsParent, itemsAttributeName, itemsMethod.getReturnType(), itemsMethod.invoke(itemsVO, new Object[0]) )) Logger.error(this.getClass().getName(),"updateParentModel","Error while setting items container value object.",null); } } } catch (Exception ex) { ex.printStackTrace(); } catch (Error er) { er.printStackTrace(); } } else { Logger.error(this.getClass().getName(),"updateParentModel","You must set 'itemsMapper' property",null); } } public ValueObject getValueObject() { if (row==-1) return null; return ((Grid)table).getVOListTableModel().getObjectForRow(row); } /** * setValue * * @param attributeName String * @param value Object */ public void setValue(String attributeName, Object value) { if (row!=-1) // ((Grid)table).getVOListTableModel().setValueAt(value,row,((Grid)table).getColumnIndex(attributeName)); ((Grid)table).getVOListTableModel().setField(row,attributeName,value); } public final void finalize() { colProperties = null; table = null; field = null; itemsMapper = null; itemsDataLocator = null; rend = null; } }