45 |
import java.awt.Graphics; |
import java.awt.Graphics; |
46 |
import java.awt.Point; |
import java.awt.Point; |
47 |
import java.awt.Rectangle; |
import java.awt.Rectangle; |
48 |
|
import java.awt.event.ActionEvent; |
49 |
import java.awt.event.FocusEvent; |
import java.awt.event.FocusEvent; |
50 |
import java.awt.event.FocusListener; |
import java.awt.event.FocusListener; |
51 |
import java.awt.event.InputEvent; |
import java.awt.event.InputEvent; |
53 |
import java.awt.event.KeyListener; |
import java.awt.event.KeyListener; |
54 |
import java.awt.event.MouseEvent; |
import java.awt.event.MouseEvent; |
55 |
|
|
56 |
|
import javax.swing.AbstractAction; |
57 |
import javax.swing.BorderFactory; |
import javax.swing.BorderFactory; |
58 |
import javax.swing.CellRendererPane; |
import javax.swing.CellRendererPane; |
59 |
|
import javax.swing.InputMap; |
60 |
import javax.swing.JComponent; |
import javax.swing.JComponent; |
61 |
import javax.swing.JTable; |
import javax.swing.JTable; |
62 |
import javax.swing.JTextField; |
import javax.swing.JTextField; |
63 |
|
import javax.swing.KeyStroke; |
64 |
import javax.swing.ListSelectionModel; |
import javax.swing.ListSelectionModel; |
65 |
import javax.swing.UIDefaults; |
import javax.swing.UIDefaults; |
66 |
import javax.swing.UIManager; |
import javax.swing.UIManager; |
93 |
/** The cell border for selected/highlighted cells. */ |
/** The cell border for selected/highlighted cells. */ |
94 |
Border highlightCellBorder; |
Border highlightCellBorder; |
95 |
|
|
96 |
|
/** The action bound to KeyStrokes. */ |
97 |
|
TableAction action; |
98 |
|
|
99 |
class FocusHandler implements FocusListener |
class FocusHandler implements FocusListener |
100 |
{ |
{ |
101 |
public void focusGained(FocusEvent e) |
public void focusGained(FocusEvent e) |
106 |
} |
} |
107 |
} |
} |
108 |
|
|
109 |
class KeyHandler implements KeyListener |
class MouseInputHandler implements MouseInputListener |
110 |
{ |
{ |
111 |
|
Point begin, curr; |
112 |
|
|
113 |
/** |
private void updateSelection(boolean controlPressed) |
|
* A helper method for the keyPressed event. Used because the actions |
|
|
* for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar. |
|
|
* |
|
|
* Selects the next (previous if SHIFT pressed) column for TAB, or row for |
|
|
* ENTER from within the currently selected cells. |
|
|
* |
|
|
* @param firstModel the ListSelectionModel for columns (TAB) or |
|
|
* rows (ENTER) |
|
|
* @param firstMin the first selected index in firstModel |
|
|
* @param firstMax the last selected index in firstModel |
|
|
* @param secondModel the ListSelectionModel for rows (TAB) or |
|
|
* columns (ENTER) |
|
|
* @param secondMin the first selected index in secondModel |
|
|
* @param secondMax the last selected index in secondModel |
|
|
* @param reverse true if shift was held for the event |
|
|
* @param eventIsTab true if TAB was pressed, false if ENTER pressed |
|
|
*/ |
|
|
void advanceMultipleSelection (ListSelectionModel firstModel, int firstMin, |
|
|
int firstMax, ListSelectionModel secondModel, |
|
|
int secondMin, int secondMax, boolean reverse, |
|
|
boolean eventIsTab) |
|
114 |
{ |
{ |
115 |
// If eventIsTab, all the "firsts" correspond to columns, otherwise, to rows |
// Update the rows |
116 |
// "seconds" correspond to the opposite |
int lo_row = table.rowAtPoint(begin); |
117 |
int firstLead = firstModel.getLeadSelectionIndex(); |
int hi_row = table.rowAtPoint(curr); |
118 |
int secondLead = secondModel.getLeadSelectionIndex(); |
ListSelectionModel rowModel = table.getSelectionModel(); |
119 |
int numFirsts = eventIsTab ? |
if (lo_row != -1 && hi_row != -1) |
|
table.getModel().getColumnCount() : table.getModel().getRowCount(); |
|
|
int numSeconds = eventIsTab ? |
|
|
table.getModel().getRowCount() : table.getModel().getColumnCount(); |
|
|
|
|
|
// check if we have to wrap the "firsts" around, going to the other side |
|
|
if ((firstLead == firstMax && !reverse) || |
|
|
(reverse && firstLead == firstMin)) |
|
120 |
{ |
{ |
121 |
firstModel.addSelectionInterval(reverse ? firstMax : firstMin, |
if (controlPressed && rowModel.getSelectionMode() |
122 |
reverse ? firstMax : firstMin); |
!= ListSelectionModel.SINGLE_SELECTION) |
123 |
|
rowModel.addSelectionInterval(lo_row, hi_row); |
|
// check if we have to wrap the "seconds" |
|
|
if ((secondLead == secondMax && !reverse) || |
|
|
(reverse && secondLead == secondMin)) |
|
|
secondModel.addSelectionInterval(reverse ? secondMax : secondMin, |
|
|
reverse ? secondMax : secondMin); |
|
|
|
|
|
// if we're not wrapping the seconds, we have to find out where we |
|
|
// are within the secondModel and advance to the next cell (or |
|
|
// go back to the previous cell if reverse == true) |
|
124 |
else |
else |
125 |
{ |
rowModel.setSelectionInterval(lo_row, hi_row); |
|
int[] secondsSelected; |
|
|
if (eventIsTab && table.getRowSelectionAllowed() || |
|
|
!eventIsTab && table.getColumnSelectionAllowed()) |
|
|
secondsSelected = eventIsTab ? |
|
|
table.getSelectedRows() : table.getSelectedColumns(); |
|
|
else |
|
|
{ |
|
|
// if row selection is not allowed, then the entire column gets |
|
|
// selected when you click on it, so consider ALL rows selected |
|
|
secondsSelected = new int[numSeconds]; |
|
|
for (int i = 0; i < numSeconds; i++) |
|
|
secondsSelected[i] = i; |
|
|
} |
|
|
|
|
|
// and now find the "next" index within the model |
|
|
int secondIndex = reverse ? secondsSelected.length - 1 : 0; |
|
|
if (!reverse) |
|
|
while (secondsSelected[secondIndex] <= secondLead) |
|
|
secondIndex++; |
|
|
else |
|
|
while (secondsSelected[secondIndex] >= secondLead) |
|
|
secondIndex--; |
|
|
|
|
|
// and select it - updating the lead selection index |
|
|
secondModel.addSelectionInterval(secondsSelected[secondIndex], |
|
|
secondsSelected[secondIndex]); |
|
|
} |
|
126 |
} |
} |
127 |
// We didn't have to wrap the firsts, so just find the "next" first |
|
128 |
// and select it, we don't have to change "seconds" |
// Update the columns |
129 |
else |
int lo_col = table.columnAtPoint(begin); |
130 |
|
int hi_col = table.columnAtPoint(curr); |
131 |
|
ListSelectionModel colModel = table.getColumnModel(). |
132 |
|
getSelectionModel(); |
133 |
|
if (lo_col != -1 && hi_col != -1) |
134 |
{ |
{ |
135 |
int[] firstsSelected; |
if (controlPressed && colModel.getSelectionMode() != |
136 |
if (eventIsTab && table.getColumnSelectionAllowed() || |
ListSelectionModel.SINGLE_SELECTION) |
137 |
!eventIsTab && table.getRowSelectionAllowed()) |
colModel.addSelectionInterval(lo_col, hi_col); |
|
firstsSelected = eventIsTab ? |
|
|
table.getSelectedColumns() : table.getSelectedRows(); |
|
138 |
else |
else |
139 |
{ |
colModel.setSelectionInterval(lo_col, hi_col); |
|
// if selection not allowed, consider ALL firsts to be selected |
|
|
firstsSelected = new int[numFirsts]; |
|
|
for (int i = 0; i < numFirsts; i++) |
|
|
firstsSelected[i] = i; |
|
|
} |
|
|
int firstIndex = reverse ? firstsSelected.length - 1 : 0; |
|
|
if (!reverse) |
|
|
while (firstsSelected[firstIndex] <= firstLead) |
|
|
firstIndex++; |
|
|
else |
|
|
while (firstsSelected[firstIndex] >= firstLead) |
|
|
firstIndex--; |
|
|
firstModel.addSelectionInterval(firstsSelected[firstIndex], |
|
|
firstsSelected[firstIndex]); |
|
|
secondModel.addSelectionInterval(secondLead, secondLead); |
|
140 |
} |
} |
141 |
} |
} |
|
|
|
|
/** |
|
|
* A helper method for the keyPressed event. Used because the actions |
|
|
* for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar. |
|
|
* |
|
|
* Selects the next (previous if SHIFT pressed) column (TAB) or row (ENTER) |
|
|
* in the table, changing the current selection. All cells in the table |
|
|
* are eligible, not just the ones that are currently selected. |
|
|
* @param firstModel the ListSelectionModel for columns (TAB) or rows |
|
|
* (ENTER) |
|
|
* @param firstMax the last index in firstModel |
|
|
* @param secondModel the ListSelectionModel for rows (TAB) or columns |
|
|
* (ENTER) |
|
|
* @param secondMax the last index in secondModel |
|
|
* @param reverse true if SHIFT was pressed for the event |
|
|
*/ |
|
142 |
|
|
143 |
void advanceSingleSelection (ListSelectionModel firstModel, int firstMax, |
public void mouseClicked(MouseEvent e) |
|
ListSelectionModel secondModel, int secondMax, |
|
|
boolean reverse) |
|
144 |
{ |
{ |
145 |
// for TABs, "first" corresponds to columns and "seconds" to rows. |
} |
146 |
// the opposite is true for ENTERs |
public void mouseDragged(MouseEvent e) |
147 |
int firstLead = firstModel.getLeadSelectionIndex(); |
{ |
148 |
int secondLead = secondModel.getLeadSelectionIndex(); |
curr = new Point(e.getX(), e.getY()); |
149 |
|
updateSelection(e.isControlDown()); |
150 |
// if we are going backwards subtract 2 because we later add 1 |
} |
151 |
// for a net change of -1 |
public void mouseEntered(MouseEvent e) |
152 |
if (reverse && (firstLead == 0)) |
{ |
153 |
{ |
} |
154 |
// check if we have to wrap around |
public void mouseExited(MouseEvent e) |
155 |
if (secondLead == 0) |
{ |
156 |
secondLead += secondMax + 1; |
} |
157 |
secondLead -= 2; |
public void mouseMoved(MouseEvent e) |
158 |
|
{ |
159 |
|
} |
160 |
|
public void mousePressed(MouseEvent e) |
161 |
|
{ |
162 |
|
ListSelectionModel rowModel = table.getSelectionModel(); |
163 |
|
ListSelectionModel colModel = table.getColumnModel().getSelectionModel(); |
164 |
|
int rowLead = rowModel.getLeadSelectionIndex(); |
165 |
|
int colLead = colModel.getLeadSelectionIndex(); |
166 |
|
|
167 |
|
begin = new Point(e.getX(), e.getY()); |
168 |
|
curr = new Point(e.getX(), e.getY()); |
169 |
|
//if control is pressed and the cell is already selected, deselect it |
170 |
|
if (e.isControlDown() && table. |
171 |
|
isCellSelected(table.rowAtPoint(begin),table.columnAtPoint(begin))) |
172 |
|
{ |
173 |
|
table.getSelectionModel(). |
174 |
|
removeSelectionInterval(table.rowAtPoint(begin), |
175 |
|
table.rowAtPoint(begin)); |
176 |
|
table.getColumnModel().getSelectionModel(). |
177 |
|
removeSelectionInterval(table.columnAtPoint(begin), |
178 |
|
table.columnAtPoint(begin)); |
179 |
} |
} |
|
|
|
|
// do we have to wrap the "seconds"? |
|
|
if (reverse && (firstLead == 0) || !reverse && (firstLead == firstMax)) |
|
|
secondModel.setSelectionInterval((secondLead + 1)%(secondMax + 1), |
|
|
(secondLead + 1)%(secondMax + 1)); |
|
|
// if not, just reselect the current lead |
|
180 |
else |
else |
181 |
secondModel.setSelectionInterval(secondLead, secondLead); |
updateSelection(e.isControlDown()); |
182 |
|
|
183 |
// if we are going backwards, subtract 2 because we add 1 later |
// If we were editing, but the moved to another cell, stop editing |
184 |
// for net change of -1 |
if (rowLead != rowModel.getLeadSelectionIndex() || |
185 |
if (reverse) |
colLead != colModel.getLeadSelectionIndex()) |
186 |
{ |
if (table.isEditing()) |
187 |
// check for wraparound |
table.editingStopped(new ChangeEvent(e)); |
|
if (firstLead == 0) |
|
|
firstLead += firstMax + 1; |
|
|
firstLead -= 2; |
|
|
} |
|
|
// select the next "first" |
|
|
firstModel.setSelectionInterval ((firstLead + 1)%(firstMax + 1), |
|
|
(firstLead + 1)%(firstMax + 1)); |
|
188 |
} |
} |
189 |
|
public void mouseReleased(MouseEvent e) |
190 |
|
{ |
191 |
|
begin = null; |
192 |
|
curr = null; |
193 |
|
} |
194 |
|
} |
195 |
|
|
196 |
|
protected FocusListener createFocusListener() |
197 |
|
{ |
198 |
|
return new FocusHandler(); |
199 |
|
} |
200 |
|
|
201 |
|
protected MouseInputListener createMouseInputListener() |
202 |
|
{ |
203 |
|
return new MouseInputHandler(); |
204 |
|
} |
205 |
|
|
206 |
|
public Dimension getMaximumSize(JComponent comp) |
207 |
|
{ |
208 |
|
return getPreferredSize(comp); |
209 |
|
} |
210 |
|
|
211 |
public void keyPressed(KeyEvent evt) |
public Dimension getMinimumSize(JComponent comp) |
212 |
|
{ |
213 |
|
return getPreferredSize(comp); |
214 |
|
} |
215 |
|
|
216 |
|
public Dimension getPreferredSize(JComponent comp) |
217 |
|
{ |
218 |
|
int width = table.getColumnModel().getTotalColumnWidth(); |
219 |
|
int height = table.getRowCount() * table.getRowHeight(); |
220 |
|
return new Dimension(width, height); |
221 |
|
} |
222 |
|
|
223 |
|
protected void installDefaults() |
224 |
|
{ |
225 |
|
UIDefaults defaults = UIManager.getLookAndFeelDefaults(); |
226 |
|
table.setFont(defaults.getFont("Table.font")); |
227 |
|
table.setGridColor(defaults.getColor("Table.gridColor")); |
228 |
|
table.setForeground(defaults.getColor("Table.foreground")); |
229 |
|
table.setBackground(defaults.getColor("Table.background")); |
230 |
|
table.setSelectionForeground(defaults.getColor("Table.selectionForeground")); |
231 |
|
table.setSelectionBackground(defaults.getColor("Table.selectionBackground")); |
232 |
|
table.setOpaque(true); |
233 |
|
|
234 |
|
highlightCellBorder = defaults.getBorder("Table.focusCellHighlightBorder"); |
235 |
|
cellBorder = BorderFactory.createEmptyBorder(1, 1, 1, 1); |
236 |
|
} |
237 |
|
|
238 |
|
private int convertModifiers(int mod) |
239 |
|
{ |
240 |
|
if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0) |
241 |
|
{ |
242 |
|
mod |= KeyEvent.SHIFT_MASK; |
243 |
|
mod &= ~KeyEvent.SHIFT_DOWN_MASK; |
244 |
|
} |
245 |
|
if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0) |
246 |
|
{ |
247 |
|
mod |= KeyEvent.CTRL_MASK; |
248 |
|
mod &= ~KeyEvent.CTRL_DOWN_MASK; |
249 |
|
} |
250 |
|
if ((mod & KeyEvent.META_DOWN_MASK) != 0) |
251 |
|
{ |
252 |
|
mod |= KeyEvent.META_MASK; |
253 |
|
mod &= ~KeyEvent.META_DOWN_MASK; |
254 |
|
} |
255 |
|
if ((mod & KeyEvent.ALT_DOWN_MASK) != 0) |
256 |
|
{ |
257 |
|
mod |= KeyEvent.ALT_MASK; |
258 |
|
mod &= ~KeyEvent.ALT_DOWN_MASK; |
259 |
|
} |
260 |
|
if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0) |
261 |
|
{ |
262 |
|
mod |= KeyEvent.ALT_GRAPH_MASK; |
263 |
|
mod &= ~KeyEvent.ALT_GRAPH_DOWN_MASK; |
264 |
|
} |
265 |
|
return mod; |
266 |
|
} |
267 |
|
|
268 |
|
protected void installKeyboardActions() |
269 |
|
{ |
270 |
|
UIDefaults defaults = UIManager.getLookAndFeelDefaults(); |
271 |
|
InputMap ancestorMap = (InputMap)defaults.get("Table.ancestorInputMap"); |
272 |
|
action = new TableAction(); |
273 |
|
Object keys[] = ancestorMap.allKeys(); |
274 |
|
// Register the key bindings with the JTable. |
275 |
|
// Note that we register key bindings with both the old and new modifier |
276 |
|
// masks: InputEvent.SHIFT_MASK and InputEvent.SHIFT_DOWN_MASK and so on. |
277 |
|
for (int i = 0; i < keys.length; i++) |
278 |
|
{ |
279 |
|
table.registerKeyboardAction(action,(String)ancestorMap.get((KeyStroke)keys[i]), |
280 |
|
KeyStroke.getKeyStroke |
281 |
|
(((KeyStroke)keys[i]).getKeyCode(), convertModifiers(((KeyStroke)keys[i]).getModifiers())), |
282 |
|
JComponent.WHEN_FOCUSED); |
283 |
|
|
284 |
|
table.registerKeyboardAction(action,(String)ancestorMap.get((KeyStroke)keys[i]), |
285 |
|
KeyStroke.getKeyStroke |
286 |
|
(((KeyStroke)keys[i]).getKeyCode(), ((KeyStroke)keys[i]).getModifiers()), |
287 |
|
JComponent.WHEN_FOCUSED); |
288 |
|
} |
289 |
|
} |
290 |
|
|
291 |
|
/** |
292 |
|
* This class implements the actions that we want to happen |
293 |
|
* when specific keys are pressed for the JTable. The actionPerformed |
294 |
|
* method is called when a key that has been registered for the JTable |
295 |
|
* is received. |
296 |
|
*/ |
297 |
|
class TableAction extends AbstractAction |
298 |
|
{ |
299 |
|
/** |
300 |
|
* What to do when this action is called. |
301 |
|
* |
302 |
|
* @param e the ActionEvent that caused this action. |
303 |
|
*/ |
304 |
|
public void actionPerformed (ActionEvent e) |
305 |
{ |
{ |
306 |
ListSelectionModel rowModel = table.getSelectionModel(); |
ListSelectionModel rowModel = table.getSelectionModel(); |
307 |
ListSelectionModel colModel = table.getColumnModel().getSelectionModel(); |
ListSelectionModel colModel = table.getColumnModel().getSelectionModel(); |
312 |
int colLead = colModel.getLeadSelectionIndex(); |
int colLead = colModel.getLeadSelectionIndex(); |
313 |
int colMax = table.getModel().getColumnCount() - 1; |
int colMax = table.getModel().getColumnCount() - 1; |
314 |
|
|
315 |
if ((evt.getKeyCode() == KeyEvent.VK_DOWN) |
if (e.getActionCommand().equals("selectPreviousRowExtendSelection")) |
|
|| (evt.getKeyCode() == KeyEvent.VK_KP_DOWN)) |
|
316 |
{ |
{ |
317 |
if (evt.getModifiers() == 0) |
rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0)); |
318 |
{ |
colModel.setLeadSelectionIndex(colLead); |
|
|
|
|
table.clearSelection(); |
|
|
rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax), |
|
|
Math.min(rowLead + 1, rowMax)); |
|
|
colModel.setSelectionInterval(colLead,colLead); |
|
|
} |
|
|
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
|
|
{ |
|
|
rowModel.setLeadSelectionIndex(Math.min(rowLead + 1, rowMax)); |
|
|
colModel.setLeadSelectionIndex(colLead); |
|
|
} |
|
319 |
} |
} |
320 |
else if ((evt.getKeyCode() == KeyEvent.VK_UP) |
else if (e.getActionCommand().equals("selectLastColumn")) |
|
|| (evt.getKeyCode() == KeyEvent.VK_KP_UP)) |
|
321 |
{ |
{ |
322 |
if (evt.getModifiers() == 0) |
table.clearSelection(); |
323 |
{ |
rowModel.setSelectionInterval(rowLead, rowLead); |
324 |
table.clearSelection(); |
colModel.setSelectionInterval(colMax, colMax); |
|
rowModel.setSelectionInterval(Math.max(rowLead - 1, 0), |
|
|
Math.max(rowLead - 1, 0)); |
|
|
colModel.setSelectionInterval(colLead,colLead); |
|
|
} |
|
|
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
|
|
{ |
|
|
rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0)); |
|
|
colModel.setLeadSelectionIndex(colLead); |
|
|
} |
|
325 |
} |
} |
326 |
else if ((evt.getKeyCode() == KeyEvent.VK_LEFT) |
else if (e.getActionCommand().equals("startEditing")) |
|
|| (evt.getKeyCode() == KeyEvent.VK_KP_LEFT)) |
|
327 |
{ |
{ |
328 |
if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
if (table.isCellEditable(rowLead, colLead)) |
329 |
{ |
table.editCellAt(rowLead,colLead); |
330 |
colModel.setLeadSelectionIndex(Math.max(colLead - 1, 0)); |
} |
331 |
rowModel.setLeadSelectionIndex(rowLead); |
else if (e.getActionCommand().equals("selectFirstRowExtendSelection")) |
332 |
} |
{ |
333 |
else if (evt.getModifiers() == 0) |
rowModel.setLeadSelectionIndex(0); |
334 |
{ |
colModel.setLeadSelectionIndex(colLead); |
|
table.clearSelection(); |
|
|
rowModel.setSelectionInterval(rowLead,rowLead); |
|
|
colModel.setSelectionInterval(Math.max(colLead - 1, 0), |
|
|
Math.max(colLead - 1, 0)); |
|
|
} |
|
335 |
} |
} |
336 |
else if ((evt.getKeyCode() == KeyEvent.VK_RIGHT) |
else if (e.getActionCommand().equals("selectFirstColumn")) |
|
|| (evt.getKeyCode() == KeyEvent.VK_KP_RIGHT)) |
|
337 |
{ |
{ |
338 |
if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
rowModel.setSelectionInterval(rowLead, rowLead); |
339 |
{ |
colModel.setSelectionInterval(0, 0); |
|
colModel.setLeadSelectionIndex(Math.min(colLead + 1, colMax)); |
|
|
rowModel.setLeadSelectionIndex(rowLead); |
|
|
} |
|
|
else if (evt.getModifiers() == 0) |
|
|
{ |
|
|
table.clearSelection(); |
|
|
rowModel.setSelectionInterval(rowLead,rowLead); |
|
|
colModel.setSelectionInterval(Math.min(colLead + 1, colMax), |
|
|
Math.min(colLead + 1, colMax)); |
|
|
} |
|
340 |
} |
} |
341 |
else if (evt.getKeyCode() == KeyEvent.VK_END) |
else if (e.getActionCommand().equals("selectFirstColumnExtendSelection")) |
342 |
{ |
{ |
343 |
if (evt.getModifiers() == (InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK)) |
colModel.setLeadSelectionIndex(0); |
344 |
{ |
rowModel.setLeadSelectionIndex(rowLead); |
|
rowModel.setLeadSelectionIndex(rowMax); |
|
|
colModel.setLeadSelectionIndex(colLead); |
|
|
} |
|
|
else if (evt.getModifiers() == InputEvent.CTRL_MASK) |
|
|
{ |
|
|
table.clearSelection(); |
|
|
rowModel.setSelectionInterval(rowMax,rowMax); |
|
|
colModel.setSelectionInterval(colLead, colLead); |
|
|
} |
|
|
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
|
|
{ |
|
|
colModel.setLeadSelectionIndex(colMax); |
|
|
rowModel.setLeadSelectionIndex(rowLead); |
|
|
} |
|
|
else if (evt.getModifiers() == 0) |
|
|
{ |
|
|
table.clearSelection(); |
|
|
rowModel.setSelectionInterval(rowLead, rowLead); |
|
|
colModel.setSelectionInterval(colMax, colMax); |
|
|
} |
|
345 |
} |
} |
346 |
else if (evt.getKeyCode() == KeyEvent.VK_HOME) |
else if (e.getActionCommand().equals("selectLastRow")) |
347 |
{ |
{ |
348 |
if (evt.getModifiers() == |
rowModel.setSelectionInterval(rowMax,rowMax); |
349 |
(InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK)) |
colModel.setSelectionInterval(colLead, colLead); |
350 |
{ |
} |
351 |
rowModel.setLeadSelectionIndex(0); |
else if (e.getActionCommand().equals("selectNextRowExtendSelection")) |
352 |
colModel.setLeadSelectionIndex(colLead); |
{ |
353 |
} |
rowModel.setLeadSelectionIndex(Math.min(rowLead + 1, rowMax)); |
354 |
else if (evt.getModifiers() == InputEvent.CTRL_MASK) |
colModel.setLeadSelectionIndex(colLead); |
|
{ |
|
|
table.clearSelection(); |
|
|
rowModel.setSelectionInterval(0,0); |
|
|
colModel.setSelectionInterval(colLead, colLead); |
|
|
} |
|
|
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
|
|
{ |
|
|
colModel.setLeadSelectionIndex(0); |
|
|
rowModel.setLeadSelectionIndex(rowLead); |
|
|
} |
|
|
else if (evt.getModifiers() == 0) |
|
|
{ |
|
|
table.clearSelection(); |
|
|
rowModel.setSelectionInterval(rowLead, rowLead); |
|
|
colModel.setSelectionInterval(0, 0); |
|
|
} |
|
355 |
} |
} |
356 |
else if (evt.getKeyCode() == KeyEvent.VK_F2) |
else if (e.getActionCommand().equals("selectFirstRow")) |
357 |
{ |
{ |
358 |
table.editCellAt(rowLead,colLead); |
rowModel.setSelectionInterval(0,0); |
359 |
|
colModel.setSelectionInterval(colLead, colLead); |
360 |
} |
} |
361 |
else if (evt.getKeyCode() == KeyEvent.VK_PAGE_UP) |
else if (e.getActionCommand().equals("selectNextColumnExtendSelection")) |
362 |
|
{ |
363 |
|
colModel.setLeadSelectionIndex(Math.min(colLead + 1, colMax)); |
364 |
|
rowModel.setLeadSelectionIndex(rowLead); |
365 |
|
} |
366 |
|
else if (e.getActionCommand().equals("selectLastColumnExtendSelection")) |
367 |
|
{ |
368 |
|
colModel.setLeadSelectionIndex(colMax); |
369 |
|
rowModel.setLeadSelectionIndex(rowLead); |
370 |
|
} |
371 |
|
else if (e.getActionCommand().equals("selectPreviousColumnExtendSelection")) |
372 |
|
{ |
373 |
|
colModel.setLeadSelectionIndex(Math.max(colLead - 1, 0)); |
374 |
|
rowModel.setLeadSelectionIndex(rowLead); |
375 |
|
} |
376 |
|
else if (e.getActionCommand().equals("selectNextRow")) |
377 |
|
{ |
378 |
|
rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax), |
379 |
|
Math.min(rowLead + 1, rowMax)); |
380 |
|
colModel.setSelectionInterval(colLead,colLead); |
381 |
|
} |
382 |
|
else if (e.getActionCommand().equals("scrollUpExtendSelection")) |
383 |
{ |
{ |
384 |
int target; |
int target; |
385 |
if (!evt.isControlDown()) |
if (rowLead == getFirstVisibleRowIndex()) |
386 |
{ |
target = Math.max |
387 |
if (rowLead == getFirstVisibleRowIndex()) |
(0, rowLead - (getLastVisibleRowIndex() - |
388 |
target = Math.max |
getFirstVisibleRowIndex() + 1)); |
|
(0, rowLead - (getLastVisibleRowIndex() - |
|
|
getFirstVisibleRowIndex() + 1)); |
|
|
else |
|
|
target = getFirstVisibleRowIndex(); |
|
|
|
|
|
if (evt.getModifiers() == 0) |
|
|
{ |
|
|
rowModel.setSelectionInterval(target, target); |
|
|
colModel.setSelectionInterval(colLead, colLead); |
|
|
} |
|
|
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
|
|
{ |
|
|
rowModel.setLeadSelectionIndex(target); |
|
|
colModel.setLeadSelectionIndex(colLead); |
|
|
} |
|
|
} |
|
389 |
else |
else |
390 |
{ |
target = getFirstVisibleRowIndex(); |
391 |
if (colLead == getFirstVisibleColumnIndex()) |
|
392 |
target = Math.max |
rowModel.setLeadSelectionIndex(target); |
393 |
(0, colLead - (getLastVisibleColumnIndex() - |
colModel.setLeadSelectionIndex(colLead); |
|
getFirstVisibleColumnIndex() + 1)); |
|
|
else |
|
|
target = getFirstVisibleColumnIndex(); |
|
|
|
|
|
if (evt.getModifiers() == InputEvent.CTRL_MASK) |
|
|
{ |
|
|
colModel.setSelectionInterval(target, target); |
|
|
rowModel.setSelectionInterval(rowLead, rowLead); |
|
|
} |
|
|
else if (evt.getModifiers() == |
|
|
(InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK)) |
|
|
{ |
|
|
colModel.setLeadSelectionIndex(target); |
|
|
rowModel.setLeadSelectionIndex(rowLead); |
|
|
} |
|
|
} |
|
394 |
} |
} |
395 |
else if (evt.getKeyCode() == KeyEvent.VK_PAGE_DOWN) |
else if (e.getActionCommand().equals("selectPreviousRow")) |
396 |
|
{ |
397 |
|
rowModel.setSelectionInterval(Math.max(rowLead - 1, 0), |
398 |
|
Math.max(rowLead - 1, 0)); |
399 |
|
colModel.setSelectionInterval(colLead,colLead); |
400 |
|
} |
401 |
|
else if (e.getActionCommand().equals("scrollRightChangeSelection")) |
402 |
{ |
{ |
403 |
int target; |
int target; |
404 |
if (!evt.isControlDown()) |
if (colLead == getLastVisibleColumnIndex()) |
405 |
{ |
target = Math.min |
406 |
if (rowLead == getLastVisibleRowIndex()) |
(colMax, colLead + (getLastVisibleColumnIndex() - |
407 |
target = Math.min |
getFirstVisibleColumnIndex() + 1)); |
|
(rowMax, rowLead + (getLastVisibleRowIndex() - |
|
|
getFirstVisibleRowIndex() + 1)); |
|
|
else |
|
|
target = getLastVisibleRowIndex(); |
|
|
|
|
|
if (evt.getModifiers() == 0) |
|
|
{ |
|
|
rowModel.setSelectionInterval(target, target); |
|
|
colModel.setSelectionInterval(colLead, colLead); |
|
|
} |
|
|
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
|
|
{ |
|
|
rowModel.setLeadSelectionIndex(target); |
|
|
colModel.setLeadSelectionIndex(colLead); |
|
|
} |
|
|
} |
|
408 |
else |
else |
409 |
{ |
target = getLastVisibleColumnIndex(); |
410 |
if (colLead == getLastVisibleColumnIndex()) |
|
411 |
target = Math.min |
colModel.setSelectionInterval(target, target); |
412 |
(colMax, colLead + (getLastVisibleColumnIndex() - |
rowModel.setSelectionInterval(rowLead, rowLead); |
413 |
getFirstVisibleColumnIndex() + 1)); |
} |
414 |
else |
else if (e.getActionCommand().equals("selectPreviousColumn")) |
415 |
target = getLastVisibleColumnIndex(); |
{ |
416 |
|
rowModel.setSelectionInterval(rowLead,rowLead); |
417 |
if (evt.getModifiers() == InputEvent.CTRL_MASK) |
colModel.setSelectionInterval(Math.max(colLead - 1, 0), |
418 |
{ |
Math.max(colLead - 1, 0)); |
|
colModel.setSelectionInterval(target, target); |
|
|
rowModel.setSelectionInterval(rowLead, rowLead); |
|
|
} |
|
|
else if (evt.getModifiers() == |
|
|
(InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK)) |
|
|
{ |
|
|
colModel.setLeadSelectionIndex(target); |
|
|
rowModel.setLeadSelectionIndex(rowLead); |
|
|
} |
|
|
} |
|
419 |
} |
} |
420 |
else if (evt.getKeyCode() == KeyEvent.VK_TAB |
else if (e.getActionCommand().equals("scrollLeftChangeSelection")) |
|
|| evt.getKeyCode() == KeyEvent.VK_ENTER) |
|
421 |
{ |
{ |
422 |
// If modifers other than SHIFT are pressed, do nothing |
int target; |
423 |
if (evt.getModifiers() != 0 && evt.getModifiers() != |
if (colLead == getFirstVisibleColumnIndex()) |
424 |
InputEvent.SHIFT_MASK) |
target = Math.max |
425 |
return; |
(0, colLead - (getLastVisibleColumnIndex() - |
426 |
|
getFirstVisibleColumnIndex() + 1)); |
427 |
|
else |
428 |
|
target = getFirstVisibleColumnIndex(); |
429 |
|
|
430 |
|
colModel.setSelectionInterval(target, target); |
431 |
|
rowModel.setSelectionInterval(rowLead, rowLead); |
432 |
|
} |
433 |
|
else if (e.getActionCommand().equals("clearSelection")) |
434 |
|
{ |
435 |
|
table.clearSelection(); |
436 |
|
} |
437 |
|
else if (e.getActionCommand().equals("cancel")) |
438 |
|
{ |
439 |
|
// FIXME: implement other parts of "cancel" like undo-ing last |
440 |
|
// selection. Right now it just calls editingCancelled if |
441 |
|
// we're currently editing. |
442 |
|
if (table.isEditing()) |
443 |
|
table.editingCanceled(new ChangeEvent("cancel")); |
444 |
|
} |
445 |
|
else if (e.getActionCommand().equals("selectNextRowCell") |
446 |
|
|| e.getActionCommand().equals("selectPreviousRowCell") |
447 |
|
|| e.getActionCommand().equals("selectNextColumnCell") |
448 |
|
|| e.getActionCommand().equals("selectPreviousColumnCell")) |
449 |
|
{ |
450 |
// If nothing is selected, select the first cell in the table |
// If nothing is selected, select the first cell in the table |
451 |
if (table.getSelectedRowCount() == 0 && |
if (table.getSelectedRowCount() == 0 && |
452 |
table.getSelectedColumnCount() == 0) |
table.getSelectedColumnCount() == 0) |
471 |
// multRowsSelected and multColsSelected tell us if multiple rows or |
// multRowsSelected and multColsSelected tell us if multiple rows or |
472 |
// columns are selected, respectively |
// columns are selected, respectively |
473 |
boolean multRowsSelected, multColsSelected; |
boolean multRowsSelected, multColsSelected; |
474 |
multRowsSelected = (table.getSelectedRowCount() > 1) || |
multRowsSelected = table.getSelectedRowCount() > 1 && |
475 |
(!table.getRowSelectionAllowed() && |
table.getRowSelectionAllowed(); |
476 |
table.getSelectedColumnCount() > 0); |
|
477 |
multColsSelected = (table.getSelectedColumnCount() > 1) || |
multColsSelected = table.getSelectedColumnCount() > 1 && |
478 |
(!table.getColumnSelectionAllowed() && |
table.getColumnSelectionAllowed(); |
|
table.getSelectedRowCount() > 0); |
|
479 |
|
|
480 |
// If there is just one selection, select the next cell, and wrap |
// If there is just one selection, select the next cell, and wrap |
481 |
// when you get to the edges of the table. |
// when you get to the edges of the table. |
482 |
if (!multColsSelected || !multRowsSelected) |
if (!multColsSelected && !multRowsSelected) |
483 |
{ |
{ |
484 |
if (evt.getKeyCode() == KeyEvent.VK_TAB) |
if (e.getActionCommand().indexOf("Column") != -1) |
485 |
advanceSingleSelection(colModel, colMax, rowModel, rowMax, |
advanceSingleSelection(colModel, colMax, rowModel, rowMax, |
486 |
(evt.getModifiers() == |
(e.getActionCommand().equals |
487 |
InputEvent.SHIFT_MASK)); |
("selectPreviousColumnCell"))); |
488 |
else |
else |
489 |
advanceSingleSelection(rowModel, rowMax, colModel, colMax, |
advanceSingleSelection(rowModel, rowMax, colModel, colMax, |
490 |
(evt.getModifiers() == |
(e.getActionCommand().equals |
491 |
InputEvent.SHIFT_MASK)); |
("selectPreviousRowCell"))); |
492 |
return; |
return; |
493 |
} |
} |
494 |
|
|
508 |
|
|
509 |
// If there are multiple rows and columns selected, select the next |
// If there are multiple rows and columns selected, select the next |
510 |
// cell and wrap at the edges of the selection. |
// cell and wrap at the edges of the selection. |
511 |
if (evt.getKeyCode() == KeyEvent.VK_TAB) |
if (e.getActionCommand().indexOf("Column") != -1) |
512 |
advanceMultipleSelection(colModel, colMinSelected, colMaxSelected, |
advanceMultipleSelection(colModel, colMinSelected, colMaxSelected, |
513 |
rowModel, rowMinSelected, rowMaxSelected, |
rowModel, rowMinSelected, rowMaxSelected, |
514 |
(evt.getModifiers() == |
(e.getActionCommand().equals |
515 |
InputEvent.SHIFT_MASK), true); |
("selectPreviousColumnCell")), true); |
516 |
|
|
517 |
else |
else |
518 |
advanceMultipleSelection(rowModel, rowMinSelected, rowMaxSelected, |
advanceMultipleSelection(rowModel, rowMinSelected, rowMaxSelected, |
519 |
colModel, colMinSelected, colMaxSelected, |
colModel, colMinSelected, colMaxSelected, |
520 |
(evt.getModifiers() == |
(e.getActionCommand().equals |
521 |
InputEvent.SHIFT_MASK), false); |
("selectPreviousRowCell")), false); |
522 |
|
|
523 |
table.repaint(); |
table.repaint(); |
524 |
} |
} |
525 |
else if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) |
else if (e.getActionCommand().equals("selectNextColumn")) |
526 |
|
{ |
527 |
|
rowModel.setSelectionInterval(rowLead,rowLead); |
528 |
|
colModel.setSelectionInterval(Math.min(colLead + 1, colMax), |
529 |
|
Math.min(colLead + 1, colMax)); |
530 |
|
} |
531 |
|
else if (e.getActionCommand().equals("scrollLeftExtendSelection")) |
532 |
|
{ |
533 |
|
int target; |
534 |
|
if (colLead == getFirstVisibleColumnIndex()) |
535 |
|
target = Math.max |
536 |
|
(0, colLead - (getLastVisibleColumnIndex() - |
537 |
|
getFirstVisibleColumnIndex() + 1)); |
538 |
|
else |
539 |
|
target = getFirstVisibleColumnIndex(); |
540 |
|
|
541 |
|
colModel.setLeadSelectionIndex(target); |
542 |
|
rowModel.setLeadSelectionIndex(rowLead); |
543 |
|
} |
544 |
|
else if (e.getActionCommand().equals("scrollDownChangeSelection")) |
545 |
|
{ |
546 |
|
int target; |
547 |
|
if (rowLead == getLastVisibleRowIndex()) |
548 |
|
target = Math.min |
549 |
|
(rowMax, rowLead + (getLastVisibleRowIndex() - |
550 |
|
getFirstVisibleRowIndex() + 1)); |
551 |
|
else |
552 |
|
target = getLastVisibleRowIndex(); |
553 |
|
|
554 |
|
rowModel.setSelectionInterval(target, target); |
555 |
|
colModel.setSelectionInterval(colLead, colLead); |
556 |
|
} |
557 |
|
else if (e.getActionCommand().equals("scrollRightExtendSelection")) |
558 |
{ |
{ |
559 |
// FIXME: implement "cancel" |
int target; |
560 |
|
if (colLead == getLastVisibleColumnIndex()) |
561 |
|
target = Math.min |
562 |
|
(colMax, colLead + (getLastVisibleColumnIndex() - |
563 |
|
getFirstVisibleColumnIndex() + 1)); |
564 |
|
else |
565 |
|
target = getLastVisibleColumnIndex(); |
566 |
|
|
567 |
|
colModel.setLeadSelectionIndex(target); |
568 |
|
rowModel.setLeadSelectionIndex(rowLead); |
569 |
} |
} |
570 |
else if ((evt.getKeyCode() == KeyEvent.VK_A || evt.getKeyCode() |
else if (e.getActionCommand().equals("selectAll")) |
|
== KeyEvent.VK_SLASH) && (evt.getModifiers() == |
|
|
InputEvent.CTRL_MASK)) |
|
571 |
{ |
{ |
572 |
table.selectAll(); |
table.selectAll(); |
573 |
} |
} |
574 |
else if (evt.getKeyCode() == KeyEvent.VK_BACK_SLASH |
else if (e.getActionCommand().equals("selectLastRowExtendSelection")) |
|
&& (evt.getModifiers() == InputEvent.CTRL_MASK)) |
|
575 |
{ |
{ |
576 |
table.clearSelection(); |
rowModel.setLeadSelectionIndex(rowMax); |
577 |
|
colModel.setLeadSelectionIndex(colLead); |
578 |
} |
} |
579 |
else if (evt.getKeyCode() == KeyEvent.VK_SPACE |
else if (e.getActionCommand().equals("scrollDownExtendSelection")) |
|
&& (evt.getModifiers() == InputEvent.CTRL_MASK)) |
|
580 |
{ |
{ |
581 |
table.changeSelection(rowLead, colLead, true, false); |
int target; |
582 |
|
if (rowLead == getLastVisibleRowIndex()) |
583 |
|
target = Math.min |
584 |
|
(rowMax, rowLead + (getLastVisibleRowIndex() - |
585 |
|
getFirstVisibleRowIndex() + 1)); |
586 |
|
else |
587 |
|
target = getLastVisibleRowIndex(); |
588 |
|
|
589 |
|
rowModel.setLeadSelectionIndex(target); |
590 |
|
colModel.setLeadSelectionIndex(colLead); |
591 |
} |
} |
592 |
|
else if (e.getActionCommand().equals("scrollUpChangeSelection")) |
593 |
|
{ |
594 |
|
int target; |
595 |
|
if (rowLead == getFirstVisibleRowIndex()) |
596 |
|
target = Math.max |
597 |
|
(0, rowLead - (getLastVisibleRowIndex() - |
598 |
|
getFirstVisibleRowIndex() + 1)); |
599 |
|
else |
600 |
|
target = getFirstVisibleRowIndex(); |
601 |
|
|
602 |
|
rowModel.setSelectionInterval(target, target); |
603 |
|
colModel.setSelectionInterval(colLead, colLead); |
604 |
|
} |
605 |
|
else |
606 |
|
{ |
607 |
|
// If we're here that means we bound this TableAction class |
608 |
|
// to a keyboard input but we either want to ignore that input |
609 |
|
// or we just haven't implemented its action yet. |
610 |
|
} |
611 |
|
|
612 |
table.scrollRectToVisible |
table.scrollRectToVisible |
613 |
(table.getCellRect(rowModel.getLeadSelectionIndex(), |
(table.getCellRect(rowModel.getLeadSelectionIndex(), |
614 |
colModel.getLeadSelectionIndex(), false)); |
colModel.getLeadSelectionIndex(), false)); |
615 |
} |
} |
616 |
|
|
|
public void keyReleased(KeyEvent e) |
|
|
{ |
|
|
} |
|
|
|
|
|
public void keyTyped(KeyEvent e) |
|
|
{ |
|
|
} |
|
|
|
|
|
/** |
|
|
* Returns the column index of the first visible column. |
|
|
* |
|
|
*/ |
|
617 |
int getFirstVisibleColumnIndex() |
int getFirstVisibleColumnIndex() |
618 |
{ |
{ |
619 |
ComponentOrientation or = table.getComponentOrientation(); |
ComponentOrientation or = table.getComponentOrientation(); |
672 |
} |
} |
673 |
return table.rowAtPoint(r.getLocation()); |
return table.rowAtPoint(r.getLocation()); |
674 |
} |
} |
|
} |
|
675 |
|
|
676 |
class MouseInputHandler implements MouseInputListener |
/** |
677 |
{ |
* A helper method for the key bindings. Used because the actions |
678 |
Point begin, curr; |
* for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar. |
679 |
|
* |
680 |
private void updateSelection(boolean controlPressed) |
* Selects the next (previous if SHIFT pressed) column for TAB, or row for |
681 |
|
* ENTER from within the currently selected cells. |
682 |
|
* |
683 |
|
* @param firstModel the ListSelectionModel for columns (TAB) or |
684 |
|
* rows (ENTER) |
685 |
|
* @param firstMin the first selected index in firstModel |
686 |
|
* @param firstMax the last selected index in firstModel |
687 |
|
* @param secondModel the ListSelectionModel for rows (TAB) or |
688 |
|
* columns (ENTER) |
689 |
|
* @param secondMin the first selected index in secondModel |
690 |
|
* @param secondMax the last selected index in secondModel |
691 |
|
* @param reverse true if shift was held for the event |
692 |
|
* @param eventIsTab true if TAB was pressed, false if ENTER pressed |
693 |
|
*/ |
694 |
|
void advanceMultipleSelection (ListSelectionModel firstModel, int firstMin, |
695 |
|
int firstMax, ListSelectionModel secondModel, |
696 |
|
int secondMin, int secondMax, boolean reverse, |
697 |
|
boolean eventIsTab) |
698 |
{ |
{ |
699 |
// Update the rows |
// If eventIsTab, all the "firsts" correspond to columns, otherwise, to rows |
700 |
int lo_row = table.rowAtPoint(begin); |
// "seconds" correspond to the opposite |
701 |
int hi_row = table.rowAtPoint(curr); |
int firstLead = firstModel.getLeadSelectionIndex(); |
702 |
ListSelectionModel rowModel = table.getSelectionModel(); |
int secondLead = secondModel.getLeadSelectionIndex(); |
703 |
if (lo_row != -1 && hi_row != -1) |
int numFirsts = eventIsTab ? |
704 |
|
table.getModel().getColumnCount() : table.getModel().getRowCount(); |
705 |
|
int numSeconds = eventIsTab ? |
706 |
|
table.getModel().getRowCount() : table.getModel().getColumnCount(); |
707 |
|
|
708 |
|
// check if we have to wrap the "firsts" around, going to the other side |
709 |
|
if ((firstLead == firstMax && !reverse) || |
710 |
|
(reverse && firstLead == firstMin)) |
711 |
{ |
{ |
712 |
if (controlPressed && rowModel.getSelectionMode() |
firstModel.addSelectionInterval(reverse ? firstMax : firstMin, |
713 |
!= ListSelectionModel.SINGLE_SELECTION) |
reverse ? firstMax : firstMin); |
714 |
rowModel.addSelectionInterval(lo_row, hi_row); |
|
715 |
|
// check if we have to wrap the "seconds" |
716 |
|
if ((secondLead == secondMax && !reverse) || |
717 |
|
(reverse && secondLead == secondMin)) |
718 |
|
secondModel.addSelectionInterval(reverse ? secondMax : secondMin, |
719 |
|
reverse ? secondMax : secondMin); |
720 |
|
|
721 |
|
// if we're not wrapping the seconds, we have to find out where we |
722 |
|
// are within the secondModel and advance to the next cell (or |
723 |
|
// go back to the previous cell if reverse == true) |
724 |
else |
else |
725 |
rowModel.setSelectionInterval(lo_row, hi_row); |
{ |
726 |
|
int[] secondsSelected; |
727 |
|
if (eventIsTab && table.getRowSelectionAllowed() || |
728 |
|
!eventIsTab && table.getColumnSelectionAllowed()) |
729 |
|
secondsSelected = eventIsTab ? |
730 |
|
table.getSelectedRows() : table.getSelectedColumns(); |
731 |
|
else |
732 |
|
{ |
733 |
|
// if row selection is not allowed, then the entire column gets |
734 |
|
// selected when you click on it, so consider ALL rows selected |
735 |
|
secondsSelected = new int[numSeconds]; |
736 |
|
for (int i = 0; i < numSeconds; i++) |
737 |
|
secondsSelected[i] = i; |
738 |
|
} |
739 |
|
|
740 |
|
// and now find the "next" index within the model |
741 |
|
int secondIndex = reverse ? secondsSelected.length - 1 : 0; |
742 |
|
if (!reverse) |
743 |
|
while (secondsSelected[secondIndex] <= secondLead) |
744 |
|
secondIndex++; |
745 |
|
else |
746 |
|
while (secondsSelected[secondIndex] >= secondLead) |
747 |
|
secondIndex--; |
748 |
|
|
749 |
|
// and select it - updating the lead selection index |
750 |
|
secondModel.addSelectionInterval(secondsSelected[secondIndex], |
751 |
|
secondsSelected[secondIndex]); |
752 |
|
} |
753 |
} |
} |
754 |
|
// We didn't have to wrap the firsts, so just find the "next" first |
755 |
// Update the columns |
// and select it, we don't have to change "seconds" |
756 |
int lo_col = table.columnAtPoint(begin); |
else |
|
int hi_col = table.columnAtPoint(curr); |
|
|
ListSelectionModel colModel = table.getColumnModel(). |
|
|
getSelectionModel(); |
|
|
if (lo_col != -1 && hi_col != -1) |
|
757 |
{ |
{ |
758 |
if (controlPressed && colModel.getSelectionMode() != |
int[] firstsSelected; |
759 |
ListSelectionModel.SINGLE_SELECTION) |
if (eventIsTab && table.getColumnSelectionAllowed() || |
760 |
colModel.addSelectionInterval(lo_col, hi_col); |
!eventIsTab && table.getRowSelectionAllowed()) |
761 |
|
firstsSelected = eventIsTab ? |
762 |
|
table.getSelectedColumns() : table.getSelectedRows(); |
763 |
else |
else |
764 |
colModel.setSelectionInterval(lo_col, hi_col); |
{ |
765 |
|
// if selection not allowed, consider ALL firsts to be selected |
766 |
|
firstsSelected = new int[numFirsts]; |
767 |
|
for (int i = 0; i < numFirsts; i++) |
768 |
|
firstsSelected[i] = i; |
769 |
|
} |
770 |
|
int firstIndex = reverse ? firstsSelected.length - 1 : 0; |
771 |
|
if (!reverse) |
772 |
|
while (firstsSelected[firstIndex] <= firstLead) |
773 |
|
firstIndex++; |
774 |
|
else |
775 |
|
while (firstsSelected[firstIndex] >= firstLead) |
776 |
|
firstIndex--; |
777 |
|
firstModel.addSelectionInterval(firstsSelected[firstIndex], |
778 |
|
firstsSelected[firstIndex]); |
779 |
|
secondModel.addSelectionInterval(secondLead, secondLead); |
780 |
} |
} |
781 |
} |
} |
782 |
|
|
783 |
|
/** |
784 |
|
* A helper method for the key bindings. Used because the actions |
785 |
|
* for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar. |
786 |
|
* |
787 |
|
* Selects the next (previous if SHIFT pressed) column (TAB) or row (ENTER) |
788 |
|
* in the table, changing the current selection. All cells in the table |
789 |
|
* are eligible, not just the ones that are currently selected. |
790 |
|
* @param firstModel the ListSelectionModel for columns (TAB) or rows |
791 |
|
* (ENTER) |
792 |
|
* @param firstMax the last index in firstModel |
793 |
|
* @param secondModel the ListSelectionModel for rows (TAB) or columns |
794 |
|
* (ENTER) |
795 |
|
* @param secondMax the last index in secondModel |
796 |
|
* @param reverse true if SHIFT was pressed for the event |
797 |
|
*/ |
798 |
|
|
799 |
public void mouseClicked(MouseEvent e) |
void advanceSingleSelection (ListSelectionModel firstModel, int firstMax, |
800 |
{ |
ListSelectionModel secondModel, int secondMax, |
801 |
} |
boolean reverse) |
|
public void mouseDragged(MouseEvent e) |
|
|
{ |
|
|
curr = new Point(e.getX(), e.getY()); |
|
|
updateSelection(e.isControlDown()); |
|
|
} |
|
|
public void mouseEntered(MouseEvent e) |
|
|
{ |
|
|
} |
|
|
public void mouseExited(MouseEvent e) |
|
|
{ |
|
|
} |
|
|
public void mouseMoved(MouseEvent e) |
|
|
{ |
|
|
} |
|
|
public void mousePressed(MouseEvent e) |
|
802 |
{ |
{ |
803 |
ListSelectionModel rowModel = table.getSelectionModel(); |
// for TABs, "first" corresponds to columns and "seconds" to rows. |
804 |
ListSelectionModel colModel = table.getColumnModel().getSelectionModel(); |
// the opposite is true for ENTERs |
805 |
int rowLead = rowModel.getLeadSelectionIndex(); |
int firstLead = firstModel.getLeadSelectionIndex(); |
806 |
int colLead = colModel.getLeadSelectionIndex(); |
int secondLead = secondModel.getLeadSelectionIndex(); |
807 |
|
|
808 |
begin = new Point(e.getX(), e.getY()); |
// if we are going backwards subtract 2 because we later add 1 |
809 |
curr = new Point(e.getX(), e.getY()); |
// for a net change of -1 |
810 |
//if control is pressed and the cell is already selected, deselect it |
if (reverse && (firstLead == 0)) |
811 |
if (e.isControlDown() && table. |
{ |
812 |
isCellSelected(table.rowAtPoint(begin),table.columnAtPoint(begin))) |
// check if we have to wrap around |
813 |
{ |
if (secondLead == 0) |
814 |
table.getSelectionModel(). |
secondLead += secondMax + 1; |
815 |
removeSelectionInterval(table.rowAtPoint(begin), |
secondLead -= 2; |
|
table.rowAtPoint(begin)); |
|
|
table.getColumnModel().getSelectionModel(). |
|
|
removeSelectionInterval(table.columnAtPoint(begin), |
|
|
table.columnAtPoint(begin)); |
|
816 |
} |
} |
817 |
|
|
818 |
|
// do we have to wrap the "seconds"? |
819 |
|
if (reverse && (firstLead == 0) || !reverse && (firstLead == firstMax)) |
820 |
|
secondModel.setSelectionInterval((secondLead + 1)%(secondMax + 1), |
821 |
|
(secondLead + 1)%(secondMax + 1)); |
822 |
|
// if not, just reselect the current lead |
823 |
else |
else |
824 |
updateSelection(e.isControlDown()); |
secondModel.setSelectionInterval(secondLead, secondLead); |
825 |
|
|
826 |
// If we were editing, but the moved to another cell, stop editing |
// if we are going backwards, subtract 2 because we add 1 later |
827 |
if (rowLead != rowModel.getLeadSelectionIndex() || |
// for net change of -1 |
828 |
colLead != colModel.getLeadSelectionIndex()) |
if (reverse) |
829 |
if (table.isEditing()) |
{ |
830 |
table.editingStopped(new ChangeEvent(e)); |
// check for wraparound |
831 |
} |
if (firstLead == 0) |
832 |
public void mouseReleased(MouseEvent e) |
firstLead += firstMax + 1; |
833 |
{ |
firstLead -= 2; |
834 |
begin = null; |
} |
835 |
curr = null; |
// select the next "first" |
836 |
|
firstModel.setSelectionInterval ((firstLead + 1)%(firstMax + 1), |
837 |
|
(firstLead + 1)%(firstMax + 1)); |
838 |
} |
} |
839 |
} |
} |
840 |
|
|
|
protected FocusListener createFocusListener() |
|
|
{ |
|
|
return new FocusHandler(); |
|
|
} |
|
|
protected KeyListener createKeyListener() |
|
|
{ |
|
|
return new KeyHandler(); |
|
|
} |
|
|
protected MouseInputListener createMouseInputListener() |
|
|
{ |
|
|
return new MouseInputHandler(); |
|
|
} |
|
|
|
|
|
public Dimension getMaximumSize(JComponent comp) |
|
|
{ |
|
|
return getPreferredSize(comp); |
|
|
} |
|
|
|
|
|
public Dimension getMinimumSize(JComponent comp) |
|
|
{ |
|
|
return getPreferredSize(comp); |
|
|
} |
|
|
|
|
|
public Dimension getPreferredSize(JComponent comp) |
|
|
{ |
|
|
int width = table.getColumnModel().getTotalColumnWidth(); |
|
|
int height = table.getRowCount() * table.getRowHeight(); |
|
|
return new Dimension(width, height); |
|
|
} |
|
|
|
|
|
protected void installDefaults() |
|
|
{ |
|
|
UIDefaults defaults = UIManager.getLookAndFeelDefaults(); |
|
|
table.setFont(defaults.getFont("Table.font")); |
|
|
table.setGridColor(defaults.getColor("Table.gridColor")); |
|
|
table.setForeground(defaults.getColor("Table.foreground")); |
|
|
table.setBackground(defaults.getColor("Table.background")); |
|
|
table.setSelectionForeground(defaults.getColor("Table.selectionForeground")); |
|
|
table.setSelectionBackground(defaults.getColor("Table.selectionBackground")); |
|
|
table.setOpaque(true); |
|
|
|
|
|
highlightCellBorder = defaults.getBorder("Table.focusCellHighlightBorder"); |
|
|
cellBorder = BorderFactory.createEmptyBorder(1, 1, 1, 1); |
|
|
} |
|
|
protected void installKeyboardActions() |
|
|
{ |
|
|
} |
|
|
|
|
841 |
protected void installListeners() |
protected void installListeners() |
842 |
{ |
{ |
843 |
table.addFocusListener(focusListener); |
table.addFocusListener(focusListener); |
882 |
{ |
{ |
883 |
table = (JTable)comp; |
table = (JTable)comp; |
884 |
focusListener = createFocusListener(); |
focusListener = createFocusListener(); |
|
keyListener = createKeyListener(); |
|
885 |
mouseInputListener = createMouseInputListener(); |
mouseInputListener = createMouseInputListener(); |
886 |
installDefaults(); |
installDefaults(); |
887 |
installKeyboardActions(); |
installKeyboardActions(); |