/* * Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org * Use is subject to license terms. See license.txt. */ // TODO javadoc - remove this comment only when the class and all non-public // methods and fields are documented package org.beanfabrics.swing.table.celleditor; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.Insets; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.EventObject; import java.util.List; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.event.CellEditorListener; import javax.swing.table.TableCellEditor; import org.beanfabrics.ModelProvider; import org.beanfabrics.Path; import org.beanfabrics.model.IBooleanPM; import org.beanfabrics.model.ITextPM; import org.beanfabrics.model.PresentationModel; import org.beanfabrics.swing.BnButton; import org.beanfabrics.swing.KeyBindingProcessor; import org.beanfabrics.swing.table.BnColumn; import org.beanfabrics.swing.table.BnTable; /** * The <code>BnTableCellEditor</code> is a {@link TableCellEditor} for a {@link PresentationModel} object inside a cell * of a {@link BnTable}. * <p> * Currently supported presentation models are: {@link ITextPM}, {@link IBooleanPM} * </p> * * @author Michael Karneim */ @SuppressWarnings("serial") public class BnTableCellEditor implements TableCellEditor { private final EmptyCellEditor FALLBACK_EDITOR = new EmptyCellEditor(); private int clickCountToStart = 1; private JComponent currentComponent; private TableCellEditor currentCellEditor; private final List<TableCellEditor> installedEditors = new ArrayList<TableCellEditor>(); public BnTableCellEditor() { super(); installDefaultEditors(); } private void installDefaultEditors() { installedEditors.add(new BnCheckBoxCellEditor()); installedEditors.add(new BnComboBoxCellEditor()); installedEditors.add(new BnTextFieldCellEditor()); } public List<TableCellEditor> getInstalledEditors() { return installedEditors; } /** {@inheritDoc} */ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { JComponent result = null; TableCellEditor editor = null; for (TableCellEditor aEd : installedEditors) { Component aComp = aEd.getTableCellEditorComponent(table, value, isSelected, row, column); if (aComp != null && aComp instanceof JComponent) { result = (JComponent) aComp; editor = aEd; break; } } if ( editor == null) { editor = FALLBACK_EDITOR; result = (JComponent)FALLBACK_EDITOR.getTableCellEditorComponent(table, value, isSelected, row, column); } BnColumn bnCol = getBnColumn(table, column); if (bnCol.getOperationPath() != null) { result = createButtonDecorator(table, row, result, bnCol); } this.setCurrentComponent(result); this.setCurrentCellEditor(editor); return result; } protected JComponent createButtonDecorator(JTable table, int row, JComponent leftComponent, BnColumn bnCol) { PresentationModel rowModel = getRowModel(table, row); ButtonDecorator deco = new ButtonDecorator(leftComponent, rowModel, bnCol.getOperationPath()); return deco; } protected PresentationModel getRowModel(JTable table, int row) { BnTable bnTable = (BnTable) table; PresentationModel result = bnTable.getPresentationModel().getAt(row); return result; } private BnColumn getBnColumn(JTable table, int column) { BnTable bnTable = (BnTable) table; BnColumn result = bnTable.getColumns()[column]; return result; } public JComponent getCurrentComponent() { return currentComponent; } public void setCurrentComponent(JComponent currentComponent) { this.currentComponent = currentComponent; } public TableCellEditor getCurrentCellEditor() { return currentCellEditor; } public void setCurrentCellEditor(TableCellEditor currentCellEditor) { this.currentCellEditor = currentCellEditor; } /** {@inheritDoc} */ public Object getCellEditorValue() { return null; // we don't support getting the value with this method } /** {@inheritDoc} */ public boolean isCellEditable(EventObject anEvent) { if (anEvent instanceof MouseEvent) { return ((MouseEvent) anEvent).getClickCount() >= clickCountToStart; } return true; } /** {@inheritDoc} */ public boolean shouldSelectCell(EventObject anEvent) { return currentCellEditor.shouldSelectCell(anEvent); } /** {@inheritDoc} */ public void cancelCellEditing() { currentCellEditor.cancelCellEditing(); this.setCurrentComponent(null); this.setCurrentCellEditor(null); } /** {@inheritDoc} */ public boolean stopCellEditing() { if (currentCellEditor == null) { return true; } boolean result = currentCellEditor.stopCellEditing(); this.setCurrentComponent(null); this.setCurrentCellEditor(null); return result; } /** {@inheritDoc} */ public void addCellEditorListener(CellEditorListener l) { currentCellEditor.addCellEditorListener(l); } /** {@inheritDoc} */ public void removeCellEditorListener(CellEditorListener l) { currentCellEditor.removeCellEditorListener(l); } private static class ButtonDecorator extends JPanel { private ModelProvider modelProvider = new ModelProvider(); private JComponent leftComponent; private BnButton button = new BnButton(); public ButtonDecorator(JComponent leftComponent, PresentationModel rootModel, Path operationPath) { this.leftComponent = leftComponent; this.setLayout(new BorderLayout(0, 0)); this.button.setMargin(new Insets(2, 2, 2, 2)); this.button.setText("..."); this.button.setFocusable(false); this.button.setPreferredSize(new Dimension(20, 0)); this.button.setModelProvider(modelProvider); this.button.setPath(operationPath); if (leftComponent != null) { this.add(leftComponent, BorderLayout.CENTER); } this.add(button, BorderLayout.EAST); this.setOpaque(false); this.modelProvider.setPresentationModel(rootModel); } public void dismiss() { this.modelProvider.setPresentationModel(null); } @Override public void requestFocus() { this.leftComponent.requestFocus(); } protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { boolean result = super.processKeyBinding(ks, e, condition, pressed); if (result == false) { if (leftComponent instanceof KeyBindingProcessor) { ((KeyBindingProcessor) leftComponent).processKeyBinding(ks, e, condition, pressed); } // final KeyEvent newEvt = new KeyEvent(leftComponent, e.getID(), e.getWhen(), e.getModifiers(), // e.getKeyCode(), e.getKeyChar(), e.getKeyLocation()); // EventQueue.invokeLater( new Runnable() { // public void run() { // leftComponent.dispatchEvent( newEvt); // } // }); } return result; } } }