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 */
021 package csheets.ui.grid;
022
023 import java.awt.Color;
024 import java.awt.event.ActionEvent;
025 import java.awt.event.KeyEvent;
026
027 import javax.swing.AbstractAction;
028 import javax.swing.JComponent;
029 import javax.swing.JScrollPane;
030 import javax.swing.JTable;
031 import javax.swing.JViewport;
032 import javax.swing.KeyStroke;
033 import javax.swing.ListSelectionModel;
034 import javax.swing.SwingConstants;
035 import javax.swing.UIManager;
036 import 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")
045 public 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 }