001/* 002 * Copyright (c) 2005 Einar Pehrson <einar@pehrson.nu>. 003 * 004 * This file is part of 005 * CleanSheets - a spreadsheet application for the Java platform. 006 * 007 * CleanSheets is free software; you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation; either version 2 of the License, or 010 * (at your option) any later version. 011 * 012 * CleanSheets is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with CleanSheets; if not, write to the Free Software 019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 */ 021package csheets.ui.grid; 022 023import java.awt.Color; 024import java.awt.event.ActionEvent; 025import java.awt.event.KeyEvent; 026 027import javax.swing.AbstractAction; 028import javax.swing.JComponent; 029import javax.swing.JScrollPane; 030import javax.swing.JTable; 031import javax.swing.JViewport; 032import javax.swing.KeyStroke; 033import javax.swing.ListSelectionModel; 034import javax.swing.SwingConstants; 035import javax.swing.UIManager; 036import javax.swing.table.TableModel; 037 038 039/** 040 * A customized JTable component, with a row header and some other improved 041 * features. 042 * @author Einar Pehrson 043 */ 044@SuppressWarnings("serial") 045public class Grid extends JTable { 046 047 /** The action command used for the action */ 048 public static final String RESUME_EDIT_COMMAND = "Edit active cell"; 049 050 /** The table's row header, if it has been placed in a scroll bar */ 051 private RowHeader rowHeader; 052 053 /** 054 * Creates a blank grid. 055 */ 056 public Grid() { 057 this(null); 058 } 059 060 /** 061 * Creates a grid for the given table model. 062 * @param tableModel the table model to display in the table 063 */ 064 public Grid(TableModel tableModel) { 065 super(tableModel); 066 067 // Configures reordering and resizing 068 getTableHeader().setReorderingAllowed(false); 069 getTableHeader().setResizingAllowed(true); 070 setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 071 072 // Configures selection 073 setCellSelectionEnabled(true); 074 setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); 075 076 // Configures cell borders 077 setGridColor(gridColor.brighter()); 078 // setShowGrid(false); 079 // setIntercellSpacing(new Dimension(0, 0)); 080 081 // Configures table headers 082 UIManager.getDefaults().putDefaults(new Object[] { 083 "TableHeader.selectionForeground", Color.black, 084 "TableHeader.selectionBackground", Color.orange}); 085 getTableHeader().setDefaultRenderer( 086 new HeaderRenderer(SwingConstants.HORIZONTAL)); 087 088 // Configures cell editing 089 setSurrendersFocusOnKeystroke(true); 090 getActionMap().put(RESUME_EDIT_COMMAND, new ResumeEditAction()); 091 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), RESUME_EDIT_COMMAND); 092 } 093 094 /** 095 * Processes key bindings in the table. Overridden to prevent modified 096 * key events from invoking the editor. 097 */ 098 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, 099 boolean pressed) { 100 if (e.getKeyCode() == KeyEvent.VK_C 101 || e.getKeyCode() == KeyEvent.VK_X 102 || e.getKeyCode() == KeyEvent.VK_V 103 || !(e.isAltDown() || e.isControlDown())) 104 return super.processKeyBinding(ks, e, condition, pressed); 105 else 106 return false; 107 } 108 109 /** 110 * Changes the current selection in the table. Overridden to repaint row 111 * and column headers as well. 112 * @param row the row that was selected 113 * @param column the column that was selected 114 * @param toggle whether the selection should be toggled 115 * @param extend whether the selection should be extended 116 */ 117 public void changeSelection(int row, int column, boolean toggle, boolean extend) { 118 super.changeSelection(row, column, toggle, extend); 119 if (tableHeader != null) 120 tableHeader.repaint(); 121 if (rowHeader != null) 122 rowHeader.repaint(); 123 } 124 125/* 126 * ROW HEADER 127 */ 128 129 /** 130 * Adds the row header. 131 */ 132 protected void configureEnclosingScrollPane() { 133 super.configureEnclosingScrollPane(); 134 if (rowHeader == null) 135 rowHeader = new RowHeader(this); 136 setEnclosingScrollPaneRowHeaderView(rowHeader); 137 } 138 139 /** 140 * Removes the row header. 141 */ 142 protected void unconfigureEnclosingScrollPane() { 143 super.unconfigureEnclosingScrollPane(); 144 setEnclosingScrollPaneRowHeaderView(null); 145 } 146 147 /** 148 * Sets the row header view of an enclosing scroll pane to the given 149 * component. 150 * @param header the component to use as the row header, or null if no header is wanted 151 */ 152 private void setEnclosingScrollPaneRowHeaderView(JComponent header) { 153 // If the table is the main viewport of a scroll pane 154 if (getParent() instanceof JViewport) 155 if (getParent().getParent() instanceof JScrollPane) { 156 JScrollPane scrollPane = (JScrollPane)(getParent().getParent()); 157 JViewport viewport = scrollPane.getViewport(); 158 if (viewport != null && viewport.getView() == this) 159 // Updates row header 160 scrollPane.setRowHeaderView(header); 161 } 162 } 163 164/* 165 * ACTIONS 166 */ 167 168 /** 169 * An action for editing a cell, without clearing its contents. 170 * @author Einar Pehrson 171 */ 172 protected class ResumeEditAction extends AbstractAction { 173 174 /** 175 * Creates an edit resuming action. 176 */ 177 public ResumeEditAction() { 178 // Configures action 179 putValue(NAME, RESUME_EDIT_COMMAND); 180 putValue(SHORT_DESCRIPTION, RESUME_EDIT_COMMAND); 181 putValue(ACTION_COMMAND_KEY, RESUME_EDIT_COMMAND); 182 } 183 184 public void actionPerformed(ActionEvent e) { 185 int row = getSelectionModel().getAnchorSelectionIndex(); 186 int column = getColumnModel().getSelectionModel().getAnchorSelectionIndex(); 187 if (row >= 0 && column >= 0) 188 editCellAt(row, column, e); 189 } 190 } 191}