1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package net.sf.xframe.swing;
22
23 import java.awt.AWTEventMulticaster;
24 import java.awt.BorderLayout;
25 import java.awt.Color;
26 import java.awt.Component;
27 import java.awt.Dimension;
28 import java.awt.Font;
29 import java.awt.Graphics;
30 import java.awt.Point;
31 import java.awt.Rectangle;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.MouseEvent;
34 import java.awt.event.MouseListener;
35 import java.awt.event.MouseMotionListener;
36 import java.awt.event.MouseWheelEvent;
37 import java.awt.event.MouseWheelListener;
38 import java.awt.geom.Rectangle2D;
39 import java.beans.PropertyChangeEvent;
40 import java.beans.PropertyChangeListener;
41 import java.util.EventListener;
42 import java.util.EventObject;
43
44 import javax.accessibility.Accessible;
45 import javax.swing.AbstractAction;
46 import javax.swing.Action;
47 import javax.swing.DefaultListSelectionModel;
48 import javax.swing.JComponent;
49 import javax.swing.JScrollBar;
50 import javax.swing.JScrollPane;
51 import javax.swing.JTable;
52 import javax.swing.JViewport;
53 import javax.swing.ListSelectionModel;
54 import javax.swing.ScrollPaneConstants;
55 import javax.swing.Scrollable;
56 import javax.swing.TransferHandler;
57 import javax.swing.border.Border;
58 import javax.swing.event.CellEditorListener;
59 import javax.swing.event.ChangeEvent;
60 import javax.swing.event.ListSelectionEvent;
61 import javax.swing.event.ListSelectionListener;
62 import javax.swing.event.TableColumnModelEvent;
63 import javax.swing.event.TableColumnModelListener;
64 import javax.swing.event.TableModelEvent;
65 import javax.swing.event.TableModelListener;
66 import javax.swing.plaf.ScrollPaneUI;
67 import javax.swing.plaf.TableUI;
68 import javax.swing.table.DefaultTableColumnModel;
69 import javax.swing.table.DefaultTableModel;
70 import javax.swing.table.JTableHeader;
71 import javax.swing.table.TableCellEditor;
72 import javax.swing.table.TableCellRenderer;
73 import javax.swing.table.TableColumn;
74 import javax.swing.table.TableColumnModel;
75 import javax.swing.table.TableModel;
76
77 import net.sf.xframe.swing.scroll.JScrollPaneAdjuster;
78 import net.sf.xframe.swing.table.ColumnGroupHeader;
79 import net.sf.xframe.swing.table.JXTableColumnModel;
80 import net.sf.xframe.swing.table.JXTableHeader;
81 import net.sf.xframe.swing.table.KTable;
82
83
84 /***
85 * A table with freezable columns.
86 *
87 * <p>The main feature of this table is two allow locking columns while still
88 * having a neat user interface. For most of the original methods of class
89 * <code>JTable</code> there are delegate methods.</p>
90 *
91 * @author <a href=mailto:kriede@users.sourceforge.net>Kurt Riede</a>
92 */
93 public class JXTable extends JComponent implements TableModelListener, Scrollable,
94 TableColumnModelListener, ListSelectionListener,
95 CellEditorListener, Accessible {
96
97 /***
98 * Used to set the horizontal scroll bar policy so that
99 * horizontal scrollbars are displayed only when needed.
100 */
101 public static final int HORIZONTAL_SCROLLBAR_AS_NEEDED = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
102
103 /***
104 * Used to set the horizontal scroll bar policy so that
105 * horizontal scrollbars are never displayed.
106 */
107 public static final int HORIZONTAL_SCROLLBAR_NEVER = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER;
108
109 /***
110 * Used to set the horizontal scroll bar policy so that
111 * horizontal scrollbars are always displayed.
112 */
113 public static final int HORIZONTAL_SCROLLBAR_ALWAYS = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS;
114
115 /*** Do not adjust column widths automatically; use a scrollbar. */
116 public static final int AUTO_RESIZE_OFF = 0;
117
118 /*** When a column is adjusted in the UI, adjust the next column the opposite way. */
119 public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
120
121 /*** During UI adjustment, change subsequent columns to preserve the total width;
122 * this is the default behavior. */
123 public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
124
125 /*** During all resize operations, apply adjustments to the last column only. */
126 public static final int AUTO_RESIZE_LAST_COLUMN = 3;
127
128 /*** During all resize operations, proportionately resize all columns. */
129 public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
130
131 /*** The ScrollPane around the table. */
132 private final JScrollPane scrollPane;
133
134 /*** the table with the locked columns. */
135 private final KTable lockedTable;
136
137 /*** The table with the scrollable columns. */
138 private final KTable scrollTable;
139
140 /*** Scroll pane adjuster. */
141 private final JScrollPaneAdjuster adjuster;
142
143 /*** Header of the locked table. */
144 private JTableHeader lockedHeader;
145
146 /*** Header of the scrollable table. */
147 private JTableHeader scrollHeader;
148
149 /*** The table column model. */
150 private TableColumnModel columnModel;
151
152 /*** the header. */
153 private JXTableHeader collTableHeader;
154
155 /*** Number of frozen columns. */
156 private int frozenColumns = 1;
157
158 /*** Reference to the mouse listener. */
159 private transient MouseListener mouseListener;
160
161 /*** Reference to the mouse motion listener. */
162 private transient MouseMotionListener mouseMotionListener;
163
164 /*** Reference to the mouse wheel listener. */
165 private transient MouseWheelListener mouseWheelListener;
166
167 /***
168 * Constructs a default <code>JTable</code> that is initialized with a default
169 * data model, a default column model, and a default selection
170 * model.
171 */
172 public JXTable() {
173 this(null, null, null, 0);
174 }
175
176 /***
177 * Constructs a <code>JTable</code> that is initialized with
178 * <code>dm</code> as the data model, a default column model,
179 * and a default selection model.
180 *
181 * @param dm the data model for the table
182 */
183 public JXTable(final TableModel dm) {
184 this(dm, null, null, 0);
185 }
186
187 /***
188 * Constructs a <code>JTable</code> that is initialized with
189 * <code>dm</code> as the data model, a default column model,
190 * and a default selection model.
191 *
192 * @param dm the data model for the table
193 * @param numFrozenColumns the initial number of frozen columns
194 */
195 public JXTable(final TableModel dm, final int numFrozenColumns) {
196 this(dm, null, null, numFrozenColumns);
197 }
198
199 /***
200 * Constructs a <code>JTable</code> that is initialized with
201 * <code>dm</code> as the data model, <code>cm</code>
202 * as the column model, and a default selection model.
203 *
204 * @param dm the data model for the table
205 * @param cm the column model for the table
206 */
207 public JXTable(final TableModel dm, final TableColumnModel cm) {
208 this(dm, cm, null, 0);
209 }
210
211 /***
212 * Constructs a <code>JTable</code> that is initialized with
213 * <code>dm</code> as the data model, <code>cm</code>
214 * as the column model, and a default selection model.
215 *
216 * @param dm the data model for the table
217 * @param cm the column model for the table
218 * @param numFrozenColumns the initial number of frozen columns
219 */
220 public JXTable(final TableModel dm, final TableColumnModel cm, final int numFrozenColumns) {
221 this(dm, cm, null, numFrozenColumns);
222 }
223
224 /***
225 * Constructs a <code>JTable</code> that is initialized with
226 * <code>dm</code> as the data model, <code>cm</code> as the
227 * column model, and <code>sm</code> as the selection model.
228 * If any of the parameters are <code>null</code> this method
229 * will initialize the table with the corresponding default model.
230 * The <code>autoCreateColumnsFromModel</code> flag is set to false
231 * if <code>cm</code> is non-null, otherwise it is set to true
232 * and the column model is populated with suitable
233 * <code>TableColumns</code> for the columns in <code>dm</code>.
234 *
235 * @param dm the data model for the table
236 * @param cm the column model for the table
237 * @param sm the row selection model for the table
238 */
239 public JXTable(final TableModel dm, final TableColumnModel cm, final ListSelectionModel sm) {
240 this(dm, cm, sm, 0);
241 }
242
243 /***
244 * Constructs a <code>JTable</code> that is initialized with
245 * <code>dm</code> as the data model, <code>cm</code> as the
246 * column model, and <code>sm</code> as the selection model.
247 * If any of the parameters are <code>null</code> this method
248 * will initialize the table with the corresponding default model.
249 * The <code>autoCreateColumnsFromModel</code> flag is set to false
250 * if <code>cm</code> is non-null, otherwise it is set to true
251 * and the column model is populated with suitable
252 * <code>TableColumns</code> for the columns in <code>dm</code>.
253 *
254 * @param dm the data model for the table
255 * @param cm the column model for the table
256 * @param sm the row selection model for the table
257 * @param numFrozenColumns the initial number of frozen columns
258 */
259 public JXTable(final TableModel dm, final TableColumnModel cm, final ListSelectionModel sm, final int numFrozenColumns) {
260 super();
261 scrollPane = new JScrollPane();
262 adjuster = new JScrollPaneAdjuster(scrollPane);
263 final TableModel model;
264 if (dm == null) {
265 model = createDefaultDataModel();
266 } else {
267 model = dm;
268 }
269 frozenColumns = numFrozenColumns;
270 if (frozenColumns > model.getColumnCount()) {
271 frozenColumns = model.getColumnCount();
272 }
273 final TableColumnModel cm1;
274 final TableColumnModel cm2;
275 if (cm == null) {
276 cm1 = null;
277 cm2 = null;
278 } else {
279 cm1 = this.createDefaultColumnModel();
280 cm2 = this.createDefaultColumnModel();
281 for (int i = 0; i < cm.getColumnCount(); i++) {
282 cm1.addColumn(cm.getColumn(i));
283 cm2.addColumn(cm.getColumn(i));
284 }
285 }
286
287 lockedTable = new KTable(model, cm1, sm, KTable.TYPE_LOCKED);
288 scrollTable = new KTable(model, cm2, sm, KTable.TYPE_SCROLL);
289 lockedHeader = new ColumnGroupHeader(lockedTable.getColumnModel());
290 scrollHeader = new ColumnGroupHeader(scrollTable.getColumnModel());
291 lockedTable.setTableHeader(lockedHeader);
292 scrollTable.setTableHeader(scrollHeader);
293 scrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, lockedHeader);
294 scrollPane.setViewportView(scrollTable);
295 scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
296 setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
297 setResizingAllowed(true);
298
299
300 final JViewport viewport = new JViewport();
301 viewport.setView(lockedTable);
302 scrollPane.setRowHeader(viewport);
303
304
305 if (sm == null) {
306 scrollTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
307 lockedTable.setSelectionModel(scrollTable.getSelectionModel());
308 }
309
310 lockedTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
311 scrollTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
312
313
314 final TableColumnModel scrollColumnModel = scrollTable.getColumnModel();
315 for (int i = 0; i < frozenColumns; i++) {
316 scrollColumnModel.removeColumn(scrollColumnModel.getColumn(0));
317 }
318
319
320 final TableColumnModel lockedColumnModel = lockedTable.getColumnModel();
321 while (lockedTable.getColumnCount() > frozenColumns) {
322 lockedColumnModel.removeColumn(lockedColumnModel.getColumn(frozenColumns));
323 }
324
325 lockedTable.setAutoCreateColumnsFromModel(false);
326 scrollTable.setAutoCreateColumnsFromModel(false);
327
328
329 for (int i = 0; i < lockedColumnModel.getColumnCount(); i++) {
330 lockedColumnModel.getColumn(i).addPropertyChangeListener(new ColumnWidthChangeListener());
331 }
332
333
334 columnModel = new JXTableColumnModel(this, lockedColumnModel, scrollColumnModel);
335
336
337 lockedTable.setPreferredScrollableViewportSize(lockedTable.getPreferredSize());
338
339 adjustActionMaps();
340
341 final JTableHeader theLockedHeader = lockedTable.getTableHeader();
342 final JTableHeader theScrollHeader = scrollTable.getTableHeader();
343 collTableHeader = new JXTableHeader(columnModel, theLockedHeader, theScrollHeader);
344 collTableHeader.setTable(this);
345
346
347 setLayout(new BorderLayout());
348 add(scrollPane, "Center");
349 }
350
351 /***
352 * Returns the underlying scroll pane.
353 *
354 * @return the underlying scroll pane
355 */
356 public JScrollPane getScrollPane() {
357 return scrollPane;
358 }
359
360 /***
361 * Adjusts the action maps of the two tables to allow proper navigation
362 * between the two tables.
363 */
364 private void adjustActionMaps() {
365
366 final Action scrollNextAction = scrollTable.getActionMap().get("selectNextColumnCell");
367 final Action lockedNextAction = lockedTable.getActionMap().get("selectNextColumnCell");
368 final Action scrollPreviousAction = scrollTable.getActionMap().get("selectPreviousColumnCell");
369 final Action lockedPreviousAction = lockedTable.getActionMap().get("selectPreviousColumnCell");
370 final Action scrollFirstAction = scrollTable.getActionMap().get("selectFirstColumn");
371 final Action lockedLastAction = lockedTable.getActionMap().get("selectLastColumn");
372
373 lockedTable.getActionMap().put("selectNextColumn", new LockedNextAction(lockedNextAction));
374 lockedTable.getActionMap().put("selectPreviousColumn", new LockedPreviousAction(lockedPreviousAction));
375 scrollTable.getActionMap().put("selectNextColumn", new ScrollNextAction(scrollNextAction));
376 scrollTable.getActionMap().put("selectPreviousColumn", new ScrollPreviousAction(scrollPreviousAction));
377
378 lockedTable.getActionMap().put("selectNextColumnCell", new LockedNextAction(lockedNextAction));
379 lockedTable.getActionMap().put("selectPreviousColumnCell", new LockedPreviousAction(lockedPreviousAction));
380 scrollTable.getActionMap().put("selectNextColumnCell", new ScrollNextAction(scrollNextAction));
381 scrollTable.getActionMap().put("selectPreviousColumnCell", new ScrollPreviousAction(scrollPreviousAction));
382
383 scrollTable.getActionMap().put("selectFirstColumn", new ScrollFirstAction(scrollFirstAction));
384 lockedTable.getActionMap().put("selectLastColumn", new LockedLastAction(lockedLastAction));
385 }
386
387 /***
388 * Returns the default table model object, which is
389 * a <code>DefaultTableModel</code>. A subclass can override this
390 * method to return a different table model object.
391 *
392 * @return the default table model object
393 * @see javax.swing.table.DefaultTableModel
394 */
395 protected TableModel createDefaultDataModel() {
396 return new DefaultTableModel();
397 }
398
399 /***
400 * Returns the default column model object, which is
401 * a <code>DefaultTableColumnModel</code>. A subclass can override this
402 * method to return a different column model object.
403 *
404 * @return the default column model object
405 * @see javax.swing.table.DefaultTableColumnModel
406 */
407 protected TableColumnModel createDefaultColumnModel() {
408 return new DefaultTableColumnModel();
409 }
410
411 /***
412 * Returns the default selection model object, which is
413 * a <code>DefaultListSelectionModel</code>. A subclass can override this
414 * method to return a different selection model object.
415 *
416 * @return the default selection model object
417 * @see javax.swing.DefaultListSelectionModel
418 */
419 protected ListSelectionModel createDefaultSelectionModel() {
420 return new DefaultListSelectionModel();
421 }
422
423 /***
424 * Returns the default table header object for the scrollable table,
425 * which is a <code>JTableHeader</code>. A subclass can override this
426 * method to return a different table header object.
427 *
428 * @return the default table header object
429 * @see javax.swing.table.JTableHeader
430 * @see net.sf.xframe.swing.table.JXTableHeader
431 */
432 public JTableHeader createDefaultScrollTableHeader() {
433 return new ColumnGroupHeader(scrollTable.getColumnModel());
434 }
435
436
437 /***
438 /**
439 * Returns the number of the next row in the table relative to the
440 * current selection. If the selection is in the last row, the next row
441 * is the first row.
442 *
443 * @param table a JTable for row calculation
444 * @return row number of next row
445 */
446 protected int nextRow(final JTable table) {
447 int row = table.getSelectedRow() + 1;
448 if (row == table.getRowCount()) {
449 row = 0;
450 }
451 return row;
452 }
453
454 /***
455 * Returns the number of the previous row in the table relative to the
456 * current selection. If the selection is in the first row, the next row
457 * is the first row.
458 *
459 * @param table a JTable for row calculation
460 * @return row number of previous row
461 */
462 private int previousRow(final JTable table) {
463 int row = table.getSelectedRow() - 1;
464 if (row == -1) {
465 row = table.getRowCount() - 1;
466 }
467 return row;
468 }
469
470 /***
471 * Returns the internal table for the locked columns.
472 *
473 * @return the locked table
474 */
475 public final JTable getLockedTable() {
476 return lockedTable;
477 }
478
479 /***
480 * Returns the internal table for the scrollable columns.
481 *
482 * @return the scrollable table
483 */
484 public final JTable getScrollTable() {
485 return scrollTable;
486 }
487
488 /***
489 * Returns the number of frozen columns.
490 *
491 * @return number of frozen columns
492 */
493 public final int getFrozenColumns() {
494 return frozenColumns;
495 }
496
497 /***
498 * Setter method for frozen columns attribute.
499 *
500 * <p>Changing the number frozen column results in rearranging the columns
501 * within the fixed-column and the scrollable table.</p>
502 *
503 * @param numFrozenColumns of frozen columns
504 */
505 public final void setFrozenColumns(final int numFrozenColumns) {
506 if (numFrozenColumns > lockedTable.getModel().getColumnCount()) {
507 return;
508 }
509 final TableColumnModel scrollColumnModel = scrollTable.getColumnModel();
510 final TableColumnModel lockedColumnModel = lockedTable.getColumnModel();
511 if (frozenColumns < numFrozenColumns) {
512
513 for (int i = frozenColumns; i < numFrozenColumns; i++) {
514 final TableColumn column = scrollColumnModel.getColumn(0);
515 lockedColumnModel.addColumn(column);
516 scrollColumnModel.removeColumn(column);
517 column.addPropertyChangeListener(new ColumnWidthChangeListener());
518 }
519 lockedTable.setPreferredScrollableViewportSize(lockedTable.getPreferredSize());
520 } else if (frozenColumns > numFrozenColumns) {
521
522 for (int i = numFrozenColumns; i < frozenColumns; i++) {
523 final TableColumn column = lockedColumnModel.getColumn(lockedColumnModel.getColumnCount() - 1);
524 scrollColumnModel.addColumn(column);
525 scrollColumnModel.moveColumn(scrollColumnModel.getColumnCount() - 1, 0);
526 lockedColumnModel.removeColumn(column);
527 }
528 lockedTable.setPreferredScrollableViewportSize(lockedTable.getPreferredSize());
529 }
530 frozenColumns = numFrozenColumns;
531 }
532
533 /***
534 * Sets the background color of this component.
535 *
536 * @param bg the desired background <code>Color</code>
537 */
538 public void setHeaderBackground(final Color bg) {
539 lockedHeader.setBackground(bg);
540 scrollHeader.setBackground(bg);
541 }
542
543 /***
544 * Sets the border of the table header.
545 *
546 * @param border the border to be rendered for this component
547 */
548 public void setHeaderBorder(final Border border) {
549 lockedHeader.setBorder(border);
550 scrollHeader.setBorder(border);
551 }
552
553 /***
554 * Sets the font for the table header.
555 *
556 * @param font the desired <code>Font</code> for this component
557 */
558 public void setHeaderFont(final Font font) {
559 lockedHeader.setFont(font);
560 scrollHeader.setFont(font);
561 }
562
563 /***
564 * Sets whether the user can drag column headers to reorder columns.
565 *
566 * @param reorderingAllowed true if the table view should allow
567 * reordering; otherwise false
568 */
569 public void setReorderingAllowed(final boolean reorderingAllowed) {
570 lockedHeader.setReorderingAllowed(reorderingAllowed);
571 scrollHeader.setReorderingAllowed(reorderingAllowed);
572 }
573
574 /***
575 * Sets whether the user can resize columns by dragging between headers.
576 *
577 * @param resizingAllowed true if table view should allow resizing
578 */
579 public void setResizingAllowed(final boolean resizingAllowed) {
580 lockedHeader.setResizingAllowed(resizingAllowed);
581 scrollHeader.setResizingAllowed(resizingAllowed);
582 }
583
584 /***
585 * Sets the font for this component.
586 *
587 * @param font the desired <code>Font</code> for this component
588 */
589 public void setTableFont(final Font font) {
590 lockedTable.setFont(font);
591 scrollTable.setFont(font);
592 }
593
594 /***
595 * Sets the foreground color of this component.
596 *
597 * @param fg the desired foreground <code>Color</code>
598 */
599 public void setForeground(final Color fg) {
600 if (lockedTable != null) {
601 lockedTable.setForeground(fg);
602 }
603 if (scrollTable != null) {
604 scrollTable.setForeground(fg);
605 }
606 }
607
608 /***
609 * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
610 * The default color is look and feel dependent.
611 *
612 * @param gridColor the new color of the grid lines
613 */
614 public void setGridColor(final Color gridColor) {
615 lockedTable.setGridColor(gridColor);
616 scrollTable.setGridColor(gridColor);
617 }
618
619 /***
620 * Sets the background color for selected cells. Cell renderers
621 * can use this color to the fill selected cells.
622 * <p>
623 * The default value of this property is defined by the look
624 * and feel implementation.
625 * <p>
626 *
627 * @param selectionBackground the <code>Color</code> to use for the background
628 * of selected cells
629 */
630 public void setSelectionBackground(final Color selectionBackground) {
631 lockedTable.setSelectionBackground(selectionBackground);
632 scrollTable.setSelectionBackground(selectionBackground);
633 }
634
635 /***
636 * Sets the foreground color for selected cells. Cell renderers
637 * can use this color to render text and graphics for selected
638 * cells.
639 * <p>
640 * The default value of this property is defined by the look
641 * and feel implementation.
642 * <p>
643 *
644 * @param selectionForeground the <code>Color</code> to use in the foreground
645 */
646 public void setSelectionForeground(final Color selectionForeground) {
647 lockedTable.setSelectionForeground(selectionForeground);
648 scrollTable.setSelectionForeground(selectionForeground);
649 }
650
651 /***
652 * Sets whether the table draws grid lines around cells.
653 * If <code>showGrid</code> is true it does; if it is false it doesn't.
654 * There is no <code>getShowGrid</code> method as this state is held
655 * in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
656 * each of which can be queried independently.
657 *
658 * @param showGrid true if table view should draw grid lines
659 */
660 public void setShowGrid(final boolean showGrid) {
661 lockedTable.setShowGrid(showGrid);
662 scrollTable.setShowGrid(showGrid);
663 }
664
665 /***
666 * Sets whether the table draws horizontal lines between cells.
667 * If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
668 *
669 * @param showHorizontalLines true if table view should draw horizontal lines
670 */
671 public void setShowHorizontalLines(final boolean showHorizontalLines) {
672 lockedTable.setShowHorizontalLines(showHorizontalLines);
673 scrollTable.setShowHorizontalLines(showHorizontalLines);
674 }
675
676 /***
677 * Sets whether the table draws vertical lines between cells.
678 * If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
679 *
680 * @param showVerticalLines true if table view should draw vertical lines
681 */
682 public void setShowVerticalLines(final boolean showVerticalLines) {
683 lockedTable.setShowVerticalLines(showVerticalLines);
684 scrollTable.setShowVerticalLines(showVerticalLines);
685 }
686
687 /***
688 * Updates the selection models of the table, depending on the state of the
689 * two flags: <code>toggle</code> and <code>extend</code>. All changes
690 * to the selection that are the result of keyboard or mouse events received
691 * by the UI are channeled through this method so that the behavior may be
692 * overridden by a subclass.
693 * <p>
694 * This implementation uses the following conventions:
695 * <ul>
696 * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
697 * Clear the previous selection and ensure the new cell is selected.
698 * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
699 * Extend the previous selection to include the specified cell.
700 * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
701 * If the specified cell is selected, deselect it. If it is not selected, select it.
702 * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
703 * Leave the selection state as it is, but move the anchor index to the specified location.
704 * </ul>
705 * @param row affects the selection at <code>row</code>
706 * @param column affects the selection at <code>column</code>
707 * @param toggle see description above
708 * @param extend if true, extend the current selection
709 *
710 */
711 public void changeSelection(final int row, final int column, final boolean toggle, final boolean extend) {
712 if (column < frozenColumns) {
713 lockedTable.changeSelection(row, column, toggle, extend);
714 } else {
715 scrollTable.changeSelection(row, column - frozenColumns, toggle, extend);
716 }
717 }
718
719 /***
720 * Programmatically starts editing the cell at <code>row</code> and
721 * <code>column</code>, if the cell is editable. Note that this is
722 * a convenience method for <code>editCellAt(int, int, null)</code>.
723 *
724 * @param row the row to be edited
725 * @param column the column to be edited
726 * @return false if for any reason the cell cannot be edited
727 */
728 public boolean editCellAt(final int row, final int column) {
729 if (column < frozenColumns) {
730 return lockedTable.editCellAt(row, column);
731 } else {
732 return scrollTable.editCellAt(row, column - frozenColumns);
733 }
734 }
735
736 /***
737 * Returns the name of the column appearing in the view at
738 * column position <code>column</code>.
739 *
740 * @param column the column in the view being queried
741 * @return the name of the column at position <code>column</code>
742 * in the view where the first column is column 0
743 */
744 public String getColumnName(final int column) {
745 if (column < frozenColumns) {
746 return lockedTable.getColumnName(column);
747 } else {
748 return scrollTable.getColumnName(column - frozenColumns);
749 }
750 }
751
752 /***
753 * Returns the index of the column that contains the cell currently
754 * being edited. If nothing is being edited, returns -1.
755 *
756 * @return the index of the column that contains the cell currently
757 * being edited; returns -1 if nothing being edited
758 */
759 public int getEditingColumn() {
760 if (lockedTable.hasFocus()) {
761 return lockedTable.getEditingColumn();
762 }
763
764 return scrollTable.getEditingColumn() + frozenColumns;
765 }
766
767 /***
768 * Returns the index of the row that contains the cell currently
769 * being edited. If nothing is being edited, returns -1.
770 *
771 * @return the index of the row that contains the cell currently
772 * being edited; returns -1 if nothing being edited
773 */
774 public int getEditingRow() {
775 if (lockedTable.hasFocus()) {
776 return lockedTable.getEditingRow();
777 }
778 return scrollTable.getEditingRow();
779 }
780
781 /***
782 * Returns the color used to draw grid lines.
783 * The default color is look and feel dependent.
784 *
785 * @return the color used to draw grid lines
786 * @see #setGridColor
787 */
788 public Color getGridColor() {
789 return lockedTable.getGridColor();
790 }
791
792 /***
793 * Returns true if rows can be selected.
794 *
795 * @return true if rows can be selected, otherwise false
796 * @see #setRowSelectionAllowed
797 */
798 public boolean getRowSelectionAllowed() {
799 return lockedTable.getRowSelectionAllowed();
800 }
801
802 /***
803 * Returns the index of the first selected row, -1 if no row is selected.
804 *
805 * @return the index of the first selected row
806 */
807 public int getSelectedRow() {
808 return lockedTable.getSelectedRow();
809 }
810
811 /***
812 * Returns the number of selected rows.
813 *
814 * @return the number of selected rows, 0 if no rows are selected
815 */
816 public int getSelectedRowCount() {
817 return lockedTable.getSelectedRowCount();
818 }
819
820 /***
821 * Returns the indices of all selected rows.
822 *
823 * @return an array of integers containing the indices of all selected rows,
824 * or an empty array if no row is selected
825 * @see #getSelectedRow
826 */
827 public int[] getSelectedRows() {
828 return lockedTable.getSelectedRows();
829 }
830
831 /***
832 * Returns the <code>ListSelectionModel</code> that is used to maintain row
833 * selection state.
834 *
835 * @return the object that provides row selection state, <code>null</code>
836 * if row selection is not allowed
837 */
838 public ListSelectionModel getSelectionModel() {
839 return lockedTable.getSelectionModel();
840 }
841
842 /***
843 * Returns the cell value at <code>row</code> and <code>column</code>.
844 * <p>
845 * <b>Note</b>: The column is specified in the table view's display
846 * order, and not in the <code>TableModel</code>'s column
847 * order. This is an important distinction because as the
848 * user rearranges the columns in the table,
849 * the column at a given index in the view will change.
850 * Meanwhile the user's actions never affect the model's
851 * column ordering.
852 *
853 * @param row the row whose value is to be queried
854 * @param column the column whose value is to be queried
855 * @return the Object at the specified cell
856 */
857 public Object getValueAt(final int row, final int column) {
858 if (column < frozenColumns) {
859 return lockedTable.getValueAt(row, column);
860 } else {
861 return scrollTable.getValueAt(row, column - frozenColumns);
862 }
863 }
864
865 /***
866 * Sets the value for the cell in the table model at <code>row</code>
867 * and <code>column</code>.
868 * <p>
869 * <b>Note</b>: The column is specified in the table view's display
870 * order, and not in the <code>TableModel</code>'s column
871 * order. This is an important distinction because as the
872 * user rearranges the columns in the table,
873 * the column at a given index in the view will change.
874 * Meanwhile the user's actions never affect the model's
875 * column ordering.
876 *
877 * <code>aValue</code> is the new value.
878 *
879 * @param aValue the new value
880 * @param row the row of the cell to be changed
881 * @param column the column of the cell to be changed
882 * @see #getValueAt
883 */
884 public void setValueAt(final Object aValue, final int row, final int column) {
885 if (column < frozenColumns) {
886 lockedTable.setValueAt(aValue, row, column);
887 } else {
888 scrollTable.setValueAt(aValue, row, column - frozenColumns);
889 }
890 }
891
892 /***
893 * Maps the index of the column in the view at <code>viewColumnIndex</code>
894 * to the index of the column in the table model. Returns the index of the
895 * corresponding column in the model. If <code>viewColumnIndex</code>
896 * is less than zero, returns <code>viewColumnIndex</code>.
897 *
898 * @param viewColumnIndex the index of the column in the view
899 * @return the index of the corresponding column in the model
900 *
901 * @see #convertColumnIndexToView
902 */
903 public int convertColumnIndexToModel(final int viewColumnIndex) {
904 if (viewColumnIndex < frozenColumns) {
905 return lockedTable.convertColumnIndexToModel(viewColumnIndex);
906 } else {
907 return scrollTable.convertColumnIndexToModel(viewColumnIndex - frozenColumns);
908 }
909 }
910
911 /***
912 * Maps the index of the column in the table model at
913 * <code>modelColumnIndex</code> to the index of the column in the view.
914 * Returns the index of the corresponding column in the view; returns -1 if
915 * this column is not being displayed. If <code>modelColumnIndex</code> is
916 * less than zero, returns <code>modelColumnIndex</code>.
917 *
918 * @param modelColumnIndex the index of the column in the model
919 * @return the index of the corresponding column in the view
920 *
921 * @see #convertColumnIndexToModel
922 */
923 public int convertColumnIndexToView(final int modelColumnIndex) {
924 final int lockedIndex = lockedTable.convertColumnIndexToView(modelColumnIndex);
925 final int scrollIndex = scrollTable.convertColumnIndexToView(modelColumnIndex);
926 if (lockedIndex >= 0) {
927 return lockedIndex;
928 } else {
929 return scrollIndex;
930 }
931 }
932
933 /***
934 * Returns true if the cell at <code>row</code> and <code>column</code>
935 * is editable. Otherwise, invoking <code>setValueAt</code> on the cell
936 * will have no effect.
937 * <p>
938 * <b>Note</b>: The column is specified in the table view's display order,
939 * and not in the <code>TableModel</code>'s column order. This is an
940 * important distinction because as the user rearranges the columns in the
941 * table, the column at a given index in the view will change. Meanwhile the
942 * user's actions never affect the model's column ordering.
943 * @param row the row whose value is to be queried
944 * @param column the column whose value is to be queried
945 * @return true if the cell is editable
946 * @see #setValueAt
947 */
948 public boolean isCellEditable(final int row, final int column) {
949 return getModel().isCellEditable(row, convertColumnIndexToModel(column));
950 }
951
952 /***
953 * Returns true if the cell at the specified position is selected.
954 * @param row the row being queried
955 * @param column the column being queried
956 *
957 * @return true if the cell at index <code>(row, column)</code> is selected,
958 * where the first row and first column are at index 0
959 */
960 public boolean isCellSelected(final int row, final int column) {
961 if (column < frozenColumns) {
962 return lockedTable.isCellSelected(row, column);
963 } else {
964 return scrollTable.isCellSelected(row, column - frozenColumns);
965 }
966 }
967
968 /***
969 * Returns true if a cell is being edited.
970 *
971 * @return true if the table is editing a cell
972 */
973 public boolean isEditing() {
974 return lockedTable.isEditing();
975 }
976
977 /***
978 * Returns true if the row at the specified index is selected.
979 *
980 * @param row the row being queried
981 * @return true if the row at index <code>row</code> is selected, where 0 is the
982 * first row
983 */
984 public boolean isRowSelected(final int row) {
985 return lockedTable.isRowSelected(row);
986 }
987
988 /***
989 * Sets the <code>editingRow</code> variable.
990 * @param row the row of the cell to be edited
991 */
992 public void setEditingRow(final int row) {
993 lockedTable.setEditingRow(row);
994 scrollTable.setEditingRow(row);
995 }
996
997 /***
998 * Sets the table's selection mode to allow only single selections, a single
999 * contiguous interval, or multiple intervals.
1000 * <P>
1001 * <bold>Note:</bold>
1002 * <code>JTable</code> provides all the methods for handling
1003 * column and row selection. When setting states,
1004 * such as <code>setSelectionMode</code>, it not only
1005 * updates the mode for the row selection model but also sets similar
1006 * values in the selection model of the <code>columnModel</code>.
1007 * If you want to have the row and column selection models operating
1008 * in different modes, set them both directly.
1009 * <p>
1010 * Both the row and column selection models for <code>JTable</code>
1011 * default to using a <code>DefaultListSelectionModel</code>
1012 * so that <code>JTable</code> works the same way as the
1013 * <code>JList</code>. See the <code>setSelectionMode</code> method
1014 * in <code>JList</code> for details about the modes.
1015 *
1016 * The following <code>selectionMode</code> values are allowed:
1017 * <ul>
1018 * <li><code>ListSelectionModel.SINGLE_SELECTION</code>
1019 * Only one list index can be selected at a time. In this mode the
1020 * <code>setSelectionInterval</code> and <code>addSelectionInterval</code>
1021 * methods are equivalent, and only the second index argument is used.</li>
1022 * <li><code>ListSelectionModel.SINGLE_INTERVAL_SELECTION</code>
1023 * One contiguous index interval can be selected at a time. In this mode
1024 * <code>setSelectionInterval</code> and <code>addSelectionInterval</code>
1025 * are equivalent.</li>
1026 * <li><code>ListSelectionModel.MULTIPLE_INTERVAL_SELECTION</code>
1027 * In this mode, there's no restriction on what can be selected. This is
1028 * the default.</li>
1029 * </ul>
1030 *
1031 * @param selectionMode an integer specifying the type of selections
1032 * that are permissible
1033 */
1034 public void setSelectionMode(final int selectionMode) {
1035 lockedTable.setSelectionMode(selectionMode);
1036 scrollTable.setSelectionMode(selectionMode);
1037 }
1038
1039 /***
1040 * Returns the <code>TableModel</code> that provides the data displayed by
1041 * this <code>JTable</code>.
1042 *
1043 * @return the <code>TableModel</code> that provides the data displayed by
1044 * this <code>JTable</code>
1045 */
1046 public TableModel getModel() {
1047 return lockedTable.getModel();
1048 }
1049
1050 /***
1051 * Sets whether the rows in this model can be selected.
1052 *
1053 * @param rowSelectionAllowed true if this model will allow row selection
1054 * @see #getRowSelectionAllowed
1055 */
1056 public void setRowSelectionAllowed(final boolean rowSelectionAllowed) {
1057 lockedTable.setRowSelectionAllowed(rowSelectionAllowed);
1058 scrollTable.setRowSelectionAllowed(rowSelectionAllowed);
1059 }
1060
1061 /***
1062 * Listener for column change events of locked columns to adjust the
1063 * viewport size of the locked table.
1064 */
1065 private final class ColumnWidthChangeListener implements PropertyChangeListener {
1066
1067 /*** Contructor. */
1068 private ColumnWidthChangeListener() {
1069 super();
1070 }
1071
1072 /***
1073 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
1074 */
1075 public void propertyChange(final PropertyChangeEvent evt) {
1076 if ("preferredWidth".equals(evt.getPropertyName())) {
1077 lockedTable.setPreferredScrollableViewportSize(lockedTable.getPreferredSize());
1078 }
1079 }
1080 }
1081
1082 /***
1083 * Appends <code>aColumn</code> to the end of the array of columns held by
1084 * this <code>JTable</code>'s column model.
1085 * If the column name of <code>aColumn</code> is <code>null</code>,
1086 * sets the column name of <code>aColumn</code> to the name
1087 * returned by <code>getModel().getColumnName()</code>.
1088 * <p>
1089 * To add a column to this <code>JTable</code> to display the
1090 * <code>modelColumn</code>'th column of data in the model with a
1091 * given <code>width</code>, <code>cellRenderer</code>,
1092 * and <code>cellEditor</code> you can use:
1093 * <pre>
1094 *
1095 * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
1096 *
1097 * </pre>
1098 * [Any of the <code>TableColumn</code> constructors can be used
1099 * instead of this one.]
1100 * The model column number is stored inside the <code>TableColumn</code>
1101 * and is used during rendering and editing to locate the appropriates
1102 * data values in the model. The model column number does not change
1103 * when columns are reordered in the view.
1104 *
1105 * @param aColumn the <code>TableColumn</code> to be added
1106 * @see #removeColumn
1107 */
1108 public void addColumn(final TableColumn aColumn) {
1109 scrollTable.addColumn(aColumn);
1110 }
1111
1112 /***
1113 * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
1114 * the current selection.
1115 *
1116 * @param index0 one end of the interval
1117 * @param index1 the other end of the interval
1118 */
1119 public void addRowSelectionInterval(final int index0, final int index1) {
1120 lockedTable.addRowSelectionInterval(index0, index1);
1121 }
1122
1123 /***
1124 * Deselects all selected columns and rows.
1125 */
1126 public void clearSelection() {
1127 lockedTable.clearSelection();
1128 scrollTable.clearSelection();
1129 }
1130
1131 /***
1132 * Programmatically starts editing the cell at <code>row</code> and
1133 * <code>column</code>, if the cell is editable.
1134 * To prevent the <code>JTable</code> from editing a particular table,
1135 * column or cell value, return false from the <code>isCellEditable</code>
1136 * method in the <code>TableModel</code> interface.
1137 *
1138 * @param row the row to be edited
1139 * @param column the column to be edited
1140 * @param e event to pass into <code>shouldSelectCell</code>;
1141 * note that as of Java 2 platform v1.2, the call to
1142 * <code>shouldSelectCell</code> is no longer made
1143 * @return false if for any reason the cell cannot be edited
1144 */
1145 public boolean editCellAt(final int row, final int column, final EventObject e) {
1146 if (column < frozenColumns) {
1147 return lockedTable.editCellAt(row, column, e);
1148 } else {
1149 return scrollTable.editCellAt(row, column - frozenColumns, e);
1150 }
1151 }
1152
1153 /***
1154 * Determines whether the table will create default columns from the model.
1155 * If true, <code>setModel</code> will clear any existing columns and
1156 * create new columns from the new model. Also, if the event in
1157 * the <code>tableChanged</code> notification specifies that the
1158 * entire table changed, then the columns will be rebuilt.
1159 * The default is true.
1160 *
1161 * @return the autoCreateColumnsFromModel of the table
1162 * @see #setAutoCreateColumnsFromModel
1163 */
1164 public boolean getAutoCreateColumnsFromModel() {
1165 return scrollTable.getAutoCreateColumnsFromModel();
1166 }
1167
1168 /***
1169 * Returns the cell editor.
1170 *
1171 * @return the <code>TableCellEditor</code> that does the editing
1172 */
1173 public TableCellEditor getCellEditor() {
1174 TableCellEditor editor = lockedTable.getCellEditor();
1175 if (editor != null) {
1176 return editor;
1177 }
1178 return scrollTable.getCellEditor();
1179 }
1180
1181 /***
1182 * Returns an appropriate editor for the cell specified by
1183 * <code>row</code> and <code>column</code>. If the
1184 * <code>TableColumn</code> for this column has a non-null editor,
1185 * returns that. If not, finds the class of the data in this
1186 * column (using <code>getColumnClass</code>)
1187 * and returns the default editor for this type of data.
1188 * <p>
1189 * <b>Note:</b>
1190 * Throughout the table package, the internal implementations always
1191 * use this method to provide editors so that this default behavior
1192 * can be safely overridden by a subclass.
1193 *
1194 * @param row the row of the cell to edit, where 0 is the first row
1195 * @param column the column of the cell to edit,
1196 * where 0 is the first column
1197 * @return the editor for this cell;
1198 * if <code>null</code> return the default editor for
1199 * this type of cell
1200 */
1201 public TableCellEditor getCellEditor(final int row, final int column) {
1202 if (column < frozenColumns) {
1203 return lockedTable.getCellEditor(row, column);
1204 } else {
1205 return scrollTable.getCellEditor(row, column - frozenColumns);
1206 }
1207 }
1208
1209 /***
1210 * Returns an appropriate renderer for the cell specified by this row and
1211 * column. If the <code>TableColumn</code> for this column has a non-null
1212 * renderer, returns that. If not, finds the class of the data in
1213 * this column (using <code>getColumnClass</code>)
1214 * and returns the default renderer for this type of data.
1215 * <p>
1216 * <b>Note:</b>
1217 * Throughout the table package, the internal implementations always
1218 * use this method to provide renderers so that this default behavior
1219 * can be safely overridden by a subclass.
1220 *
1221 * @param row the row of the cell to render, where 0 is the first row
1222 * @param column the column of the cell to render,
1223 * where 0 is the first column
1224 * @return the assigned renderer; if <code>null</code>
1225 * returns the default renderer
1226 * for this type of object
1227 * @see javax.swing.table.TableColumn#setCellRenderer
1228 * @see #setDefaultRenderer
1229 */
1230 public TableCellRenderer getCellRenderer(final int row, final int column) {
1231 if (column < frozenColumns) {
1232 return lockedTable.getCellRenderer(row, column);
1233 } else {
1234 return scrollTable.getCellRenderer(row, column - frozenColumns);
1235 }
1236 }
1237
1238 /***
1239 * Returns true if both row and column selection models are enabled.
1240 * Equivalent to <code>getRowSelectionAllowed() &&
1241 * getColumnSelectionAllowed()</code>.
1242 *
1243 * @return true if both row and column selection models are enabled
1244 *
1245 * @see #setCellSelectionEnabled
1246 */
1247 public boolean getCellSelectionEnabled() {
1248 return lockedTable.getCellSelectionEnabled();
1249 }
1250
1251 /***
1252 * Returns the <code>TableColumn</code> object for the column in the table
1253 * whose identifier is equal to <code>identifier</code>, when compared using
1254 * <code>equals</code>.
1255 *
1256 * @param identifier the identifier object
1257 * @return the <code>TableColumn</code> object that matches the identifier
1258 * @exception IllegalArgumentException if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code>
1259 * has this identifier
1260 */
1261 public TableColumn getColumn(final Object identifier) throws IllegalArgumentException {
1262 try {
1263 return lockedTable.getColumn(identifier);
1264 } catch (IllegalArgumentException e) {
1265 return scrollTable.getColumn(identifier);
1266 }
1267 }
1268
1269 /***
1270 * Returns the type of the column appearing in the view at
1271 * column position <code>column</code>.
1272 *
1273 * @param column the column in the view being queried
1274 * @return the type of the column at position <code>column</code>
1275 * in the view where the first column is column 0
1276 */
1277 public Class getColumnClass(final int column) {
1278 if (column < frozenColumns) {
1279 return lockedTable.getColumnClass(column);
1280 } else {
1281 return scrollTable.getColumnClass(column - frozenColumns);
1282 }
1283 }
1284
1285 /***
1286 * Returns the number of columns in the column model. Note that this may
1287 * be different from the number of columns in the table model.
1288 *
1289 * @return the number of columns in the table
1290 * @see #getRowCount
1291 * @see #removeColumn
1292 */
1293 public int getColumnCount() {
1294 return lockedTable.getColumnCount() + scrollTable.getColumnCount();
1295 }
1296
1297 /***
1298 * Returns always false.
1299 *
1300 * @return true if columns can be selected, otherwise false
1301 */
1302 public boolean getColumnSelectionAllowed() {
1303 return false;
1304 }
1305
1306 /***
1307 * Returns the editor to be used when no editor has been set in
1308 * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
1309 * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1310 * there is no entry for this <code>columnClass</code> the method returns
1311 * the entry for the most specific superclass. The <code>JTable</code> installs entries
1312 * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1313 * or replaced.
1314 *
1315 * @param columnClass return the default cell editor for this columnClass
1316 * @return the default cell editor to be used for this columnClass
1317 * @see #setDefaultEditor
1318 * @see #getColumnClass
1319 */
1320 public TableCellEditor getDefaultEditor(final Class columnClass) {
1321 return lockedTable.getDefaultEditor(columnClass);
1322 }
1323
1324 /***
1325 * Returns the cell renderer to be used when no renderer has been set in
1326 * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
1327 * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1328 * there is no entry for this <code>columnClass</code> the method returns
1329 * the entry for the most specific superclass. The <code>JTable</code> installs entries
1330 * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1331 * or replaced.
1332 *
1333 * @param columnClass return the default cell renderer
1334 * for this columnClass
1335 * @return the renderer for this columnClass
1336 * @see #setDefaultRenderer
1337 * @see #getColumnClass
1338 */
1339 public TableCellRenderer getDefaultRenderer(final Class columnClass) {
1340 return lockedTable.getDefaultRenderer(columnClass);
1341 }
1342
1343 /***
1344 * Gets the value of the <code>dragEnabled</code> property.
1345 *
1346 * @return the value of the <code>dragEnabled</code> property
1347 * @see #setDragEnabled
1348 * @since JDK 1.4
1349 */
1350 public boolean getDragEnabled() {
1351 return lockedTable.getDragEnabled();
1352 }
1353
1354 /***
1355 * Returns the component that is handling the editing session.
1356 * If nothing is being edited, returns null.
1357 *
1358 * @return Component handling editing session
1359 */
1360 public Component getEditorComponent() {
1361 return lockedTable.getEditorComponent();
1362 }
1363
1364 /***
1365 * Returns the horizontal and vertical space between cells.
1366 * The default spacing is (1, 1), which provides room to draw the grid.
1367 *
1368 * @return the horizontal and vertical spacing between cells
1369 * @see #setIntercellSpacing
1370 */
1371 public Dimension getIntercellSpacing() {
1372 return lockedTable.getIntercellSpacing();
1373 }
1374
1375 /***
1376 * Returns the preferred size of the viewport for this table.
1377 *
1378 * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
1379 * which displays this table
1380 */
1381 public Dimension getPreferredScrollableViewportSize() {
1382 return scrollPane.getPreferredSize();
1383 }
1384
1385 /***
1386 * Returns the number of rows in this table's model.
1387 * @return the number of rows in this table's model
1388 *
1389 * @see #getColumnCount
1390 */
1391 public int getRowCount() {
1392 return lockedTable.getRowCount();
1393 }
1394
1395 /***
1396 * Returns the height of a table row, in pixels.
1397 * The default row height is 16.0.
1398 *
1399 * @return the height in pixels of a table row
1400 * @see #setRowHeight(int)
1401 */
1402 public int getRowHeight() {
1403 return lockedTable.getRowHeight();
1404 }
1405
1406 /***
1407 * Returns the height, in pixels, of the cells in <code>row</code>.
1408 * @param row the row whose height is to be returned
1409 * @return the height, in pixels, of the cells in the row
1410 */
1411 public int getRowHeight(final int row) {
1412 return lockedTable.getRowHeight(row);
1413 }
1414
1415 /***
1416 * Gets the amount of empty space, in pixels, between cells. Equivalent to:
1417 * <code>getIntercellSpacing().height</code>.
1418 * @return the number of pixels between cells in a row
1419 *
1420 * @see #setRowMargin
1421 */
1422 public int getRowMargin() {
1423 return lockedTable.getRowMargin();
1424 }
1425
1426 /***
1427 * Returns <code>visibleRect.height</code> or
1428 * <code>visibleRect.width</code>,
1429 * depending on this table's orientation. Note that as of Swing 1.1.1
1430 * (Java 2 v 1.2.2) the value
1431 * returned will ensure that the viewport is cleanly aligned on
1432 * a row boundary.
1433 *
1434 * @param visibleRect The view area visible within the viewport
1435 * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
1436 * @param direction Less than zero to scroll up/left, greater than zero for down/right.
1437 * @return <code>visibleRect.height</code> or
1438 * <code>visibleRect.width</code>
1439 * per the orientation
1440 * @see Scrollable#getScrollableBlockIncrement
1441 */
1442 public int getScrollableBlockIncrement(final Rectangle visibleRect, final int orientation, final int direction) {
1443 return scrollTable.getScrollableBlockIncrement(visibleRect, orientation, direction);
1444 }
1445
1446 /***
1447 * Returns false to indicate that the height of the viewport does not
1448 * determine the height of the table.
1449 *
1450 * @return false
1451 * @see Scrollable#getScrollableTracksViewportHeight
1452 */
1453 public boolean getScrollableTracksViewportHeight() {
1454 return scrollTable.getScrollableTracksViewportHeight();
1455 }
1456
1457 /***
1458 * Returns false if <code>autoResizeMode</code> is set to
1459 * <code>AUTO_RESIZE_OFF</code>, which indicates that the
1460 * width of the viewport does not determine the width
1461 * of the table. Otherwise returns true.
1462 *
1463 * @return false if <code>autoResizeMode</code> is set
1464 * to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
1465 * @see Scrollable#getScrollableTracksViewportWidth
1466 */
1467 public boolean getScrollableTracksViewportWidth() {
1468 return scrollTable.getScrollableTracksViewportWidth();
1469 }
1470
1471 /***
1472 * Returns the scroll increment (in pixels) that completely exposes one new
1473 * row or column (depending on the orientation).
1474 * <p>
1475 * This method is called each time the user requests a unit scroll.
1476 *
1477 * @param visibleRect the view area visible within the viewport
1478 * @param orientation either <code>SwingConstants.VERTICAL</code>
1479 * or <code>SwingConstants.HORIZONTAL</code>
1480 * @param direction less than zero to scroll up/left,
1481 * greater than zero for down/right
1482 * @return the "unit" increment for scrolling in the specified direction
1483 * @see Scrollable#getScrollableUnitIncrement
1484 */
1485 public int getScrollableUnitIncrement(final Rectangle visibleRect, final int orientation, final int direction) {
1486 return lockedTable.getScrollableUnitIncrement(visibleRect, orientation, direction);
1487 }
1488
1489 /***
1490 * Returns the background color for selected cells.
1491 *
1492 * @return the <code>Color</code> used for the background of selected list items
1493 * @see #setSelectionBackground
1494 * @see #setSelectionForeground
1495 */
1496 public Color getSelectionBackground() {
1497 return lockedTable.getSelectionBackground();
1498 }
1499
1500 /***
1501 * Returns the foreground color for selected cells.
1502 *
1503 * @return the <code>Color</code> object for the foreground property
1504 * @see #setSelectionForeground
1505 * @see #setSelectionBackground
1506 */
1507 public Color getSelectionForeground() {
1508 return lockedTable.getSelectionForeground();
1509 }
1510
1511 /***
1512 * Returns true if the table draws horizontal lines between cells, false if it
1513 * doesn't. The default is true.
1514 *
1515 * @return true if the table draws horizontal lines between cells, false if it
1516 * doesn't
1517 * @see #setShowHorizontalLines
1518 */
1519 public boolean getShowHorizontalLines() {
1520 return lockedTable.getShowHorizontalLines();
1521 }
1522
1523 /***
1524 * Returns true if the table draws vertical lines between cells, false if it
1525 * doesn't. The default is true.
1526 *
1527 * @return true if the table draws vertical lines between cells, false if it
1528 * doesn't
1529 * @see #setShowVerticalLines
1530 */
1531 public boolean getShowVerticalLines() {
1532 return lockedTable.getShowVerticalLines();
1533 }
1534
1535 /***
1536 * Returns true if the editor should get the focus
1537 * when keystrokes cause the editor to be activated.
1538 *
1539 * @return true if the editor should get the focus
1540 * when keystrokes cause the editor to be
1541 * activated
1542 *
1543 * @see #setSurrendersFocusOnKeystroke
1544 */
1545 public boolean getSurrendersFocusOnKeystroke() {
1546 return lockedTable.getSurrendersFocusOnKeystroke();
1547 }
1548
1549 /***
1550 * Moves the column <code>column</code> to the position currently
1551 * occupied by the column <code>targetColumn</code> in the view.
1552 * The old column at <code>targetColumn</code> is
1553 * shifted left or right to make room.
1554 *
1555 * @param column the index of column to be moved
1556 * @param targetColumn the new index of the column
1557 */
1558 public void moveColumn(final int column, final int targetColumn) {
1559 if (column < frozenColumns && targetColumn < frozenColumns) {
1560
1561 lockedTable.moveColumn(column, targetColumn);
1562 } else if (column < frozenColumns && targetColumn >= frozenColumns) {
1563
1564 final TableColumn tableColumn = lockedTable.getColumnModel().getColumn(column);
1565 lockedTable.removeColumn(tableColumn);
1566 scrollTable.addColumn(tableColumn);
1567 scrollTable.moveColumn(scrollTable.getColumnCount(), targetColumn - frozenColumns);
1568 } else if (column >= frozenColumns && targetColumn < frozenColumns) {
1569
1570 final TableColumn tableColumn = scrollTable.getColumnModel().getColumn(column);
1571 scrollTable.removeColumn(tableColumn);
1572 lockedTable.addColumn(tableColumn);
1573 lockedTable.moveColumn(lockedTable.getColumnCount(), targetColumn);
1574 } else {
1575
1576 scrollTable.moveColumn(column, targetColumn);
1577 }
1578 }
1579
1580 /***
1581 * Prepares the renderer by querying the data model for the
1582 * value and selection state
1583 * of the cell at <code>row</code>, <code>column</code>.
1584 * Returns the component (may be a <code>Component</code>
1585 * or a <code>JComponent</code>) under the event location.
1586 * <p>
1587 * <b>Note:</b>
1588 * Throughout the table package, the internal implementations always
1589 * use this method to prepare renderers so that this default behavior
1590 * can be safely overridden by a subclass.
1591 *
1592 * @param renderer the <code>TableCellRenderer</code> to prepare
1593 * @param row the row of the cell to render, where 0 is the first row
1594 * @param column the column of the cell to render,
1595 * where 0 is the first column
1596 * @return the <code>Component</code> under the event location
1597 * TODO handle the renderer correctly across the KTables
1598 */
1599 public Component prepareRenderer(final TableCellRenderer renderer, final int row, final int column) {
1600 if (column < frozenColumns) {
1601 return lockedTable.prepareRendererSuper(renderer, row, column);
1602 } else {
1603 return scrollTable.prepareRendererSuper(renderer, row, column - frozenColumns);
1604 }
1605 }
1606
1607 /***
1608 * Removes <code>aColumn</code> from this <code>JTable</code>'s array
1609 * of columns. Note: this method does not remove the column of data from the
1610 * model; it just removes the <code>TableColumn</code> that was
1611 * responsible for displaying it.
1612 * @param aColumn the <code>TableColumn</code> to be removed
1613 * @see #addColumn
1614 */
1615 public void removeColumn(final TableColumn aColumn) {
1616 lockedTable.removeColumn(aColumn);
1617 scrollTable.removeColumn(aColumn);
1618 }
1619
1620 /***
1621 * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
1622 *
1623 * @param index0 one end of the interval
1624 * @param index1 the other end of the interval
1625 */
1626 public void removeColumnSelectionInterval(final int index0, final int index1) {
1627 lockedTable.removeColumnSelectionInterval(index0, index1);
1628 scrollTable.removeColumnSelectionInterval(index0, index1);
1629 }
1630
1631 /***
1632 * Discards the editor object and frees the real estate it used for
1633 * cell rendering.
1634 */
1635 public void removeEditor() {
1636 lockedTable.removeEditor();
1637 scrollTable.removeEditor();
1638 }
1639
1640 /***
1641 * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
1642 *
1643 * @param index0 one end of the interval
1644 * @param index1 the other end of the interval
1645 */
1646 public void removeRowSelectionInterval(final int index0, final int index1) {
1647 lockedTable.removeRowSelectionInterval(index0, index1);
1648 }
1649
1650 /***
1651 * Returns the index of the row that <code>point</code> lies in,
1652 * or -1 if the result is not in the range
1653 * [0, <code>getRowCount()</code>-1].
1654 *
1655 * @param point the location of interest
1656 * @return the index of the row that <code>point</code> lies in,
1657 * or -1 if the result is not in the range
1658 * [0, <code>getRowCount()</code>-1]
1659 */
1660 public int rowAtPoint(final Point point) {
1661 return lockedTable.rowAtPoint(point);
1662 }
1663
1664 /***
1665 * Selects all rows, columns, and cells in the table.
1666 */
1667 public void selectAll() {
1668 lockedTable.selectAll();
1669 }
1670
1671 /***
1672 * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
1673 * This method calls <code>createDefaultColumnsFromModel</code> if
1674 * <code>autoCreateColumnsFromModel</code> changes from false to true.
1675 *
1676 * @param autoCreateColumnsFromModel true if <code>JTable</code> should automatically create columns
1677 * @see #getAutoCreateColumnsFromModel
1678 */
1679 public void setAutoCreateColumnsFromModel(final boolean autoCreateColumnsFromModel) {
1680 lockedTable.setAutoCreateColumnsFromModel(autoCreateColumnsFromModel);
1681 }
1682
1683 /***
1684 * Sets the table's auto resize mode when the table is resized.
1685 *
1686 * @param mode One of 5 legal values:
1687 * AUTO_RESIZE_OFF,
1688 * AUTO_RESIZE_NEXT_COLUMN,
1689 * AUTO_RESIZE_SUBSEQUENT_COLUMNS,
1690 * AUTO_RESIZE_LAST_COLUMN,
1691 * AUTO_RESIZE_ALL_COLUMNS
1692 */
1693 public void setAutoResizeMode(final int mode) {
1694 lockedTable.setAutoResizeMode(mode);
1695 scrollTable.setAutoResizeMode(mode);
1696 }
1697
1698 /***
1699 * Sets the <code>cellEditor</code> variable.
1700 *
1701 * @param anEditor the TableCellEditor that does the editing
1702 */
1703 public void setCellEditor(final TableCellEditor anEditor) {
1704 lockedTable.setCellEditor(anEditor);
1705 scrollTable.setCellEditor(anEditor);
1706 }
1707
1708 /***
1709 * Sets whether this table allows both a column selection and a
1710 * row selection to exist simultaneously. When set,
1711 * the table treats the intersection of the row and column selection
1712 * models as the selected cells. Override <code>isCellSelected</code> to
1713 * change this default behavior. This method is equivalent to setting
1714 * both the <code>rowSelectionAllowed</code> property and
1715 * <code>columnSelectionAllowed</code> property of the
1716 * <code>columnModel</code> to the supplied value.
1717 *
1718 * @param cellSelectionEnabled true if simultaneous row and column
1719 * selection is allowed
1720 * @see #getCellSelectionEnabled
1721 * @see #isCellSelected
1722 */
1723 public void setCellSelectionEnabled(final boolean cellSelectionEnabled) {
1724 lockedTable.setCellSelectionEnabled(cellSelectionEnabled);
1725 scrollTable.setCellSelectionEnabled(cellSelectionEnabled);
1726 }
1727
1728 /***
1729 * Sets a default cell editor to be used if no editor has been set in
1730 * a <code>TableColumn</code>. If no editing is required in a table, or a
1731 * particular column in a table, uses the <code>isCellEditable</code>
1732 * method in the <code>TableModel</code> interface to ensure that this
1733 * <code>JTable</code> will not start an editor in these columns.
1734 * If editor is <code>null</code>, removes the default editor for this
1735 * column class.
1736 *
1737 * @param columnClass set the default cell editor for this columnClass
1738 * @param editor default cell editor to be used for this columnClass
1739 * @see TableModel#isCellEditable
1740 * @see #getDefaultEditor
1741 * @see #setDefaultRenderer
1742 */
1743 public void setDefaultEditor(final Class columnClass, final TableCellEditor editor) {
1744 lockedTable.setDefaultEditor(columnClass, editor);
1745 scrollTable.setDefaultEditor(columnClass, editor);
1746 }
1747
1748 /***
1749 * Sets a default cell renderer to be used if no renderer has been set in
1750 * a <code>TableColumn</code>. If renderer is <code>null</code>,
1751 * removes the default renderer for this column class.
1752 *
1753 * @param columnClass set the default cell renderer for this columnClass
1754 * @param renderer default cell renderer to be used for this columnClass
1755 * @see #getDefaultRenderer
1756 * @see #setDefaultEditor
1757 */
1758 public void setDefaultRenderer(final Class columnClass, final TableCellRenderer renderer) {
1759 lockedTable.setDefaultRenderer(columnClass, renderer);
1760 scrollTable.setDefaultRenderer(columnClass, renderer);
1761 }
1762
1763 /***
1764 * Sets the <code>dragEnabled</code> property,
1765 * which must be <code>true</code> to enable
1766 * automatic drag handling (the first part of drag and drop)
1767 * on this component.
1768 * The <code>transferHandler</code> property needs to be set
1769 * to a non-<code>null</code> value for the drag to do
1770 * anything. The default value of the <code>dragEnabled</code>
1771 * property
1772 * is <code>false</code>.
1773 *
1774 * <p>
1775 *
1776 * When automatic drag handling is enabled,
1777 * most look and feels begin a drag-and-drop operation
1778 * whenever the user presses the mouse button over a selection
1779 * and then moves the mouse a few pixels.
1780 * Setting this property to <code>true</code>
1781 * can therefore have a subtle effect on
1782 * how selections behave.
1783 *
1784 * <p>
1785 *
1786 * Some look and feels might not support automatic drag and drop;
1787 * they will ignore this property. You can work around such
1788 * look and feels by modifying the component
1789 * to directly call the <code>exportAsDrag</code> method of a
1790 * <code>TransferHandler</code>.
1791 *
1792 * @param b the value to set the <code>dragEnabled</code> property to
1793 * @see #getDragEnabled
1794 * @since JDK 1.4
1795 */
1796 public void setDragEnabled(final boolean b) {
1797 lockedTable.setDragEnabled(b);
1798 scrollTable.setDragEnabled(b);
1799 }
1800
1801 /***
1802 * Sets the <code>editingColumn</code> variable.
1803 * @param aColumn the column of the cell to be edited
1804 */
1805 public void setEditingColumn(final int aColumn) {
1806 if (aColumn < frozenColumns) {
1807 lockedTable.setEditingColumn(aColumn);
1808 } else {
1809 scrollTable.setEditingColumn(aColumn - frozenColumns);
1810 }
1811 }
1812
1813 /***
1814 * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
1815 * the height and width of the space between cells -- to
1816 * <code>intercellSpacing</code>.
1817 *
1818 * @param intercellSpacing a <code>Dimension</code>
1819 * specifying the new width
1820 * and height between cells
1821 * @see #getIntercellSpacing
1822 */
1823 public void setIntercellSpacing(final Dimension intercellSpacing) {
1824 lockedTable.setIntercellSpacing(intercellSpacing);
1825 }
1826
1827 /***
1828 * Sets the data model for this table to <code>newModel</code> and registers
1829 * with it for listener notifications from the new data model.
1830 *
1831 * @param dataModel the new data source for this table
1832 * @see #getModel
1833 */
1834 public void setModel(final TableModel dataModel) {
1835
1836 final TableColumnModel scrollColumnModel = scrollTable.getColumnModel();
1837 while (scrollColumnModel.getColumnCount() > 0) {
1838 scrollColumnModel.removeColumn(scrollColumnModel.getColumn(0));
1839 }
1840
1841 final TableColumnModel lockedColumnModel = lockedTable.getColumnModel();
1842 while (lockedTable.getColumnCount() > 0) {
1843 lockedColumnModel.removeColumn(lockedColumnModel.getColumn(0));
1844 }
1845 lockedTable.setModel(dataModel);
1846 scrollTable.setModel(dataModel);
1847
1848 lockedTable.createDefaultColumnsFromModel();
1849 scrollTable.createDefaultColumnsFromModel();
1850
1851 if (frozenColumns > dataModel.getColumnCount()) {
1852 frozenColumns = dataModel.getColumnCount();
1853 }
1854
1855 for (int i = 0; i < frozenColumns; i++) {
1856 scrollColumnModel.removeColumn(scrollColumnModel.getColumn(0));
1857 }
1858
1859 while (lockedTable.getColumnCount() > frozenColumns) {
1860 lockedColumnModel.removeColumn(lockedColumnModel.getColumn(frozenColumns));
1861 }
1862
1863 for (int i = 0; i < lockedColumnModel.getColumnCount(); i++) {
1864 lockedColumnModel.getColumn(i).addPropertyChangeListener(new ColumnWidthChangeListener());
1865 }
1866 }
1867
1868 /***
1869 * Sets the preferred size of the viewport for this table.
1870 *
1871 * @param size a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
1872 * <code>JViewport</code> whose view is this table
1873 * @see Scrollable#getPreferredScrollableViewportSize
1874 */
1875 public void setPreferredScrollableViewportSize(final Dimension size) {
1876 scrollTable.setPreferredScrollableViewportSize(size);
1877 }
1878
1879 /***
1880 * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
1881 * revalidates, and repaints.
1882 * The height of the cells will be equal to the row height minus
1883 * the row margin.
1884 *
1885 * @param rowHeight new row height
1886 * @see #getRowHeight()
1887 */
1888 public void setRowHeight(final int rowHeight) {
1889 lockedTable.setRowHeight(rowHeight);
1890 scrollTable.setRowHeight(rowHeight);
1891 }
1892
1893 /***
1894 * Sets the height for <code>row</code> to <code>rowHeight</code>,
1895 * revalidates, and repaints. The height of the cells in this row
1896 * will be equal to the row height minus the row margin.
1897 *
1898 * @param row the row whose height is being changed
1899 * @param rowHeight new row height, in pixels
1900 */
1901 public void setRowHeight(final int row, final int rowHeight) {
1902 lockedTable.setRowHeight(row, rowHeight);
1903 scrollTable.setRowHeight(row, rowHeight);
1904 }
1905
1906 /***
1907 * Sets the amount of empty space between cells in adjacent rows.
1908 *
1909 * @param rowMargin the number of pixels between cells in a row
1910 * @see #getRowMargin
1911 */
1912 public void setRowMargin(final int rowMargin) {
1913 lockedTable.setRowMargin(rowMargin);
1914 scrollTable.setRowMargin(rowMargin);
1915 }
1916
1917 /***
1918 * Selects the rows from <code>index0</code> to <code>index1</code>,
1919 * inclusive.
1920 *
1921 * @param index0 one end of the interval
1922 * @param index1 the other end of the interval
1923 */
1924 public void setRowSelectionInterval(final int index0, final int index1) {
1925 lockedTable.setRowSelectionInterval(index0, index1);
1926 scrollTable.setRowSelectionInterval(index0, index1);
1927 }
1928
1929 /***
1930 * Sets the row selection model for this table to <code>newModel</code>
1931 * and registers for listener notifications from the new selection model.
1932 *
1933 * @param newModel the new selection model
1934 * @see #getSelectionModel
1935 */
1936 public void setSelectionModel(final ListSelectionModel newModel) {
1937 lockedTable.setSelectionModel(newModel);
1938 scrollTable.setSelectionModel(newModel);
1939 }
1940
1941 /***
1942 * Sets whether editors in this JTable get the keyboard focus
1943 * when an editor is activated as a result of the JTable
1944 * forwarding keyboard events for a cell.
1945 * By default, this property is false, and the JTable
1946 * retains the focus unless the cell is clicked.
1947 *
1948 * @param surrendersFocusOnKeystroke true if the editor should get the focus
1949 * when keystrokes cause the editor to be
1950 * activated
1951 *
1952 *
1953 * @see #getSurrendersFocusOnKeystroke
1954 */
1955 public void setSurrendersFocusOnKeystroke(final boolean surrendersFocusOnKeystroke) {
1956 lockedTable.setSurrendersFocusOnKeystroke(surrendersFocusOnKeystroke);
1957 scrollTable.setSurrendersFocusOnKeystroke(surrendersFocusOnKeystroke);
1958 }
1959
1960 /***
1961 * Sizes the table columns to fit the available space.
1962 * @param lastColumnOnly
1963 * @deprecated As of Swing version 1.0.3,
1964 * replaced by <code>doLayout()</code>.
1965 * @see #doLayout()
1966 */
1967 public void sizeColumnsToFit(final boolean lastColumnOnly) {
1968 scrollTable.sizeColumnsToFit(lastColumnOnly);
1969 }
1970
1971 /***
1972 * Obsolete as of Java 2 platform v1.4. Please use the
1973 * <code>doLayout()</code> method instead.
1974 * @param resizingColumn the column whose resizing made this adjustment
1975 * necessary or -1 if there is no such column
1976 * @see #doLayout()
1977 */
1978 public void sizeColumnsToFit(final int resizingColumn) {
1979 scrollTable.sizeColumnsToFit(resizingColumn);
1980 }
1981
1982 /***
1983 * Returns the table header.
1984 *
1985 * @return table header
1986 */
1987 public JXTableHeader getTableHeader() {
1988 return collTableHeader;
1989 }
1990
1991 /***
1992 * @see javax.swing.JComponent#setFont(java.awt.Font)
1993 */
1994 public void setFont(final Font f) {
1995 final double f12 = 1d + (2d / (2d + 2d + 2d + 2d + 2d));
1996 lockedTable.setFont(f);
1997 scrollTable.setFont(f);
1998 final Graphics graphics = lockedTable.getGraphics();
1999 final int height;
2000 if (graphics != null) {
2001 final Rectangle2D rectangle2D = graphics.getFontMetrics(f).getMaxCharBounds(lockedTable.getGraphics());
2002 height = (int) (rectangle2D.getHeight() + 1);
2003 } else {
2004 height = (int) (f.getSize() * f12 + 2 * lockedTable.getRowMargin());
2005 }
2006 lockedTable.setRowHeight(height);
2007 scrollTable.setRowHeight(height);
2008 }
2009
2010 /***
2011 * Sets whether the columns in this model can be selected.
2012 *
2013 * @param b true if this model will allow column selection
2014 * @see #getColumnSelectionAllowed
2015 */
2016 public void setColumnSelectionAllowed(final boolean b) {
2017 lockedTable.setColumnSelectionAllowed(b);
2018 scrollTable.setColumnSelectionAllowed(b);
2019 }
2020
2021 /***
2022 * Returns the horizontal scrollbar of the table.
2023 *
2024 * @return the horizontal scrollbar
2025 */
2026 public JScrollBar getHorizontalScrollBar() {
2027 return scrollPane.getHorizontalScrollBar();
2028 }
2029
2030 /***
2031 * Returns the vertical scrollbar of the table.
2032 *
2033 * @return the vertical scrollbar
2034 */
2035 public JScrollBar getVerticalScrollBar() {
2036 return scrollPane.getVerticalScrollBar();
2037 }
2038
2039 /***
2040 * Determines when the horizontal scrollbar appears in the scrollpane.
2041 * The options are:<ul>
2042 * <li>JXTable.HORIZONTAL_SCROLLBAR_AS_NEEDED
2043 * <li>JXTable.HORIZONTAL_SCROLLBAR_NEVER
2044 * <li>JXTable.HORIZONTAL_SCROLLBAR_ALWAYS
2045 * </ul>
2046 *
2047 * @param policy one of the three values listed above
2048 * @see #getHorizontalScrollBarPolicy
2049 */
2050 public void setHorizontalScrollBarPolicy(final int policy) {
2051 scrollPane.setHorizontalScrollBarPolicy(policy);
2052 }
2053
2054 /***
2055 * Returns the horizontal scroll bar policy value.
2056 * @return the <code>horizontalScrollBarPolicy</code> property
2057 * @see #setHorizontalScrollBarPolicy
2058 */
2059 public int getHorizontalScrollBarPolicy() {
2060 return scrollPane.getHorizontalScrollBarPolicy();
2061 }
2062
2063 /***
2064 * Determines when the vertical scrollbar appears in the scrollpane.
2065 * Legal values are:
2066 * <ul>
2067 * <li>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
2068 * <li>JScrollPane.VERTICAL_SCROLLBAR_NEVER
2069 * <li>JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
2070 * </ul>
2071 *
2072 * @param policy one of the three values listed above
2073 * @throws IllegalArgumentException if <code>policy</code>
2074 * is not one of the legal values shown above
2075 * @see #getVerticalScrollBarPolicy
2076 */
2077 public void setVerticalScrollBarPolicy(final int policy) throws IllegalArgumentException {
2078 scrollPane.setVerticalScrollBarPolicy(policy);
2079 }
2080
2081 /***
2082 * Returns the vertical scroll bar policy value.
2083 * @return the <code>verticalScrollBarPolicy</code> property
2084 * @see #setVerticalScrollBarPolicy
2085 */
2086 public int getVerticalScrollBarPolicy() {
2087 return scrollPane.getVerticalScrollBarPolicy();
2088 }
2089
2090 /***
2091 * Action of <tt>Goto First</tt> key events in scrollable table.
2092 */
2093 private final class ScrollFirstAction extends AbstractAction {
2094 /*** the original action. */
2095 private final Action originalAction;
2096 /*** Contructor.
2097 * @param theOriginalAction the original action */
2098 private ScrollFirstAction(final Action theOriginalAction) {
2099 super();
2100 this.originalAction = theOriginalAction;
2101 }
2102 /*** @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */
2103 public void actionPerformed(final ActionEvent e) {
2104 if (e.getSource() == scrollTable && frozenColumns > 0 && scrollTable.getSelectedColumn() == 0) {
2105 scrollTable.transferFocusBackward();
2106 lockedTable.changeSelection(scrollTable.getSelectedRow(), 0, false, false);
2107 } else {
2108 originalAction.actionPerformed(e);
2109 }
2110 }
2111 }
2112
2113 /***
2114 * Action of <tt>Goto Last</tt> key events in locked table.
2115 */
2116 private final class LockedLastAction extends AbstractAction {
2117 /*** the original action. */
2118 private final Action originalAction;
2119 /*** Contructor.
2120 * @param theOriginalAction the original action */
2121 private LockedLastAction(final Action theOriginalAction) {
2122 super();
2123 this.originalAction = theOriginalAction;
2124 }
2125 /*** @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */
2126 public void actionPerformed(final ActionEvent e) {
2127 if (e.getSource() == lockedTable && scrollTable.getColumnCount() > 0
2128 && lockedTable.getSelectedColumn() == lockedTable.getColumnCount() - 1) {
2129 lockedTable.transferFocus();
2130 scrollTable.changeSelection(scrollTable.getSelectedRow(), scrollTable.getColumnCount() - 1, false, false);
2131 } else {
2132 originalAction.actionPerformed(e);
2133 }
2134 }
2135 }
2136
2137 /***
2138 * Action of <tt>Next</tt> key events in locked table.
2139 */
2140 private final class LockedNextAction extends AbstractAction {
2141 /*** the original action. */
2142 private final Action originalAction;
2143 /*** Contructor.
2144 * @param theOriginalAction the original action */
2145 private LockedNextAction(final Action theOriginalAction) {
2146 super();
2147 this.originalAction = theOriginalAction;
2148 }
2149 /*** @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */
2150 public void actionPerformed(final ActionEvent e) {
2151 if (lockedTable.getSelectedColumn() == lockedTable.getColumnCount() - 1 && scrollTable.getColumnCount() > 0) {
2152 lockedTable.transferFocus();
2153 scrollTable.changeSelection(lockedTable.getSelectedRow(), 0, false, false);
2154 } else {
2155 originalAction.actionPerformed(e);
2156 }
2157 }
2158 }
2159
2160 /***
2161 * Action of <tt>Next</tt> key events in scrollable table.
2162 */
2163 private final class ScrollNextAction extends AbstractAction {
2164 /*** the original action. */
2165 private final Action originalAction;
2166 /*** Contructor.
2167 * @param theOriginalAction the original action */
2168 private ScrollNextAction(final Action theOriginalAction) {
2169 super();
2170 this.originalAction = theOriginalAction;
2171 }
2172 /*** @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */
2173 public void actionPerformed(final ActionEvent e) {
2174 if (scrollTable.getSelectedColumn() == scrollTable.getColumnCount() - 1 && lockedTable.getColumnCount() > 0) {
2175 scrollTable.transferFocusBackward();
2176 lockedTable.changeSelection(nextRow(scrollTable), 0, false, false);
2177 } else {
2178 originalAction.actionPerformed(e);
2179 }
2180 }
2181 }
2182
2183 /***
2184 * Action of <tt>Previous</tt> key events in scrollable table.
2185 */
2186 private final class ScrollPreviousAction extends AbstractAction {
2187 /*** the original action. */
2188 private final Action originalAction;
2189 /*** Contructor.
2190 * @param theOriginalAction the original action */
2191 private ScrollPreviousAction(final Action theOriginalAction) {
2192 super();
2193 this.originalAction = theOriginalAction;
2194 }
2195 /*** @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */
2196 public void actionPerformed(final ActionEvent e) {
2197 if (scrollTable.getSelectedColumn() == 0 && frozenColumns > 0) {
2198 scrollTable.transferFocusBackward();
2199 lockedTable.changeSelection(scrollTable.getSelectedRow(), lockedTable.getColumnCount() - 1, false, false);
2200 } else {
2201 originalAction.actionPerformed(e);
2202 }
2203 }
2204 }
2205
2206 /***
2207 * Action of <tt>Previous</tt> key events in locked table.
2208 */
2209 private final class LockedPreviousAction extends AbstractAction {
2210 /*** the original action. */
2211 private final Action originalAction;
2212 /*** Contructor.
2213 * @param theOriginalAction the original action */
2214 private LockedPreviousAction(final Action theOriginalAction) {
2215 super();
2216 this.originalAction = theOriginalAction;
2217 }
2218 /*** @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */
2219 public void actionPerformed(final ActionEvent e) {
2220 if (lockedTable.getSelectedColumn() == 0 && scrollTable.getColumnCount() > 0) {
2221 lockedTable.transferFocus();
2222 scrollTable.changeSelection(previousRow(scrollTable), scrollTable.getColumnCount() - 1, false, false);
2223 } else {
2224 originalAction.actionPerformed(e);
2225 }
2226 }
2227 }
2228
2229 /***
2230 * @return the table column model
2231 */
2232 public TableColumnModel getColumnModel() {
2233 return columnModel;
2234 }
2235
2236 /***
2237 * Sets the column model for this table to <code>newModel</code> and registers
2238 * for listener notifications from the new column model. Also sets
2239 * the column model of the <code>JTableHeader</code> to <code>columnModel</code>.
2240 *
2241 * @param cm the new data source for this table
2242 * @exception IllegalArgumentException if <code>columnModel</code> is <code>null</code>
2243 * @see #getColumnModel
2244 */
2245 public void setColumnModel(final TableColumnModel cm) throws IllegalArgumentException {
2246 if (columnModel == null) {
2247 throw new IllegalArgumentException("Cannot set a null ColumnModel");
2248 }
2249 columnModel = cm;
2250 final TableColumnModel cm1 = this.createDefaultColumnModel();
2251 final TableColumnModel cm2 = this.createDefaultColumnModel();
2252 for (int i = 0; i < cm.getColumnCount(); i++) {
2253 cm1.addColumn(cm.getColumn(i));
2254 cm2.addColumn(cm.getColumn(i));
2255 }
2256 lockedTable.setColumnModel(cm1);
2257 scrollTable.setColumnModel(cm2);
2258
2259 final TableColumnModel scrollColumnModel = scrollTable.getColumnModel();
2260 for (int i = 0; i < frozenColumns; i++) {
2261 scrollColumnModel.removeColumn(scrollColumnModel.getColumn(0));
2262 }
2263
2264 while (lockedTable.getColumnCount() > frozenColumns) {
2265 cm1.removeColumn(cm1.getColumn(frozenColumns));
2266 }
2267
2268 for (int i = 0; i < cm1.getColumnCount(); i++) {
2269 cm1.getColumn(i).addPropertyChangeListener(new ColumnWidthChangeListener());
2270 }
2271 }
2272
2273 /***
2274 * This fine grain notification tells listeners the exact range
2275 * of cells, rows, or columns that changed.
2276 *
2277 * @param e a tableModelEvent
2278 */
2279 public void tableChanged(final TableModelEvent e) {
2280 final int column = e.getColumn();
2281 if (column < frozenColumns) {
2282 lockedTable.tableChanged(e);
2283 } else {
2284 TableModelEvent event = new TableModelEvent((TableModel)
2285 e.getSource(), e.getFirstRow(), e.getLastRow(),
2286 e.getColumn() - frozenColumns, e.getType());
2287 scrollTable.tableChanged(event);
2288 }
2289 }
2290
2291 /***
2292 * Tells listeners that a column was moved due to a margin change.
2293 *
2294 * @param e a ChangeEvent
2295 */
2296 public void columnMarginChanged(final ChangeEvent e) {
2297 lockedTable.columnMarginChanged(e);
2298 scrollTable.columnMarginChanged(e);
2299 }
2300
2301 /***
2302 * Tells listeners that the selection model of the
2303 * TableColumnModel changed.
2304 *
2305 * @param e a ListSelectionEvent
2306 */
2307 public void columnSelectionChanged(final ListSelectionEvent e) {
2308 lockedTable.columnSelectionChanged(e);
2309 scrollTable.columnSelectionChanged(e);
2310 }
2311
2312 /***
2313 * Tells listeners that a column was added to the model.
2314 *
2315 * @param e a TableColumnModelEvent
2316 */
2317 public void columnAdded(final TableColumnModelEvent e) {
2318 lockedTable.columnAdded(e);
2319 scrollTable.columnAdded(e);
2320 }
2321
2322 /***
2323 * Tells listeners that a column was repositioned.
2324 *
2325 * @param e a TableColumnModelEvent
2326 */
2327 public void columnMoved(final TableColumnModelEvent e) {
2328 lockedTable.columnMoved(e);
2329 scrollTable.columnMoved(e);
2330 }
2331
2332 /***
2333 * Tells listeners that a column was removed from the model.
2334 *
2335 * @param e a TableColumnModelEvent
2336 */
2337 public void columnRemoved(final TableColumnModelEvent e) {
2338 final int from = e.getFromIndex();
2339 final int to = e.getToIndex();
2340 if (to < frozenColumns) {
2341 lockedTable.columnRemoved(e);
2342 } else if (from >= frozenColumns) {
2343 scrollTable.columnRemoved(e);
2344 } else {
2345 TableColumnModelEvent e1 = new TableColumnModelEvent((TableColumnModel) e.getSource(), from, frozenColumns - 1);
2346 TableColumnModelEvent e2 = new TableColumnModelEvent((TableColumnModel) e.getSource(), frozenColumns, to);
2347 lockedTable.columnRemoved(e1);
2348 scrollTable.columnRemoved(e2);
2349 }
2350 }
2351
2352 /***
2353 * Called whenever the value of the selection changes.
2354 * @param e the event that characterizes the change.
2355 */
2356 public void valueChanged(final ListSelectionEvent e) {
2357 lockedTable.valueChanged(e);
2358 scrollTable.valueChanged(e);
2359 }
2360
2361 /***
2362 * This tells the listeners the editor has canceled editing.
2363 *
2364 * @param e a ChangeEvent
2365 */
2366 public void editingCanceled(final ChangeEvent e) {
2367 lockedTable.superEditingCanceled(e);
2368 scrollTable.superEditingCanceled(e);
2369 }
2370
2371 /***
2372 * This tells the listeners the editor has ended editing.
2373 *
2374 * @param e a ChangeEvent
2375 */
2376 public void editingStopped(final ChangeEvent e) {
2377 lockedTable.superEditingStopped(e);
2378 scrollTable.superEditingStopped(e);
2379 }
2380
2381 /***
2382 * Sets the <code>tableHeader</code> working with this <code>JTable</code>
2383 * to <code>newHeader</code>.
2384 * It is legal to have a <code>null</code> <code>tableHeader</code>.
2385 *
2386 * @param newHeader new tableHeader
2387 * @see #getTableHeader
2388 */
2389 public void setTableHeader(final JXTableHeader newHeader) {
2390 if (collTableHeader != newHeader) {
2391 final JXTableHeader oldHeader = collTableHeader;
2392 if (oldHeader != null) {
2393 oldHeader.setTable(null);
2394 }
2395 collTableHeader = newHeader;
2396 lockedHeader = newHeader.getLockedHeader();
2397 scrollHeader = newHeader.getScrollHeader();
2398 lockedHeader.setColumnModel(lockedTable.getColumnModel());
2399 scrollHeader.setColumnModel(scrollTable.getColumnModel());
2400 lockedHeader.setTable(lockedTable);
2401 scrollHeader.setTable(scrollTable);
2402 lockedTable.setTableHeader(lockedHeader);
2403 scrollTable.setTableHeader(scrollHeader);
2404 scrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, lockedHeader);
2405 }
2406 }
2407
2408 /***
2409 * Returns the auto resize mode of the table. The default mode
2410 * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
2411 *
2412 * @return the autoResizeMode of the table
2413 *
2414 * @see #setAutoResizeMode(int)
2415 * @see #doLayout()
2416 */
2417 public int getAutoResizeMode() {
2418 return lockedTable.getAutoResizeMode();
2419 }
2420
2421 /***
2422 * Creates default columns for the table from
2423 * the data model using the <code>getColumnCount</code> method
2424 * defined in the <code>TableModel</code> interface.
2425 * <p>
2426 * Clears any existing columns before creating the
2427 * new columns based on information from the model.
2428 *
2429 * @see #getAutoCreateColumnsFromModel
2430 */
2431 public void createDefaultColumnsFromModel() {
2432 createDefaultLockedColumnsFromModel();
2433 createDefaultScrollColumnsFromModel();
2434 }
2435
2436 /***
2437 * Creates default columns for the locked table from
2438 * the data model using the <code>getColumnCount</code> method
2439 * defined in the <code>TableModel</code> interface.
2440 * <p>
2441 * Clears any existing columns before creating the
2442 * new columns based on information from the model.
2443 * <p>
2444 * If the model contains more than the number of frozen columns,
2445 * only the number of frozen columns is created.
2446 *
2447 * @see #getAutoCreateColumnsFromModel
2448 */
2449 private void createDefaultLockedColumnsFromModel() {
2450 final TableModel m = getModel();
2451 if (m != null) {
2452
2453 final TableColumnModel cm = lockedTable.getColumnModel();
2454 while (cm.getColumnCount() > 0) {
2455 cm.removeColumn(cm.getColumn(0));
2456 }
2457
2458 int columnCount = Math.min(frozenColumns - 1, m.getColumnCount());
2459 for (int i = 0; i < columnCount; i++) {
2460 TableColumn newColumn = new TableColumn(i);
2461 addColumn(newColumn);
2462 }
2463 }
2464 }
2465
2466 /***
2467 * Creates default columns for the scrollable table from
2468 * the data model using the <code>getColumnCount</code> method
2469 * defined in the <code>TableModel</code> interface and the number
2470 * of frozen columns .
2471 * <p>
2472 * Clears any existing columns before creating the
2473 * new columns based on information from the model.
2474 * <p>
2475 * If the model contains less than the number of frozen columns,
2476 * no columns are created.
2477 *
2478 * @see #getAutoCreateColumnsFromModel
2479 */
2480 private void createDefaultScrollColumnsFromModel() {
2481 TableModel m = getModel();
2482 if (m != null) {
2483
2484 TableColumnModel cm = scrollTable.getColumnModel();
2485 while (cm.getColumnCount() > 0) {
2486 cm.removeColumn(cm.getColumn(0));
2487 }
2488
2489 int columnCount = m.getColumnCount() - frozenColumns;
2490 if (columnCount > 0) {
2491 for (int i = frozenColumns; i < m.getColumnCount(); i++) {
2492 TableColumn newColumn = new TableColumn(i);
2493 addColumn(newColumn);
2494 }
2495 }
2496 }
2497 }
2498
2499 /***
2500 * Selects the columns from <code>index0</code> to <code>index1</code>,
2501 * inclusive.
2502 *
2503 * @param index0 one end of the interval
2504 * @param index1 the other end of the interval
2505 * @exception IllegalArgumentException if <code>index0</code> or
2506 * <code>index1</code> lie outside
2507 * [0, <code>getColumnCount()</code>-1]
2508 */
2509 public void setColumnSelectionInterval(final int index0, final int index1) throws IllegalArgumentException {
2510 if (index1 < frozenColumns) {
2511 final int count = scrollTable.getColumnCount();
2512 if (count > 0) {
2513 scrollTable.removeColumnSelectionInterval(0, count - 1);
2514 }
2515 lockedTable.setColumnSelectionInterval(index0, index1);
2516 } else if (index0 >= frozenColumns) {
2517 final int count = lockedTable.getColumnCount();
2518 if (count > 0) {
2519 lockedTable.removeColumnSelectionInterval(0, count - 1);
2520 }
2521 scrollTable.setColumnSelectionInterval(index0 - frozenColumns, index1 - frozenColumns);
2522 } else {
2523 lockedTable.setColumnSelectionInterval(index0, frozenColumns - 1);
2524 scrollTable.setColumnSelectionInterval(frozenColumns, index1 + frozenColumns);
2525 }
2526 }
2527
2528 /***
2529 * Adds the columns from <code>index0</code> to <code>index1</code>,
2530 * inclusive, to the current selection.
2531 *
2532 * @param index0 one end of the interval
2533 * @param index1 the other end of the interval
2534 * @exception IllegalArgumentException if <code>index0</code> or
2535 * <code>index1</code> lie outside
2536 * [0, <code>getColumnCount()</code>-1]
2537 */
2538 public void addColumnSelectionInterval(final int index0, final int index1) throws IllegalArgumentException {
2539 if (index1 < frozenColumns) {
2540 lockedTable.setColumnSelectionInterval(index0, index1);
2541 } else if (index0 >= frozenColumns) {
2542 scrollTable.addColumnSelectionInterval(index0 - frozenColumns, index1 - frozenColumns);
2543 } else {
2544 lockedTable.addColumnSelectionInterval(index0, frozenColumns - 1);
2545 scrollTable.addColumnSelectionInterval(frozenColumns, index1 + frozenColumns);
2546 }
2547 }
2548
2549 /***
2550 * Returns the index of the first selected column,
2551 * -1 if no column is selected.
2552 * @return the index of the first selected column
2553 */
2554 public int getSelectedColumn() {
2555 final int i = lockedTable.getSelectedColumn();
2556 return i == -1 ? frozenColumns + scrollTable.getSelectedColumn() : i;
2557 }
2558
2559 /***
2560 * Returns the indices of all selected columns.
2561 *
2562 * @return an array of integers containing the indices of all selected columns,
2563 * or an empty array if no column is selected
2564 * @see #getSelectedColumn
2565 */
2566 public int[] getSelectedColumns() {
2567 int[] i1 = lockedTable.getSelectedColumns();
2568 int[] i2 = scrollTable.getSelectedColumns();
2569 int[] i3 = new int[i1.length + i2.length];
2570 for (int i = 0; i < i1.length; i++) {
2571 i3[i] = i1[i];
2572 }
2573 for (int i = 0; i < i2.length; i++) {
2574 i3[i + i1.length] = i2[i] + frozenColumns;
2575 }
2576 return i3;
2577 }
2578
2579 /***
2580 * Returns the number of selected columns.
2581 *
2582 * @return the number of selected columns, 0 if no columns are selected
2583 */
2584 public int getSelectedColumnCount() {
2585 return lockedTable.getSelectedColumnCount() + scrollTable.getSelectedColumnCount();
2586 }
2587
2588 /***
2589 * Returns true if the column at the specified index is selected.
2590 *
2591 * @param column the column in the column model
2592 * @return true if the column at index <code>column</code> is selected, where
2593 * 0 is the first column
2594 * @exception IllegalArgumentException if <code>column</code> is not in the
2595 * valid range
2596 */
2597 public boolean isColumnSelected(final int column) throws IllegalArgumentException {
2598 return lockedTable.isColumnSelected(column) || scrollTable.isColumnSelected(column - frozenColumns);
2599 }
2600
2601 /***
2602 * Returns the index of the column that <code>point</code> lies in,
2603 * or -1 if the result is not in the range
2604 * [0, <code>getColumnCount()</code>-1].
2605 *
2606 * @param point the location of interest
2607 * @return the index of the column that <code>point</code> lies in,
2608 * or -1 if the result is not in the range
2609 * [0, <code>getColumnCount()</code>-1]
2610 * @see #rowAtPoint
2611 */
2612 public int columnAtPoint(final Point point) {
2613 int lockedWidth = lockedTable.getWidth();
2614 if (point.x < lockedWidth) {
2615 return lockedTable.columnAtPoint(point);
2616 } else {
2617 Point p = new Point(point.x - lockedWidth, point.y);
2618 return frozenColumns + scrollTable.columnAtPoint(p);
2619 }
2620 }
2621
2622 /***
2623 * Returns a rectangle for the cell that lies at the intersection of
2624 * <code>row</code> and <code>column</code>.
2625 * If <code>includeSpacing</code> is true then the value returned
2626 * has the full height and width of the row and column
2627 * specified. If it is false, the returned rectangle is inset by the
2628 * intercell spacing to return the true bounds of the rendering or
2629 * editing component as it will be set during rendering.
2630 * <p>
2631 * If the column index is valid but the row index is less
2632 * than zero the method returns a rectangle with the
2633 * <code>y</code> and <code>height</code> values set appropriately
2634 * and the <code>x</code> and <code>width</code> values both set
2635 * to zero. In general, when either the row or column indices indicate a
2636 * cell outside the appropriate range, the method returns a rectangle
2637 * depicting the closest edge of the closest cell that is within
2638 * the table's range. When both row and column indices are out
2639 * of range the returned rectangle covers the closest
2640 * point of the closest cell.
2641 * <p>
2642 * In all cases, calculations that use this method to calculate
2643 * results along one axis will not fail because of anomalies in
2644 * calculations along the other axis. When the cell is not valid
2645 * the <code>includeSpacing</code> parameter is ignored.
2646 *
2647 * @param row the row index where the desired cell
2648 * is located
2649 * @param column the column index where the desired cell
2650 * is located in the display; this is not
2651 * necessarily the same as the column index
2652 * in the data model for the table; the
2653 * {@link #convertColumnIndexToView(int)}
2654 * method may be used to convert a data
2655 * model column index to a display
2656 * column index
2657 * @param includeSpacing if false, return the true cell bounds -
2658 * computed by subtracting the intercell
2659 * spacing from the height and widths of
2660 * the column and row models
2661 *
2662 * @return the rectangle containing the cell at location
2663 * <code>row</code>,<code>column</code>
2664 */
2665 public Rectangle getCellRect(final int row, final int column, final boolean includeSpacing) {
2666 if (column < frozenColumns) {
2667 return lockedTable.getCellRect(row, column, includeSpacing);
2668 } else {
2669 return scrollTable.getCellRect(row, column - frozenColumns, includeSpacing);
2670 }
2671 }
2672
2673 /***
2674 * Returns the L&F object that renders this component.
2675 *
2676 * @return the <code>TableUI</code> object that renders this component
2677 */
2678 public TableUI getUI() {
2679 return lockedTable.getUI();
2680 }
2681
2682 /***
2683 * Sets the L&F object that renders this component and repaints.
2684 *
2685 * @param tableUi the TableUI L&F object
2686 * @see javax.swing.JTable#setUI(javax.swing.plaf.TableUI)
2687 */
2688 public void setUI(final TableUI tableUi) {
2689 lockedTable.setUI(tableUi);
2690 scrollTable.setUI(tableUi);
2691 }
2692
2693 /***
2694 * Prepares the editor by querying the data model for the value and
2695 * selection state of the cell at <code>row</code>, <code>column</code>.
2696 * <p>
2697 * <b>Note:</b>
2698 * Throughout the table package, the internal implementations always
2699 * use this method to prepare editors so that this default behavior
2700 * can be safely overridden by a subclass.
2701 *
2702 * @param editor the <code>TableCellEditor</code> to set up
2703 * @param row the row of the cell to edit,
2704 * where 0 is the first row
2705 * @param column the column of the cell to edit,
2706 * where 0 is the first column
2707 * @return the <code>Component</code> being edited
2708 */
2709 public Component prepareEditor(final TableCellEditor editor, final int row, final int column) {
2710 if (column < frozenColumns) {
2711 return lockedTable.prepareEditor(editor, row, column);
2712 } else {
2713 return scrollTable.prepareEditor(editor, row, column - frozenColumns);
2714 }
2715 }
2716
2717 /***
2718 * Appends <code>aColumn</code> after the currently last frozen column
2719 * held by this <code>JTable</code>'s column model.
2720 * If the column name of <code>aColumn</code> is <code>null</code>,
2721 * sets the column name of <code>aColumn</code> to the name
2722 * returned by <code>getModel().getColumnName()</code>.
2723 * <p>
2724 * The number of frozenn column is increased by one with a call to
2725 * this method.
2726 * <p>
2727 * To add a column to this <code>JTable</code> to display the
2728 * <code>modelColumn</code>'th column of data in the model with a
2729 * given <code>width</code>, <code>cellRenderer</code>,
2730 * and <code>cellEditor</code> you can use:
2731 * <pre>
2732 *
2733 * addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
2734 *
2735 * </pre>
2736 * [Any of the <code>TableColumn</code> constructors can be used
2737 * instead of this one.]
2738 * The model column number is stored inside the <code>TableColumn</code>
2739 * and is used during rendering and editing to locate the appropriates
2740 * data values in the model. The model column number does not change
2741 * when columns are reordered in the view.
2742 *
2743 * @param aColumn the <code>TableColumn</code> to be added
2744 * @see #removeColumn
2745 */
2746 public void addFrozenColumn(final TableColumn aColumn) {
2747 lockedTable.addColumn(aColumn);
2748 frozenColumns++;
2749 }
2750
2751 /***
2752 * Removes <code>aColumn</code> from this <code>JXTable</code>'s
2753 * frozen columns. Note: this method does not remove the column
2754 * of data from the model; it just removes the frozen
2755 * <code>TableColumn</code> that was responsible for displaying it.
2756 * <p>
2757 * The number of frozenn column is decreased by one with a call to
2758 * this method.
2759 *
2760 * @param aColumn the <code>TableColumn</code> to be removed
2761 * @see #addFrozenColumn
2762 */
2763 public void removeFrozenColumn(final TableColumn aColumn) {
2764 lockedTable.removeColumn(aColumn);
2765 frozenColumns++;
2766 }
2767
2768 /***
2769 * Returns the scroll pane adjuster.
2770 * @return the scroll pane adjuster
2771 */
2772 protected JScrollPaneAdjuster getAdjuster() {
2773 return adjuster;
2774 }
2775
2776 /***
2777 * Sets the <code>transferHandler</code> property,
2778 * which is <code>null</code> if the component does
2779 * not support data transfer operations.
2780 * <p>
2781 * If <code>newHandler</code> is not null, and the system property
2782 * <code>suppressSwingDropSupport</code> is not true, this will
2783 * install a <code>DropTarget</code> on the <code>JComponent</code>.
2784 * The default for the system property is false, so that a
2785 * <code>DropTarget</code> will be added.
2786 *
2787 * @param newHandler mechanism for transfer of data to
2788 * and from the component
2789 *
2790 * @see TransferHandler
2791 * @see javax.swing.JComponent#setTransferHandler(javax.swing.TransferHandler)
2792 */
2793 public void setTransferHandler(final TransferHandler newHandler) {
2794
2795 getLockedTable().setTransferHandler(newHandler);
2796 getScrollTable().setTransferHandler(newHandler);
2797 }
2798
2799 /***
2800 * Gets the <code>transferHandler</code> property.
2801 *
2802 * @return the value of the <code>transferHandler</code> property
2803 *
2804 * @see TransferHandler
2805 * @see #setTransferHandler
2806 */
2807 public TransferHandler getTransferHandler() {
2808
2809 return getLockedTable().getTransferHandler();
2810 }
2811
2812 /***
2813 * Adds the specified mouse listener to receive mouse events from this
2814 * component. If listener <code>l</code> is <code>null</code>, no
2815 * exception is thrown and no action is performed.
2816 * @param l the mouse listener
2817 * @see java.awt.event.MouseEvent
2818 * @see java.awt.event.MouseListener
2819 * @see #removeMouseListener
2820 * @see #getMouseListeners
2821 *
2822 * @see java.awt.Component#addMouseListener(java.awt.event.MouseListener)
2823 */
2824 public synchronized void addMouseListener(final MouseListener l) {
2825 if (l == null) {
2826 return;
2827 }
2828 mouseListener = AWTEventMulticaster.add(mouseListener, l);
2829 scrollTable.addMouseListener(new JXMouseMultiListener(l, KTable.TYPE_SCROLL));
2830 lockedTable.addMouseListener(new JXMouseMultiListener(l, KTable.TYPE_LOCKED));
2831 }
2832
2833 /***
2834 * Removes the specified mouse listener so that it no longer
2835 * receives mouse events from this component. This method performs
2836 * no function, nor does it throw an exception, if the listener
2837 * specified by the argument was not previously added to this component.
2838 * If listener <code>l</code> is <code>null</code>,
2839 * no exception is thrown and no action is performed.
2840 *
2841 * @param l the mouse listener
2842 * @see java.awt.event.MouseEvent
2843 * @see java.awt.event.MouseListener
2844 * @see #addMouseListener
2845 * @see #getMouseListeners
2846 * @see java.awt.Component#removeMouseListener(java.awt.event.MouseListener)
2847 */
2848 public synchronized void removeMouseListener(final MouseListener l) {
2849 if (l == null) {
2850 return;
2851 }
2852 mouseListener = AWTEventMulticaster.remove(mouseListener, l);
2853 }
2854
2855 /***
2856 * Returns an array of all the mouse listeners
2857 * registered on this component.
2858 *
2859 * @return all of this component's <code>MouseListener</code>s
2860 * or an empty array if no mouse
2861 * listeners are currently registered
2862 *
2863 * @see #addMouseListener
2864 * @see #removeMouseListener
2865 * @since 1.4
2866 * @see java.awt.Component#getMouseListeners()
2867 */
2868 public synchronized MouseListener[] getMouseListeners() {
2869 return (MouseListener[]) getListeners(MouseListener.class);
2870 }
2871
2872 /***
2873 * Adds the specified mouse motion listener to receive mouse motion
2874 * events from this component.
2875 * If listener <code>l</code> is <code>null</code>,
2876 * no exception is thrown and no action is performed.
2877 *
2878 * @param l the mouse motion listener
2879 * @see java.awt.event.MouseEvent
2880 * @see java.awt.event.MouseMotionListener
2881 * @see #removeMouseMotionListener
2882 * @see #getMouseMotionListeners
2883 * @see java.awt.Component#addMouseMotionListener(java.awt.event.MouseMotionListener)
2884 */
2885 public synchronized void addMouseMotionListener(final MouseMotionListener l) {
2886 if (l == null) {
2887 return;
2888 }
2889 mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener, l);
2890 scrollTable.addMouseMotionListener(new JXMouseMultiListener(l, KTable.TYPE_SCROLL));
2891 lockedTable.addMouseMotionListener(new JXMouseMultiListener(l, KTable.TYPE_LOCKED));
2892 }
2893
2894 /***
2895 * Removes the specified mouse motion listener so that it no longer
2896 * receives mouse motion events from this component. This method performs
2897 * no function, nor does it throw an exception, if the listener
2898 * specified by the argument was not previously added to this component.
2899 * If listener <code>l</code> is <code>null</code>,
2900 * no exception is thrown and no action is performed.
2901 *
2902 * @param l the mouse motion listener
2903 * @see java.awt.event.MouseEvent
2904 * @see java.awt.event.MouseMotionListener
2905 * @see #addMouseMotionListener
2906 * @see #getMouseMotionListeners
2907 * @see java.awt.Component#removeMouseMotionListener(java.awt.event.MouseMotionListener)
2908 */
2909 public synchronized void removeMouseMotionListener(final MouseMotionListener l) {
2910 if (l == null) {
2911 return;
2912 }
2913 mouseMotionListener = AWTEventMulticaster.remove(mouseMotionListener, l);
2914 }
2915
2916 /***
2917 * Returns an array of all the mouse motion listeners
2918 * registered on this component.
2919 *
2920 * @return all of this component's <code>MouseMotionListener</code>s
2921 * or an empty array if no mouse motion
2922 * listeners are currently registered
2923 *
2924 * @see #addMouseMotionListener
2925 * @see #removeMouseMotionListener
2926 * @see java.awt.Component#getMouseMotionListeners()
2927 */
2928 public synchronized MouseMotionListener[] getMouseMotionListeners() {
2929 return (MouseMotionListener[]) getListeners(MouseMotionListener.class);
2930 }
2931
2932 /***
2933 * Adds the specified mouse wheel listener to receive mouse wheel events
2934 * from this component. Containers also receive mouse wheel events from
2935 * sub-components.
2936 * If l is null, no exception is thrown and no action is performed.
2937 *
2938 * @param l the mouse wheel listener.
2939 * @see java.awt.event.MouseWheelEvent
2940 * @see java.awt.event.MouseWheelListener
2941 * @see #removeMouseWheelListener
2942 * @see #getMouseWheelListeners
2943 * @see java.awt.Component#addMouseWheelListener(java.awt.event.MouseWheelListener)
2944 */
2945 public synchronized void addMouseWheelListener(final MouseWheelListener l) {
2946 if (l == null) {
2947 return;
2948 }
2949 mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener, l);
2950 scrollTable.addMouseWheelListener(new JXMouseMultiListener(l, KTable.TYPE_SCROLL));
2951 lockedTable.addMouseWheelListener(new JXMouseMultiListener(l, KTable.TYPE_LOCKED));
2952 }
2953
2954 /***
2955 * Removes the specified mouse wheel listener so that it no longer
2956 * receives mouse wheel events from this component. This method performs
2957 * no function, nor does it throw an exception, if the listener
2958 * specified by the argument was not previously added to this component.
2959 * If l is null, no exception is thrown and no action is performed.
2960 *
2961 * @param l the mouse wheel listener.
2962 * @see java.awt.event.MouseWheelEvent
2963 * @see java.awt.event.MouseWheelListener
2964 * @see #addMouseWheelListener
2965 * @see #getMouseWheelListeners
2966 * @see java.awt.Component#removeMouseWheelListener(java.awt.event.MouseWheelListener)
2967 */
2968 public synchronized void removeMouseWheelListener(final MouseWheelListener l) {
2969 if (l == null) {
2970 return;
2971 }
2972 mouseWheelListener = AWTEventMulticaster.remove(mouseWheelListener, l);
2973 }
2974
2975 /***
2976 * Returns an array of all the mouse wheel listeners
2977 * registered on this component.
2978 *
2979 * @return all of this component's <code>MouseWheelListener</code>s
2980 * or an empty array if no mouse wheel
2981 * listeners are currently registered
2982 *
2983 * @see #addMouseWheelListener
2984 * @see #removeMouseWheelListener
2985 * @see java.awt.Component#getMouseWheelListeners()
2986 */
2987 public synchronized MouseWheelListener[] getMouseWheelListeners() {
2988 return (MouseWheelListener[]) getListeners(MouseWheelListener.class);
2989 }
2990
2991 /***
2992 * Returns an array of all the objects currently registered
2993 * as <code><em>Foo</em>Listener</code>s
2994 * upon this <code>Component</code>.
2995 * <code><em>Foo</em>Listener</code>s are registered using the
2996 * <code>add<em>Foo</em>Listener</code> method.
2997 *
2998 * <p>
2999 * You can specify the <code>listenerType</code> argument
3000 * with a class literal, such as
3001 * <code><em>Foo</em>Listener.class</code>.
3002 * For example, you can query a
3003 * <code>Component</code> <code>c</code>
3004 * for its mouse listeners with the following code:
3005 *
3006 * <pre>MouseListener[] mls = (MouseListener[])(c.getListeners(MouseListener.class));</pre>
3007 *
3008 * If no such listeners exist, this method returns an empty array.
3009 *
3010 * @param listenerType the type of listeners requested; this parameter
3011 * should specify an interface that descends from
3012 * <code>java.util.EventListener</code>
3013 * @return an array of all objects registered as
3014 * <code><em>Foo</em>Listener</code>s on this component,
3015 * or an empty array if no such listeners have been added
3016 *
3017 * @see #getMouseListeners
3018 */
3019 public EventListener[] getListeners(final Class listenerType) {
3020 final EventListener l;
3021 if (listenerType == MouseListener.class) {
3022 l = mouseListener;
3023 } else if (listenerType == MouseMotionListener.class) {
3024 l = mouseMotionListener;
3025 } else if (listenerType == MouseWheelListener.class) {
3026 l = mouseWheelListener;
3027 } else {
3028 return super.getListeners(listenerType);
3029 }
3030 return AWTEventMulticaster.getListeners(l, listenerType);
3031 }
3032
3033 /***
3034 * @see javax.swing.JComponent#setBackground(java.awt.Color)
3035 */
3036 public void setBackground(final Color bg) {
3037 scrollPane.setBackground(bg);
3038 }
3039
3040 /***
3041 * @see javax.swing.JComponent#setOpaque(boolean)
3042 */
3043 public void setOpaque(final boolean isOpaque) {
3044 scrollPane.setOpaque(isOpaque);
3045 }
3046
3047 /***
3048 * Internal mouse listener delegate for all three mouse listener interfaces.
3049 */
3050 private final class JXMouseMultiListener implements MouseListener, MouseMotionListener, MouseWheelListener {
3051
3052 /*** Reference to the enclosing mouse listener. */
3053 private final transient EventListener parentEventListener;
3054
3055 /*** Type of tabel, can be {@link KTable#TYPE_LOCKED}, {@link KTable#TYPE_SCROLL} or {@link KTable#TYPE_NONE}. */
3056 private final int tableType;
3057
3058 /***
3059 * Constructor.
3060 * @param l mouse listener of sourrounding JTable
3061 * @param type table tye ({@link KTable#TYPE_LOCKED} or {@link KTable#TYPE_SCROLL})
3062 */
3063 private JXMouseMultiListener(final EventListener l, final int type) {
3064 super();
3065 parentEventListener = l;
3066 tableType = type;
3067 }
3068
3069 /***
3070 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
3071 */
3072 public void mouseClicked(final MouseEvent e) {
3073 ((MouseListener) parentEventListener).mouseClicked(translateMouseEvent(e));
3074 }
3075
3076 /***
3077 * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
3078 */
3079 public void mouseEntered(final MouseEvent e) {
3080 ((MouseListener) parentEventListener).mouseEntered(translateMouseEvent(e));
3081 }
3082
3083 /***
3084 * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
3085 */
3086 public void mouseExited(final MouseEvent e) {
3087 ((MouseListener) parentEventListener).mouseExited(translateMouseEvent(e));
3088 }
3089
3090 /***
3091 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
3092 */
3093 public void mousePressed(final MouseEvent e) {
3094 ((MouseListener) parentEventListener).mousePressed(translateMouseEvent(e));
3095 }
3096
3097 /***
3098 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
3099 */
3100 public void mouseReleased(final MouseEvent e) {
3101 ((MouseListener) parentEventListener).mouseReleased(translateMouseEvent(e));
3102 }
3103
3104 /***
3105 * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
3106 */
3107 public void mouseDragged(final MouseEvent e) {
3108 ((MouseMotionListener) parentEventListener).mouseDragged(translateMouseEvent(e));
3109 }
3110
3111 /***
3112 * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
3113 */
3114 public void mouseMoved(final MouseEvent e) {
3115 ((MouseMotionListener) parentEventListener).mouseMoved(translateMouseEvent(e));
3116 }
3117
3118 /***
3119 * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent)
3120 */
3121 public void mouseWheelMoved(final MouseWheelEvent e) {
3122 ((MouseWheelListener) parentEventListener).mouseWheelMoved(translateMouseWheelEvent(e));
3123 }
3124
3125 /***
3126 * Translates the coordinates of a KTable's mouse event into
3127 * coordinated of the surrounding JTable.
3128 *
3129 * @param e mouse event of KTable
3130 * @return mouse event for JTable
3131 */
3132 private MouseEvent translateMouseEvent(final MouseEvent e) {
3133 final int x;
3134 if (tableType == KTable.TYPE_LOCKED) {
3135 x = e.getX();
3136 } else {
3137 x = e.getX() + lockedTable.getWidth();
3138 }
3139 return new MouseEvent(
3140 e.getComponent(), e.getID(), e.getWhen(), e.getModifiers(), x, e.getY(),
3141 e.getClickCount(), e.isPopupTrigger(), e.getButton());
3142 }
3143
3144 /***
3145 * Translates the coordinates of a KTable's mouse wheel event into
3146 * coordinated of the surrounding JTable.
3147 *
3148 * @param e mouse event of KTable
3149 * @return mouse event for JTable
3150 */
3151 private MouseWheelEvent translateMouseWheelEvent(final MouseWheelEvent e) {
3152 final int x;
3153 if (tableType == KTable.TYPE_LOCKED) {
3154 x = e.getX();
3155 } else {
3156 x = e.getX() + lockedTable.getWidth();
3157 }
3158 return new MouseWheelEvent(
3159 e.getComponent(), e.getID(), e.getWhen(), e.getModifiers(), x, e.getY(),
3160 e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation());
3161 }
3162 }
3163
3164 /***
3165 * @see javax.swing.JScrollPane#setUI(javax.swing.plaf.ScrollPaneUI)
3166 */
3167 public void setScrollPaneUI(final ScrollPaneUI scrollpaneui) {
3168 scrollPane.setUI(scrollpaneui);
3169 }
3170 }