/** * */ package photoSpreadTable; import java.awt.Component; import java.rmi.NotBoundException; import javax.swing.AbstractCellEditor; import javax.swing.JTable; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import photoSpread.PhotoSpread; import photoSpreadUtilities.ComputableDimension; import photoSpreadUtilities.Misc; /** * @author paepcke * * Implements both the TableCellEditor and TableCellRenderer interfaces * for JTable. Both rendering and editing is provided by a combination * of PhotoSpreadCellHandler objects (subclasses of ObjectsPanel), * and the formula editor. Only one formula editor instance exists, * but each cell has its own associated PhotoSpreadCellHandler. * * We maintain an association between row/column pairs and their associated * PhotoSpreadCellHandler instance. When asked for a Component, both * getTableCellRendererComponent() and getTableCellEditorComponent() therefore * return a PhotoSpreadCellHandler instance, which is either created, * if one doesn't exist for the respective row/column pair, or is retrieved * from a specialized HashMap. * */ public class PhotoSpreadCellEditorAndRenderer extends AbstractCellEditor implements TableCellEditor, TableCellRenderer { private static final long serialVersionUID = 1L; // Place to remember each row/column's (i.e. visual cell's) PhotoSpreadCellHandler: static TableCellObjectsMap<PhotoSpreadCellHandler> _tableCellHandlers = new TableCellObjectsMap<PhotoSpreadCellHandler>(); PhotoSpreadCell _currentEditedCell = null; PhotoSpreadCellHandler _currentCellHandler = null; PhotoSpreadCellHandler _prevDragCellHandler = null; /**************************************************** * Constructor(s) *****************************************************/ /** * */ public PhotoSpreadCellEditorAndRenderer() { super(); } /**************************************************** * Methods to Satisfy Interface TableCellRenderer *****************************************************/ /** * The one method required by the TableCellRenderer * interface. We find or create the PhotoSpreadCellHandler * instance that provides both rendering and display, * and return it. * * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) */ public Component getTableCellRendererComponent( JTable table, Object currCellValue, boolean isSelected, // I *believe* this is true when // cell is in same row with the // active cell boolean hasFocus, // Called for each cell that's hovered // over, except for the active cell. int row, int column) { PhotoSpreadCellHandler cellHandler = _tableCellHandlers.get(row, column); if (cellHandler == null) { cellHandler = createCellHandler ((PhotoSpreadTable) table, row, column); } // Need the following unHighlight() because // JTable really does use cell editor/renderer // components as 'rubber stamps.' This means // that if the mechanism gets the selected cell // into its throat, it will use its opacity // on other cells one click on. Strange...: cellHandler.activeUnHighlight(); return cellHandler; } /**************************************************** * Getter/Setter(s) *****************************************************/ public PhotoSpreadCell getSelectedCellObject() { return _currentEditedCell; } /**************************************************** * Methods to Satisfy Interface TableCellEditor *****************************************************/ /* * The one method required by the TableCellEditor * interface. We find or create the PhotoSpreadCellHandler * instance that provides both rendering and display, * and return it. * * Before we do, we need to get that handler ready * * @see javax.swing.table.TableCellEditor#getTableCellEditorComponent(javax.swing.JTable, java.lang.Object, boolean, int, int) */ @Override public Component getTableCellEditorComponent( JTable table, Object initialValueForEditorToShow, boolean isSelected, int row, int column) { PhotoSpreadCellHandler cellHandler = _tableCellHandlers.get(row, column); if (_currentCellHandler != null) _currentCellHandler.activeUnHighlight(); _currentEditedCell = (PhotoSpreadCell) ((PhotoSpreadTable) table).getValueAt(row, column); if (cellHandler == null) { cellHandler = createCellHandler ( (PhotoSpreadTable)table, _currentEditedCell, row, column); } _currentCellHandler = cellHandler; cellHandler.activeHighlight(); try { ((PhotoSpreadTable) table).getWorkspace().setDisplayedCell(_currentEditedCell); } catch (NumberFormatException e) { Misc.showErrorMsgAndStackTrace(e, ""); // e.printStackTrace(); } catch (NotBoundException e) { Misc.showErrorMsgAndStackTrace(e, ""); //e.printStackTrace(); } updateFormulaEditor((PhotoSpreadTable) table, row, column); ((PhotoSpreadTable) table).getFormulaEditor().requestFocus(); return cellHandler; } /** * Simplified method for obtaining the cell editor * of the currently selected cell. * <b>NOTE</b> This version of the method will * not initialize the returned handler. It just * retrieves the handler. You <b>must</b> call * the long version to get all the initialization * done that is required to start editing. * * @param table Table that holds the cell whose editor is requested * @param row * @param column * @return PhotoSpreadCellHandler that renders and edits the currently * selected cell. */ public PhotoSpreadCellHandler getTableCellEditorComponent( PhotoSpreadTable table, int row, int column) { PhotoSpreadCellHandler cellHandler = _tableCellHandlers.get(row, column); if (_currentCellHandler != null) { _currentCellHandler.activeUnHighlight(); _currentCellHandler.stopCellEditing(); } if (cellHandler == null) { cellHandler = createCellHandler ( (PhotoSpreadTable)table, _currentEditedCell, row, column); } return cellHandler; } /* (non-Javadoc) * @see javax.swing.CellEditor#getCellEditorValue() */ @Override public Object getCellEditorValue() { return _currentEditedCell; } /**************************************************** * Support Methods for Both TableCellRenderer and TableCellEditor *****************************************************/ private PhotoSpreadCellHandler createCellHandler (PhotoSpreadTable table, int row, int column) { return createCellHandler ( table, (PhotoSpreadCell) ((PhotoSpreadTable) table).getValueAt(row, column), row, column); } /** * Create a new CellHandler that will be the * visual in one cell. * @param table * @param row * @param column * @return * @throws NotBoundException */ private PhotoSpreadCellHandler createCellHandler ( PhotoSpreadTable table, PhotoSpreadCell cellObj, int row, int column) { PhotoSpreadCellHandler cellHandler; // Create a handler for this cell. if (column == 0) cellHandler = new PhotoSpreadColumnZeroCellHandler (table, row, cellObj); else cellHandler = new PhotoSpreadCellHandler(table, cellObj); // Make this new cell ObjectsPanel findable by row/col: _tableCellHandlers.put(row, column, cellHandler); // Set minimum cell size as specified in the user preference // file or the built-in defaults: cellHandler.setMinimumSize(new ComputableDimension( PhotoSpread.photoSpreadPrefs.getInt(PhotoSpread.sheetColWidthMinKey), PhotoSpread.photoSpreadPrefs.getInt(PhotoSpread.sheetRowHeightMinKey))); // Set current and preferred sizes also to user/default sizes: cellHandler.setSize(cellHandler.getMinimumSize());; cellHandler.setPreferredSize(cellHandler.getMinimumSize()); cellHandler.setDisplayedCell((PhotoSpreadCell) table.getValueAt(row, column)); // Prepare panel to use the table's background as its // normal color. cellHandler.setBackground(null); cellHandler.setOpaque(true); return cellHandler; } private void updateFormulaEditor(PhotoSpreadTable table, int row, int column) { PhotoSpreadCell currCell = (PhotoSpreadCell) table.getValueAt(row, column); table.getFormulaEditor().setInitialValue(currCell.getFormula()); } }