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;
}
}