KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > basic > BasicTableUI


1 /*
2  * @(#)BasicTableUI.java 1.148 06/04/18
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.plaf.basic;
9
10 import java.awt.*;
11 import java.awt.datatransfer.*;
12 import java.awt.dnd.*;
13 import java.awt.event.*;
14 import java.util.Enumeration JavaDoc;
15 import java.util.EventObject JavaDoc;
16 import java.util.Hashtable JavaDoc;
17 import java.util.TooManyListenersException JavaDoc;
18 import javax.swing.*;
19 import javax.swing.event.*;
20 import javax.swing.plaf.*;
21 import javax.swing.text.*;
22 import javax.swing.table.*;
23 import javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag JavaDoc;
24 import com.sun.java.swing.SwingUtilities2;
25 import static com.sun.java.swing.SwingUtilities2.DRAG_FIX;
26
27
28 import java.beans.PropertyChangeEvent JavaDoc;
29 import java.beans.PropertyChangeListener JavaDoc;
30
31 import sun.swing.DefaultLookup;
32 import sun.swing.UIAction;
33
34 /**
35  * BasicTableUI implementation
36  *
37  * @version 1.148 04/18/06
38  * @author Philip Milne
39  * @author Shannon Hickey (improved drag recognition)
40  */

41 public class BasicTableUI extends TableUI
42 {
43
44 //
45
// Instance Variables
46
//
47

48     // The JTable that is delegating the painting to this UI.
49
protected JTable table;
50     protected CellRendererPane rendererPane;
51
52     // Listeners that are attached to the JTable
53
protected KeyListener keyListener;
54     protected FocusListener focusListener;
55     protected MouseInputListener mouseInputListener;
56
57     private Handler handler;
58
59     /**
60      * Local cache of Table's client property "Table.isFileList"
61      */

62     private boolean isFileList = false;
63
64 //
65
// Helper class for keyboard actions
66
//
67

68     private static class Actions extends UIAction {
69         private static final String JavaDoc CANCEL_EDITING = "cancel";
70         private static final String JavaDoc SELECT_ALL = "selectAll";
71         private static final String JavaDoc CLEAR_SELECTION = "clearSelection";
72         private static final String JavaDoc START_EDITING = "startEditing";
73
74         private static final String JavaDoc NEXT_ROW = "selectNextRow";
75         private static final String JavaDoc NEXT_ROW_CELL = "selectNextRowCell";
76     private static final String JavaDoc NEXT_ROW_EXTEND_SELECTION =
77                 "selectNextRowExtendSelection";
78         private static final String JavaDoc NEXT_ROW_CHANGE_LEAD =
79                 "selectNextRowChangeLead";
80         private static final String JavaDoc PREVIOUS_ROW = "selectPreviousRow";
81         private static final String JavaDoc PREVIOUS_ROW_CELL = "selectPreviousRowCell";
82     private static final String JavaDoc PREVIOUS_ROW_EXTEND_SELECTION =
83                 "selectPreviousRowExtendSelection";
84         private static final String JavaDoc PREVIOUS_ROW_CHANGE_LEAD =
85                 "selectPreviousRowChangeLead";
86
87         private static final String JavaDoc NEXT_COLUMN = "selectNextColumn";
88         private static final String JavaDoc NEXT_COLUMN_CELL = "selectNextColumnCell";
89     private static final String JavaDoc NEXT_COLUMN_EXTEND_SELECTION =
90                 "selectNextColumnExtendSelection";
91         private static final String JavaDoc NEXT_COLUMN_CHANGE_LEAD =
92                 "selectNextColumnChangeLead";
93         private static final String JavaDoc PREVIOUS_COLUMN = "selectPreviousColumn";
94         private static final String JavaDoc PREVIOUS_COLUMN_CELL =
95                 "selectPreviousColumnCell";
96     private static final String JavaDoc PREVIOUS_COLUMN_EXTEND_SELECTION =
97                 "selectPreviousColumnExtendSelection";
98         private static final String JavaDoc PREVIOUS_COLUMN_CHANGE_LEAD =
99                 "selectPreviousColumnChangeLead";
100
101         private static final String JavaDoc SCROLL_LEFT_CHANGE_SELECTION =
102                 "scrollLeftChangeSelection";
103         private static final String JavaDoc SCROLL_LEFT_EXTEND_SELECTION =
104                 "scrollLeftExtendSelection";
105         private static final String JavaDoc SCROLL_RIGHT_CHANGE_SELECTION =
106                 "scrollRightChangeSelection";
107         private static final String JavaDoc SCROLL_RIGHT_EXTEND_SELECTION =
108                 "scrollRightExtendSelection";
109
110     private static final String JavaDoc SCROLL_UP_CHANGE_SELECTION =
111                 "scrollUpChangeSelection";
112         private static final String JavaDoc SCROLL_UP_EXTEND_SELECTION =
113                 "scrollUpExtendSelection";
114         private static final String JavaDoc SCROLL_DOWN_CHANGE_SELECTION =
115                 "scrollDownChangeSelection";
116         private static final String JavaDoc SCROLL_DOWN_EXTEND_SELECTION =
117                 "scrollDownExtendSelection";
118
119         private static final String JavaDoc FIRST_COLUMN =
120                 "selectFirstColumn";
121         private static final String JavaDoc FIRST_COLUMN_EXTEND_SELECTION =
122                 "selectFirstColumnExtendSelection";
123         private static final String JavaDoc LAST_COLUMN =
124                 "selectLastColumn";
125         private static final String JavaDoc LAST_COLUMN_EXTEND_SELECTION =
126                 "selectLastColumnExtendSelection";
127
128         private static final String JavaDoc FIRST_ROW =
129                 "selectFirstRow";
130         private static final String JavaDoc FIRST_ROW_EXTEND_SELECTION =
131                 "selectFirstRowExtendSelection";
132         private static final String JavaDoc LAST_ROW =
133                 "selectLastRow";
134         private static final String JavaDoc LAST_ROW_EXTEND_SELECTION =
135                 "selectLastRowExtendSelection";
136
137         // add the lead item to the selection without changing lead or anchor
138
private static final String JavaDoc ADD_TO_SELECTION = "addToSelection";
139
140         // toggle the selected state of the lead item and move the anchor to it
141
private static final String JavaDoc TOGGLE_AND_ANCHOR = "toggleAndAnchor";
142
143         // extend the selection to the lead item
144
private static final String JavaDoc EXTEND_TO = "extendTo";
145
146         // move the anchor to the lead and ensure only that item is selected
147
private static final String JavaDoc MOVE_SELECTION_TO = "moveSelectionTo";
148
149         protected int dx;
150         protected int dy;
151     protected boolean extend;
152     protected boolean inSelection;
153         protected boolean forwards;
154         protected boolean vertically;
155         protected boolean toLimit;
156
157     protected int leadRow;
158     protected int leadColumn;
159
160         Actions(String JavaDoc name) {
161             super(name);
162         }
163
164         Actions(String JavaDoc name, int dx, int dy, boolean extend,
165                 boolean inSelection) {
166             super(name);
167
168             // Actions spcifying true for "inSelection" are
169
// fairly sensitive to bad parameter values. They require
170
// that one of dx and dy be 0 and the other be -1 or 1.
171
// Bogus parameter values could cause an infinite loop.
172
// To prevent any problems we massage the params here
173
// and complain if we get something we can't deal with.
174
if (inSelection) {
175                 this.inSelection = true;
176
177                 // look at the sign of dx and dy only
178
dx = sign(dx);
179                 dy = sign(dy);
180
181                 // make sure one is zero, but not both
182
assert (dx == 0 || dy == 0) && !(dx == 0 && dy == 0);
183             }
184
185             this.dx = dx;
186             this.dy = dy;
187             this.extend = extend;
188         }
189
190         Actions(String JavaDoc name, boolean extend, boolean forwards,
191                 boolean vertically, boolean toLimit) {
192             this(name, 0, 0, extend, false);
193             this.forwards = forwards;
194             this.vertically = vertically;
195             this.toLimit = toLimit;
196         }
197
198     private static int clipToRange(int i, int a, int b) {
199         return Math.min(Math.max(i, a), b-1);
200     }
201
202     private void moveWithinTableRange(JTable table, int dx, int dy) {
203             leadRow = clipToRange(leadRow+dy, 0, table.getRowCount());
204             leadColumn = clipToRange(leadColumn+dx, 0, table.getColumnCount());
205     }
206
207         private static int sign(int num) {
208             return (num < 0) ? -1 : ((num == 0) ? 0 : 1);
209         }
210
211         /**
212          * Called to move within the selected range of the given JTable.
213          * This method uses the table's notion of selection, which is
214          * important to allow the user to navigate between items visually
215          * selected on screen. This notion may or may not be the same as
216          * what could be determined by directly querying the selection models.
217          * It depends on certain table properties (such as whether or not
218          * row or column selection is allowed). When performing modifications,
219          * it is recommended that caution be taken in order to preserve
220          * the intent of this method, especially when deciding whether to
221          * query the selection models or interact with JTable directly.
222          */

223     private boolean moveWithinSelectedRange(JTable table, int dx, int dy,
224                 ListSelectionModel rsm, ListSelectionModel csm) {
225
226             // Note: The Actions constructor ensures that only one of
227
// dx and dy is 0, and the other is either -1 or 1
228

229             // find out how many items the table is showing as selected
230
// and the range of items to navigate through
231
int totalCount;
232             int minX, maxX, minY, maxY;
233
234             boolean rs = table.getRowSelectionAllowed();
235             boolean cs = table.getColumnSelectionAllowed();
236
237             // both column and row selection
238
if (rs && cs) {
239                 totalCount = table.getSelectedRowCount() * table.getSelectedColumnCount();
240                 minX = csm.getMinSelectionIndex();
241                 maxX = csm.getMaxSelectionIndex();
242                 minY = rsm.getMinSelectionIndex();
243                 maxY = rsm.getMaxSelectionIndex();
244             // row selection only
245
} else if (rs) {
246                 totalCount = table.getSelectedRowCount();
247                 minX = 0;
248                 maxX = table.getColumnCount() - 1;
249                 minY = rsm.getMinSelectionIndex();
250                 maxY = rsm.getMaxSelectionIndex();
251             // column selection only
252
} else if (cs) {
253                 totalCount = table.getSelectedColumnCount();
254                 minX = csm.getMinSelectionIndex();
255                 maxX = csm.getMaxSelectionIndex();
256                 minY = 0;
257                 maxY = table.getRowCount() - 1;
258             // no selection allowed
259
} else {
260                 totalCount = 0;
261                 // A bogus assignment to stop javac from complaining
262
// about unitialized values. In this case, these
263
// won't even be used.
264
minX = maxX = minY = maxY = 0;
265             }
266
267             // For some cases, there is no point in trying to stay within the
268
// selected area. Instead, move outside the selection, wrapping at
269
// the table boundaries. The cases are:
270
boolean stayInSelection;
271
272             // - nothing selected
273
if (totalCount == 0 ||
274                     // - one item selected, and the lead is already selected
275
(totalCount == 1 && table.isCellSelected(leadRow, leadColumn))) {
276
277                 stayInSelection = false;
278
279                 maxX = table.getColumnCount() - 1;
280                 maxY = table.getRowCount() - 1;
281
282                 // the mins are calculated like this in case the max is -1
283
minX = Math.min(0, maxX);
284                 minY = Math.min(0, maxY);
285             } else {
286                 stayInSelection = true;
287             }
288
289             // the algorithm below isn't prepared to deal with -1 lead/anchor
290
// so massage appropriately here first
291
if (dy == 1 && leadColumn == -1) {
292                 leadColumn = minX;
293                 leadRow = -1;
294             } else if (dx == 1 && leadRow == -1) {
295                 leadRow = minY;
296                 leadColumn = -1;
297             } else if (dy == -1 && leadColumn == -1) {
298                 leadColumn = maxX;
299                 leadRow = maxY + 1;
300             } else if (dx == -1 && leadRow == -1) {
301                 leadRow = maxY;
302                 leadColumn = maxX + 1;
303             }
304
305             // In cases where the lead is not within the search range,
306
// we need to bring it within one cell for the the search
307
// to work properly. Check these here.
308
leadRow = Math.min(Math.max(leadRow, minY - 1), maxY + 1);
309             leadColumn = Math.min(Math.max(leadColumn, minX - 1), maxX + 1);
310
311             // find the next position, possibly looping until it is selected
312
do {
313                 calcNextPos(dx, minX, maxX, dy, minY, maxY);
314             } while (stayInSelection && !table.isCellSelected(leadRow, leadColumn));
315
316             return stayInSelection;
317     }
318
319         /**
320          * Find the next lead row and column based on the given
321          * dx/dy and max/min values.
322          */

323         private void calcNextPos(int dx, int minX, int maxX,
324                                  int dy, int minY, int maxY) {
325
326             if (dx != 0) {
327                 leadColumn += dx;
328                 if (leadColumn > maxX) {
329                     leadColumn = minX;
330                     leadRow++;
331                     if (leadRow > maxY) {
332                         leadRow = minY;
333                     }
334                 } else if (leadColumn < minX) {
335                     leadColumn = maxX;
336                     leadRow--;
337                     if (leadRow < minY) {
338                         leadRow = maxY;
339                     }
340                 }
341             } else {
342                 leadRow += dy;
343                 if (leadRow > maxY) {
344                     leadRow = minY;
345                     leadColumn++;
346                     if (leadColumn > maxX) {
347                         leadColumn = minX;
348                     }
349                 } else if (leadRow < minY) {
350                     leadRow = maxY;
351                     leadColumn--;
352                     if (leadColumn < minX) {
353                         leadColumn = maxX;
354                     }
355                 }
356             }
357         }
358
359         public void actionPerformed(ActionEvent e) {
360             String JavaDoc key = getName();
361             JTable table = (JTable)e.getSource();
362
363             ListSelectionModel rsm = table.getSelectionModel();
364             leadRow = getAdjustedLead(table, true, rsm);
365
366             ListSelectionModel csm = table.getColumnModel().getSelectionModel();
367             leadColumn = getAdjustedLead(table, false, csm);
368
369             if (!table.getComponentOrientation().isLeftToRight()) {
370                 if (key == SCROLL_LEFT_CHANGE_SELECTION ||
371                         key == SCROLL_LEFT_EXTEND_SELECTION) {
372                     forwards = true;
373                 } else if (key == SCROLL_RIGHT_CHANGE_SELECTION ||
374                         key == SCROLL_RIGHT_EXTEND_SELECTION) {
375                     forwards = false;
376                 }
377             }
378
379             if (key == SCROLL_LEFT_CHANGE_SELECTION || // Paging Actions
380
key == SCROLL_LEFT_EXTEND_SELECTION ||
381                     key == SCROLL_RIGHT_CHANGE_SELECTION ||
382                     key == SCROLL_RIGHT_EXTEND_SELECTION ||
383                 key == SCROLL_UP_CHANGE_SELECTION ||
384                     key == SCROLL_UP_EXTEND_SELECTION ||
385                     key == SCROLL_DOWN_CHANGE_SELECTION ||
386                     key == SCROLL_DOWN_EXTEND_SELECTION ||
387                     key == FIRST_COLUMN ||
388                     key == FIRST_COLUMN_EXTEND_SELECTION ||
389                     key == FIRST_ROW ||
390                     key == FIRST_ROW_EXTEND_SELECTION ||
391                     key == LAST_COLUMN ||
392                     key == LAST_COLUMN_EXTEND_SELECTION ||
393                     key == LAST_ROW ||
394                     key == LAST_ROW_EXTEND_SELECTION) {
395                 if (toLimit) {
396                     if (vertically) {
397                         int rowCount = table.getRowCount();
398                         this.dx = 0;
399                         this.dy = forwards ? rowCount : -rowCount;
400                     }
401                     else {
402                         int colCount = table.getColumnCount();
403                         this.dx = forwards ? colCount : -colCount;
404                         this.dy = 0;
405                     }
406                 }
407                 else {
408                     if (!(table.getParent().getParent() instanceof
409                             JScrollPane)) {
410                         return;
411                     }
412     
413                     Dimension delta = table.getParent().getSize();
414
415                     if (vertically) {
416                         Rectangle r = table.getCellRect(leadRow, 0, true);
417                         r.y += forwards ? delta.height : -delta.height;
418                         this.dx = 0;
419                         int newRow = table.rowAtPoint(r.getLocation());
420                         if (newRow == -1 && forwards) {
421                             newRow = table.getRowCount();
422                         }
423                         this.dy = newRow - leadRow;
424                     }
425                     else {
426                         Rectangle r = table.getCellRect(0, leadColumn, true);
427                         r.x += forwards ? delta.width : -delta.width;
428                         int newColumn = table.columnAtPoint(r.getLocation());
429                         if (newColumn == -1 && forwards) {
430                             newColumn = table.getColumnCount();
431                         }
432                         this.dx = newColumn - leadColumn;
433                         this.dy = 0;
434                     }
435                 }
436             }
437             if (key == NEXT_ROW || // Navigate Actions
438
key == NEXT_ROW_CELL ||
439                     key == NEXT_ROW_EXTEND_SELECTION ||
440                     key == NEXT_ROW_CHANGE_LEAD ||
441                     key == NEXT_COLUMN ||
442                     key == NEXT_COLUMN_CELL ||
443                     key == NEXT_COLUMN_EXTEND_SELECTION ||
444                     key == NEXT_COLUMN_CHANGE_LEAD ||
445                     key == PREVIOUS_ROW ||
446                     key == PREVIOUS_ROW_CELL ||
447                     key == PREVIOUS_ROW_EXTEND_SELECTION ||
448                     key == PREVIOUS_ROW_CHANGE_LEAD ||
449                     key == PREVIOUS_COLUMN ||
450                     key == PREVIOUS_COLUMN_CELL ||
451                     key == PREVIOUS_COLUMN_EXTEND_SELECTION ||
452                     key == PREVIOUS_COLUMN_CHANGE_LEAD ||
453                     // Paging Actions.
454
key == SCROLL_LEFT_CHANGE_SELECTION ||
455                     key == SCROLL_LEFT_EXTEND_SELECTION ||
456                     key == SCROLL_RIGHT_CHANGE_SELECTION ||
457                     key == SCROLL_RIGHT_EXTEND_SELECTION ||
458                 key == SCROLL_UP_CHANGE_SELECTION ||
459                     key == SCROLL_UP_EXTEND_SELECTION ||
460                     key == SCROLL_DOWN_CHANGE_SELECTION ||
461                     key == SCROLL_DOWN_EXTEND_SELECTION ||
462                     key == FIRST_COLUMN ||
463                     key == FIRST_COLUMN_EXTEND_SELECTION ||
464                     key == FIRST_ROW ||
465                     key == FIRST_ROW_EXTEND_SELECTION ||
466                     key == LAST_COLUMN ||
467                     key == LAST_COLUMN_EXTEND_SELECTION ||
468                     key == LAST_ROW ||
469                     key == LAST_ROW_EXTEND_SELECTION) {
470
471                 if (table.isEditing() &&
472                         !table.getCellEditor().stopCellEditing()) {
473                     return;
474                 }
475     
476                 // Unfortunately, this strategy introduces bugs because
477
// of the asynchronous nature of requestFocus() call below.
478
// Introducing a delay with invokeLater() makes this work
479
// in the typical case though race conditions then allow
480
// focus to disappear altogether. The right solution appears
481
// to be to fix requestFocus() so that it queues a request
482
// for the focus regardless of who owns the focus at the
483
// time the call to requestFocus() is made. The optimisation
484
// to ignore the call to requestFocus() when the component
485
// already has focus may ligitimately be made as the
486
// request focus event is dequeued, not before.
487

488                 // boolean wasEditingWithFocus = table.isEditing() &&
489
// table.getEditorComponent().isFocusOwner();
490

491                 boolean changeLead = false;
492                 if (key == NEXT_ROW_CHANGE_LEAD || key == PREVIOUS_ROW_CHANGE_LEAD) {
493                     changeLead = (rsm.getSelectionMode()
494                                      == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
495                 } else if (key == NEXT_COLUMN_CHANGE_LEAD || key == PREVIOUS_COLUMN_CHANGE_LEAD) {
496                     changeLead = (csm.getSelectionMode()
497                                      == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
498                 }
499
500                 if (changeLead) {
501                     moveWithinTableRange(table, dx, dy);
502                     if (dy != 0) {
503                         // casting should be safe since the action is only enabled
504
// for DefaultListSelectionModel
505
((DefaultListSelectionModel)rsm).moveLeadSelectionIndex(leadRow);
506                         if (getAdjustedLead(table, false, csm) == -1
507                                 && table.getColumnCount() > 0) {
508
509                             ((DefaultListSelectionModel)csm).moveLeadSelectionIndex(0);
510                         }
511                     } else {
512                         // casting should be safe since the action is only enabled
513
// for DefaultListSelectionModel
514
((DefaultListSelectionModel)csm).moveLeadSelectionIndex(leadColumn);
515                         if (getAdjustedLead(table, true, rsm) == -1
516                                 && table.getRowCount() > 0) {
517
518                             ((DefaultListSelectionModel)rsm).moveLeadSelectionIndex(0);
519                         }
520                     }
521
522                     Rectangle cellRect = table.getCellRect(leadRow, leadColumn, false);
523                     if (cellRect != null) {
524                         table.scrollRectToVisible(cellRect);
525                     }
526                 } else if (!inSelection) {
527                     moveWithinTableRange(table, dx, dy);
528                     table.changeSelection(leadRow, leadColumn, false, extend);
529                 }
530                 else {
531                     if (table.getRowCount() <= 0 || table.getColumnCount() <= 0) {
532                         // bail - don't try to move selection on an empty table
533
return;
534                     }
535
536                     if (moveWithinSelectedRange(table, dx, dy, rsm, csm)) {
537                         // this is the only way we have to set both the lead
538
// and the anchor without changing the selection
539
if (rsm.isSelectedIndex(leadRow)) {
540                             rsm.addSelectionInterval(leadRow, leadRow);
541                         } else {
542                             rsm.removeSelectionInterval(leadRow, leadRow);
543                         }
544
545                         if (csm.isSelectedIndex(leadColumn)) {
546                             csm.addSelectionInterval(leadColumn, leadColumn);
547                         } else {
548                             csm.removeSelectionInterval(leadColumn, leadColumn);
549                         }
550
551                         Rectangle cellRect = table.getCellRect(leadRow, leadColumn, false);
552                         if (cellRect != null) {
553                             table.scrollRectToVisible(cellRect);
554                         }
555                     }
556                     else {
557                         table.changeSelection(leadRow, leadColumn,
558                                 false, false);
559                     }
560                 }
561     
562                 /*
563                 if (wasEditingWithFocus) {
564                     table.editCellAt(leadRow, leadColumn);
565                     final Component editorComp = table.getEditorComponent();
566                     if (editorComp != null) {
567                         SwingUtilities.invokeLater(new Runnable() {
568                             public void run() {
569                                 editorComp.requestFocus();
570                             }
571                         });
572                     }
573                 }
574                 */

575             } else if (key == CANCEL_EDITING) {
576                 table.removeEditor();
577             } else if (key == SELECT_ALL) {
578                 table.selectAll();
579             } else if (key == CLEAR_SELECTION) {
580                 table.clearSelection();
581             } else if (key == START_EDITING) {
582                 if (!table.hasFocus()) {
583                     CellEditor cellEditor = table.getCellEditor();
584                     if (cellEditor != null && !cellEditor.stopCellEditing()) {
585                         return;
586                     }
587                     table.requestFocus();
588                     return;
589                 }
590                 table.editCellAt(leadRow, leadColumn);
591                 Component editorComp = table.getEditorComponent();
592                 if (editorComp != null) {
593                     editorComp.requestFocus();
594                 }
595             } else if (key == ADD_TO_SELECTION) {
596                 if (!table.isCellSelected(leadRow, leadColumn)) {
597                     int oldAnchorRow = rsm.getAnchorSelectionIndex();
598                     int oldAnchorColumn = csm.getAnchorSelectionIndex();
599                     rsm.setValueIsAdjusting(true);
600                     csm.setValueIsAdjusting(true);
601                     table.changeSelection(leadRow, leadColumn, true, false);
602                     rsm.setAnchorSelectionIndex(oldAnchorRow);
603                     csm.setAnchorSelectionIndex(oldAnchorColumn);
604                     rsm.setValueIsAdjusting(false);
605                     csm.setValueIsAdjusting(false);
606                 }
607             } else if (key == TOGGLE_AND_ANCHOR) {
608                 table.changeSelection(leadRow, leadColumn, true, false);
609             } else if (key == EXTEND_TO) {
610                 table.changeSelection(leadRow, leadColumn, false, true);
611             } else if (key == MOVE_SELECTION_TO) {
612                 table.changeSelection(leadRow, leadColumn, false, false);
613             }
614         }
615
616         public boolean isEnabled(Object JavaDoc sender) {
617             String JavaDoc key = getName();
618
619             if (sender instanceof JTable &&
620                 Boolean.TRUE.equals(((JTable)sender).getClientProperty("Table.isFileList"))) {
621                 if (key == NEXT_COLUMN ||
622                         key == NEXT_COLUMN_CELL ||
623                         key == NEXT_COLUMN_EXTEND_SELECTION ||
624                         key == NEXT_COLUMN_CHANGE_LEAD ||
625                         key == PREVIOUS_COLUMN ||
626                         key == PREVIOUS_COLUMN_CELL ||
627                         key == PREVIOUS_COLUMN_EXTEND_SELECTION ||
628                         key == PREVIOUS_COLUMN_CHANGE_LEAD ||
629                         key == SCROLL_LEFT_CHANGE_SELECTION ||
630                         key == SCROLL_LEFT_EXTEND_SELECTION ||
631                         key == SCROLL_RIGHT_CHANGE_SELECTION ||
632                         key == SCROLL_RIGHT_EXTEND_SELECTION ||
633                         key == FIRST_COLUMN ||
634                         key == FIRST_COLUMN_EXTEND_SELECTION ||
635                         key == LAST_COLUMN ||
636                         key == LAST_COLUMN_EXTEND_SELECTION ||
637                         key == NEXT_ROW_CELL ||
638                         key == PREVIOUS_ROW_CELL) {
639
640                     return false;
641                 }
642             }
643
644             if (key == CANCEL_EDITING && sender instanceof JTable) {
645                 return ((JTable)sender).isEditing();
646             } else if (key == NEXT_ROW_CHANGE_LEAD ||
647                        key == PREVIOUS_ROW_CHANGE_LEAD) {
648                 // discontinuous selection actions are only enabled for
649
// DefaultListSelectionModel
650
return sender != null &&
651                        ((JTable)sender).getSelectionModel()
652                            instanceof DefaultListSelectionModel;
653             } else if (key == NEXT_COLUMN_CHANGE_LEAD ||
654                        key == PREVIOUS_COLUMN_CHANGE_LEAD) {
655                 // discontinuous selection actions are only enabled for
656
// DefaultListSelectionModel
657
return sender != null &&
658                        ((JTable)sender).getColumnModel().getSelectionModel()
659                            instanceof DefaultListSelectionModel;
660             } else if (key == ADD_TO_SELECTION && sender instanceof JTable) {
661                 // This action is typically bound to SPACE.
662
// If the table is already in an editing mode, SPACE should
663
// simply enter a space character into the table, and not
664
// select a cell. Likewise, if the lead cell is already selected
665
// then hitting SPACE should just enter a space character
666
// into the cell and begin editing. In both of these cases
667
// this action will be disabled.
668
JTable table = (JTable)sender;
669                 int leadRow = getAdjustedLead(table, true);
670                 int leadCol = getAdjustedLead(table, false);
671                 return !(table.isEditing() || table.isCellSelected(leadRow, leadCol));
672             }
673
674             return true;
675         }
676     }
677
678
679 //
680
// The Table's Key listener
681
//
682

683     /**
684      * This inner class is marked &quot;public&quot; due to a compiler bug.
685      * This class should be treated as a &quot;protected&quot; inner class.
686      * Instantiate it only within subclasses of BasicTableUI.
687      * <p>As of Java 2 platform v1.3 this class is no longer used.
688      * Instead <code>JTable</code>
689      * overrides <code>processKeyBinding</code> to dispatch the event to
690      * the current <code>TableCellEditor</code>.
691      */

692      public class KeyHandler implements KeyListener {
693         // NOTE: This class exists only for backward