/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.inspector.widget.propertylist; import java.awt.Color; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractCellEditor; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import org.openflexo.inspector.AbstractController; import org.openflexo.inspector.InspectableObject; import org.openflexo.inspector.model.PropertyListColumn; import org.openflexo.inspector.model.PropertyModel; import org.openflexo.inspector.widget.CustomWidget; import org.openflexo.inspector.widget.CustomWidget.ApplyCancelListener; import org.openflexo.toolbox.ToolBox; /** * Please comment this class * * @author sguerin * */ public abstract class CustomColumn extends AbstractColumn implements EditableColumn, ApplyCancelListener { private static final Logger logger = Logger.getLogger(CustomColumn.class.getPackage().getName()); PropertyListColumn _propertyListColumn; private CustomWidget _viewCustomWidget; private CustomWidget _editCustomWidget; private AbstractController _controller; private boolean useCustomViewForCellRendering; public CustomColumn(PropertyListColumn propertyListColumn, String title, int defaultWidth, AbstractController controller) { this(propertyListColumn, title, defaultWidth, true, controller); } public CustomColumn(PropertyListColumn propertyListColumn, String title, int defaultWidth, boolean isResizable, AbstractController controller) { this(propertyListColumn, title, defaultWidth, isResizable, true, controller); } public CustomColumn(PropertyListColumn propertyListColumn, String title, int defaultWidth, boolean isResizable, boolean displayTitle, AbstractController controller) { super(title, defaultWidth, isResizable, displayTitle); _propertyListColumn = propertyListColumn; _viewCustomWidget = buildCustomWidget(); _editCustomWidget = buildCustomWidget(); _editCustomWidget.addApplyCancelListener(this); _customCellRenderer = new CustomCellRenderer(); _customCellEditor = new CustomCellEditor(); _controller = controller; useCustomViewForCellRendering = Boolean.valueOf(propertyListColumn.getValueForParameter("customRendering")); } private CustomWidget buildCustomWidget() { String className = _propertyListColumn.getValueForParameter("className"); try { Class widgetClass = Class.forName(className); Class[] constructorClassParams = new Class[2]; constructorClassParams[0] = PropertyModel.class; constructorClassParams[1] = AbstractController.class; Constructor c = widgetClass.getConstructor(constructorClassParams); Object[] constructorParams = new Object[2]; constructorParams[0] = _propertyListColumn; constructorParams[1] = _controller; CustomWidget returned = (CustomWidget) c.newInstance(constructorParams); return returned; } catch (ClassNotFoundException e) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Class not found: " + className + ". See console for details."); } e.printStackTrace(); } catch (SecurityException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); } catch (NoSuchMethodException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); } catch (IllegalArgumentException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); } catch (InstantiationException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); } catch (IllegalAccessException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); } catch (InvocationTargetException e) { // Warns about the exception if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details."); } e.printStackTrace(); } return null; } @Override public Class getValueClass() { return _viewCustomWidget.getDefaultType(); } @Override public boolean isCellEditableFor(InspectableObject object) { return true; } @Override public void setValueFor(InspectableObject object, Object value) { setValue(object, value); notifyValueChangedFor(object); } public abstract void setValue(InspectableObject object, Object aValue); @Override public String toString() { return "CustomColumn " + "[" + getTitle() + "]" + Integer.toHexString(hashCode()); } @Override public Object getValueFor(InspectableObject object) { return getValue(object); } public abstract Object getValue(InspectableObject object); /** * Returns true as cell renderer is required here * * @return true */ @Override public boolean requireCellRenderer() { return true; } /** * @return */ @Override public TableCellRenderer getCellRenderer() { return _customCellRenderer; } private CustomCellRenderer _customCellRenderer; protected class CustomCellRenderer extends DefaultTableCellRenderer { /** * * Returns the selector cell renderer. * * @param table * the <code>JTable</code> * @param value * the value to assign to the cell at <code>[row, column]</code> * @param isSelected * true if cell is selected * @param hasFocus * true if cell has focus * @param row * the row of the cell to render * @param column * the column of the cell to render * @return the default table cell renderer */ @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component c; if (isSelected && hasFocus || useCustomViewForCellRendering) { c = getViewCustomWidget(elementAt(row)).getDynamicComponent(); Color fg = null; Color bg = null; if (isSelected) { c.setForeground(fg == null ? table.getSelectionForeground() : fg); c.setBackground(bg == null ? table.getSelectionBackground() : bg); } else { c.setForeground(table.getForeground()); c.setBackground(table.getBackground()); } setFont(table.getFont()); if (c instanceof JComponent) { if (hasFocus) { Border border = null; if (isSelected) { border = UIManager.getBorder("Table.focusSelectedCellHighlightBorder"); } if (border == null) { border = UIManager.getBorder("Table.focusCellHighlightBorder"); } ((JComponent) c).setBorder(border); } if (hasFocus && !isSelected && table.isCellEditable(row, column)) { Color col; col = UIManager.getColor("Table.focusCellForeground"); if (col != null) { c.setForeground(col); } col = UIManager.getColor("Table.focusCellBackground"); if (col != null) { c.setBackground(col); } } } } else { Component returned = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (returned instanceof JLabel) { ((JLabel) returned).setText(_propertyListColumn.getStringRepresentation(value)); if (ToolBox.isMacOSLaf()) { ((JLabel) returned).setForeground(getColorFor(value)); } } c = returned; } if (c instanceof JComponent) { ((JComponent) c).setToolTipText(getTooltip(elementAt(row))); } return c; } } protected Color getColorFor(Object value) { return _viewCustomWidget.getColorForObject(value); } protected CustomWidget getViewCustomWidget(InspectableObject value) { _viewCustomWidget.setModel(value); _viewCustomWidget.updateWidgetFromModel(); if (logger.isLoggable(Level.FINE)) { logger.fine("Return _viewCustomWidget for model " + value); } return _viewCustomWidget; } protected CustomWidget getEditCustomWidget(InspectableObject value) { _editCustomWidget.setModel(value); _editCustomWidget.updateWidgetFromModel(); if (logger.isLoggable(Level.FINE)) { logger.fine("Return _editCustomWidget for model " + value); } setEditedRowObject(value); return _editCustomWidget; } /** * Returns true as cell editor is required here * * @return true */ @Override public boolean requireCellEditor() { return true; } /** * Must be overriden if required * * @return */ @Override public TableCellEditor getCellEditor() { return _customCellEditor; } private CustomCellEditor _customCellEditor; protected class CustomCellEditor extends AbstractCellEditor implements TableCellEditor, ActionListener { CustomWidget _customWidget; public CustomCellEditor() { _customWidget = getEditCustomWidget(null); } @Override public void actionPerformed(ActionEvent e) { fireEditingStopped(); } @Override protected void fireEditingCanceled() { if (_customWidget != null) { _customWidget.fireEditingCanceled(); } super.fireEditingCanceled(); } @Override protected void fireEditingStopped() { if (_customWidget != null) { _customWidget.fireEditingStopped(); } super.fireEditingStopped(); } // Implement the one CellEditor method that AbstractCellEditor doesn't. @Override public Object getCellEditorValue() { return _customWidget.getEditedValue(); } // Implement the one method defined by TableCellEditor. @Override public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, int row, int column) { // logger.info("elementAt(row)="+elementAt(row)); if (_customWidget.disableTerminateEditOnFocusLost()) { table.putClientProperty("terminateEditOnFocusLost", Boolean.FALSE); } _customWidget.setModel(elementAt(row)); _customWidget.updateWidgetFromModel(); setEditedRowObject(elementAt(row)); if (_customWidget.disableTerminateEditOnFocusLost()) { _customWidget.addApplyCancelListener(new ApplyCancelListener() { @Override public void fireApplyPerformed() { table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); } @Override public void fireCancelPerformed() { table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); } }); } return _customWidget.getDynamicComponent(); } } protected InspectableObject _editedRowObject; protected void setEditedRowObject(InspectableObject anObject) { _editedRowObject = anObject; } @Override public void fireApplyPerformed() { notifyValueChangedFor(_editedRowObject); } @Override public void fireCancelPerformed() { } }