History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/plaf/basic/BasicTableHeaderUI.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/plaf/basic/BasicTableHeaderUI.java+961−0
@@ -0,0 +1,961 @@
1/*
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.swing.plaf.basic;
27
28import java.awt.*;
29import java.awt.event.*;
30import java.util.*;
31import javax.swing.*;
32import javax.swing.event.*;
33import javax.swing.plaf.*;
34import javax.swing.table.*;
35
36import sun.swing.*;
37
38/**
39 * BasicTableHeaderUI implementation
40 *
41 * @author Alan Chung
42 * @author Philip Milne
43 */
44public class BasicTableHeaderUI extends TableHeaderUI {
45
46 private static Cursor resizeCursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
47
48//
49// Instance Variables
50//
51
52 /** The JTableHeader that is delegating the painting to this UI. */
53 protected JTableHeader header;
54 protected CellRendererPane rendererPane;
55
56 // Listeners that are attached to the JTable
57 protected MouseInputListener mouseInputListener;
58
59 // The column header over which the mouse currently is.
60 private int rolloverColumn = -1;
61
62 // The column that should be highlighted when the table header has the focus.
63 private int selectedColumnIndex = 0; // Read ONLY via getSelectedColumnIndex!
64
65 private static FocusListener focusListener = new FocusListener() {
66 public void focusGained(FocusEvent e) {
67 repaintHeader(e.getSource());
68 }
69
70 public void focusLost(FocusEvent e) {
71 repaintHeader(e.getSource());
72 }
73
74 private void repaintHeader(Object source) {
75 if (source instanceof JTableHeader) {
76 JTableHeader th = (JTableHeader)source;
77 BasicTableHeaderUI ui =
78 (BasicTableHeaderUI)BasicLookAndFeel.
79 getUIOfType(th.getUI(),
80 BasicTableHeaderUI.class);
81 if (ui == null) {
82 return;
83 }
84
85 th.repaint(th.getHeaderRect(ui.getSelectedColumnIndex()));
86 }
87 }
88 };
89
90 /**
91 * This class should be treated as a "protected" inner class.
92 * Instantiate it only within subclasses of {@code BasicTableHeaderUI}.
93 */
94 public class MouseInputHandler implements MouseInputListener {
95
96 private int mouseXOffset;
97 private Cursor otherCursor = resizeCursor;
98
99 public void mouseClicked(MouseEvent e) {
100 if (!header.isEnabled()) {
101 return;
102 }
103 if (e.getClickCount() % 2 == 1 &&
104 SwingUtilities.isLeftMouseButton(e)) {
105 JTable table = header.getTable();
106 RowSorter sorter;
107 if (table != null && (sorter = table.getRowSorter()) != null) {
108 int columnIndex = header.columnAtPoint(e.getPoint());
109 if (columnIndex != -1) {
110 columnIndex = table.convertColumnIndexToModel(
111 columnIndex);
112 sorter.toggleSortOrder(columnIndex);
113 }
114 }
115 }
116 }
117
118 private TableColumn getResizingColumn(Point p) {
119 return getResizingColumn(p, header.columnAtPoint(p));
120 }
121
122 private TableColumn getResizingColumn(Point p, int column) {
123 if (column == -1) {
124 return null;
125 }
126 Rectangle r = header.getHeaderRect(column);
127 r.grow(-3, 0);
128 if (r.contains(p)) {
129 return null;
130 }
131 int midPoint = r.x + r.width/2;
132 int columnIndex;
133 if( header.getComponentOrientation().isLeftToRight() ) {
134 columnIndex = (p.x < midPoint) ? column - 1 : column;
135 } else {
136 columnIndex = (p.x < midPoint) ? column : column - 1;
137 }
138 if (columnIndex == -1) {
139 return null;
140 }
141 return header.getColumnModel().getColumn(columnIndex);
142 }
143
144 public void mousePressed(MouseEvent e) {
145 if (!header.isEnabled()) {
146 return;
147 }
148 header.setDraggedColumn(null);
149 header.setResizingColumn(null);
150 header.setDraggedDistance(0);
151
152 Point p = e.getPoint();
153
154 // First find which header cell was hit
155 TableColumnModel columnModel = header.getColumnModel();
156 int index = header.columnAtPoint(p);
157
158 if (index != -1) {
159 // The last 3 pixels + 3 pixels of next column are for resizing
160 TableColumn resizingColumn = getResizingColumn(p, index);
161 if (canResize(resizingColumn, header)) {
162 header.setResizingColumn(resizingColumn);
163 if( header.getComponentOrientation().isLeftToRight() ) {
164 mouseXOffset = p.x - resizingColumn.getWidth();
165 } else {
166 mouseXOffset = p.x + resizingColumn.getWidth();
167 }
168 }
169 else if (header.getReorderingAllowed()) {
170 TableColumn hitColumn = columnModel.getColumn(index);
171 header.setDraggedColumn(hitColumn);
172 mouseXOffset = p.x;
173 }
174 }
175
176 if (header.getReorderingAllowed()) {
177 int oldRolloverColumn = rolloverColumn;
178 rolloverColumn = -1;
179 rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
180 }
181 }
182
183 private void swapCursor() {
184 Cursor tmp = header.getCursor();
185 header.setCursor(otherCursor);
186 otherCursor = tmp;
187 }
188
189 public void mouseMoved(MouseEvent e) {
190 if (!header.isEnabled()) {
191 return;
192 }
193 if (canResize(getResizingColumn(e.getPoint()), header) !=
194 (header.getCursor() == resizeCursor)) {
195 swapCursor();
196 }
197 updateRolloverColumn(e);
198 }
199
200 public void mouseDragged(MouseEvent e) {
201 if (!header.isEnabled()) {
202 return;
203 }
204 int mouseX = e.getX();
205
206 TableColumn resizingColumn = header.getResizingColumn();
207 TableColumn draggedColumn = header.getDraggedColumn();
208
209 boolean headerLeftToRight = header.getComponentOrientation().isLeftToRight();
210
211 if (resizingColumn != null) {
212 int oldWidth = resizingColumn.getWidth();
213 int newWidth;
214 if (headerLeftToRight) {
215 newWidth = mouseX - mouseXOffset;
216 } else {
217 newWidth = mouseXOffset - mouseX;
218 }
219 mouseXOffset += changeColumnWidth(resizingColumn, header,
220 oldWidth, newWidth);
221 }
222 else if (draggedColumn != null) {
223 TableColumnModel cm = header.getColumnModel();
224 int draggedDistance = mouseX - mouseXOffset;
225 int direction = (draggedDistance < 0) ? -1 : 1;
226 int columnIndex = viewIndexForColumn(draggedColumn);
227 int newColumnIndex = columnIndex + (headerLeftToRight ? direction : -direction);
228 if (0 <= newColumnIndex && newColumnIndex < cm.getColumnCount()) {
229 int width = cm.getColumn(newColumnIndex).getWidth();
230 if (Math.abs(draggedDistance) > (width / 2)) {
231
232 mouseXOffset = mouseXOffset + direction * width;
233 header.setDraggedDistance(draggedDistance - direction * width);
234
235 //Cache the selected column.
236 int selectedIndex =
237 SwingUtilities2.convertColumnIndexToModel(
238 header.getColumnModel(),
239 getSelectedColumnIndex());
240
241 //Now do the move.
242 cm.moveColumn(columnIndex, newColumnIndex);
243
244 //Update the selected index.
245 selectColumn(
246 SwingUtilities2.convertColumnIndexToView(
247 header.getColumnModel(), selectedIndex),
248 false);
249
250 return;
251 }
252 }
253 setDraggedDistance(draggedDistance, columnIndex);
254 }
255
256 updateRolloverColumn(e);
257 }
258
259 public void mouseReleased(MouseEvent e) {
260 if (!header.isEnabled()) {
261 return;
262 }
263 setDraggedDistance(0, viewIndexForColumn(header.getDraggedColumn()));
264
265 header.setResizingColumn(null);
266 header.setDraggedColumn(null);
267
268 updateRolloverColumn(e);
269 }
270
271 public void mouseEntered(MouseEvent e) {
272 if (!header.isEnabled()) {
273 return;
274 }
275 updateRolloverColumn(e);
276 }
277
278 public void mouseExited(MouseEvent e) {
279 if (!header.isEnabled()) {
280 return;
281 }
282 int oldRolloverColumn = rolloverColumn;
283 rolloverColumn = -1;
284 rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
285 }
286//
287// Protected & Private Methods
288//
289
290 private void setDraggedDistance(int draggedDistance, int column) {
291 header.setDraggedDistance(draggedDistance);
292 if (column != -1) {
293 header.getColumnModel().moveColumn(column, column);
294 }
295 }
296 }
297
298//
299// Factory methods for the Listeners
300//
301
302 /**
303 * Creates the mouse listener for the JTableHeader.
304 */
305 protected MouseInputListener createMouseInputListener() {
306 return new MouseInputHandler();
307 }
308
309//
310// The installation/uninstall procedures and support
311//
312
313 public static ComponentUI createUI(JComponent h) {
314 return new BasicTableHeaderUI();
315 }
316
317// Installation
318
319 public void installUI(JComponent c) {
320 header = (JTableHeader)c;
321
322 rendererPane = new CellRendererPane();
323 header.add(rendererPane);
324
325 installDefaults();
326 installListeners();
327 installKeyboardActions();
328 }
329
330 /**
331 * Initializes JTableHeader properties such as font, foreground, and background.
332 * The font, foreground, and background properties are only set if their
333 * current value is either null or a UIResource, other properties are set
334 * if the current value is null.
335 *
336 * @see #installUI
337 */
338 protected void installDefaults() {
339 LookAndFeel.installColorsAndFont(header, "TableHeader.background",
340 "TableHeader.foreground", "TableHeader.font");
341 LookAndFeel.installProperty(header, "opaque", Boolean.TRUE);
342 }
343
344 /**
345 * Attaches listeners to the JTableHeader.
346 */
347 protected void installListeners() {
348 mouseInputListener = createMouseInputListener();
349
350 header.addMouseListener(mouseInputListener);
351 header.addMouseMotionListener(mouseInputListener);
352 header.addFocusListener(focusListener);
353 }
354
355 /**
356 * Register all keyboard actions on the JTableHeader.
357 */
358 protected void installKeyboardActions() {
359 InputMap keyMap = (InputMap)DefaultLookup.get(header, this,
360 "TableHeader.ancestorInputMap");
361 SwingUtilities.replaceUIInputMap(header,
362 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap);
363 LazyActionMap.installLazyActionMap(header, BasicTableHeaderUI.class,
364 "TableHeader.actionMap");
365 }
366
367// Uninstall methods
368
369 public void uninstallUI(JComponent c) {
370 uninstallDefaults();
371 uninstallListeners();
372 uninstallKeyboardActions();
373
374 header.remove(rendererPane);
375 rendererPane = null;
376 header = null;
377 }
378
379 protected void uninstallDefaults() {}
380
381 protected void uninstallListeners() {
382 header.removeMouseListener(mouseInputListener);
383 header.removeMouseMotionListener(mouseInputListener);
384
385 mouseInputListener = null;
386 }
387
388 /**
389 * Unregisters default key actions.
390 */
391 protected void uninstallKeyboardActions() {
392 SwingUtilities.replaceUIInputMap(header, JComponent.WHEN_FOCUSED, null);
393 SwingUtilities.replaceUIActionMap(header, null);
394 }
395
396 /**
397 * Populates TableHeader's actions.
398 */
399 static void loadActionMap(LazyActionMap map) {
400 map.put(new Actions(Actions.TOGGLE_SORT_ORDER));
401 map.put(new Actions(Actions.SELECT_COLUMN_TO_LEFT));
402 map.put(new Actions(Actions.SELECT_COLUMN_TO_RIGHT));
403 map.put(new Actions(Actions.MOVE_COLUMN_LEFT));
404 map.put(new Actions(Actions.MOVE_COLUMN_RIGHT));
405 map.put(new Actions(Actions.RESIZE_LEFT));
406 map.put(new Actions(Actions.RESIZE_RIGHT));
407 map.put(new Actions(Actions.FOCUS_TABLE));
408 }
409
410//
411// Support for mouse rollover
412//
413
414 /**
415 * Returns the index of the column header over which the mouse
416 * currently is. When the mouse is not over the table header,
417 * -1 is returned.
418 *
419 * @see #rolloverColumnUpdated(int, int)
420 * @return the index of the current rollover column
421 * @since 1.6
422 */
423 protected int getRolloverColumn() {
424 return rolloverColumn;
425 }
426
427 /**
428 * This method gets called every time when a rollover column in the table
429 * header is updated. Every look and feel that supports a rollover effect
430 * in a table header should override this method and repaint the header.
431 *
432 * @param oldColumn the index of the previous rollover column or -1 if the
433 * mouse was not over a column
434 * @param newColumn the index of the new rollover column or -1 if the mouse
435 * is not over a column
436 * @see #getRolloverColumn()
437 * @see JTableHeader#getHeaderRect(int)
438 * @since 1.6
439 */
440 protected void rolloverColumnUpdated(int oldColumn, int newColumn) {
441 }
442
443 private void updateRolloverColumn(MouseEvent e) {
444 if (header.getDraggedColumn() == null &&
445 header.contains(e.getPoint())) {
446
447 int col = header.columnAtPoint(e.getPoint());
448 if (col != rolloverColumn) {
449 int oldRolloverColumn = rolloverColumn;
450 rolloverColumn = col;
451 rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
452 }
453 }
454 }
455
456//
457// Support for keyboard and mouse access
458//
459 private int selectNextColumn(boolean doIt) {
460 int newIndex = getSelectedColumnIndex();
461 if (newIndex < header.getColumnModel().getColumnCount() - 1) {
462 newIndex++;
463 if (doIt) {
464 selectColumn(newIndex);
465 }
466 }
467 return newIndex;
468 }
469
470 private int selectPreviousColumn(boolean doIt) {
471 int newIndex = getSelectedColumnIndex();
472 if (newIndex > 0) {
473 newIndex--;
474 if (doIt) {
475 selectColumn(newIndex);
476 }
477 }
478 return newIndex;
479 }
480
481 /**
482 * Selects the specified column in the table header. Repaints the
483 * affected header cells and makes sure the newly selected one is visible.
484 */
485 void selectColumn(int newColIndex) {
486 selectColumn(newColIndex, true);
487 }
488
489 void selectColumn(int newColIndex, boolean doScroll) {
490 Rectangle repaintRect = header.getHeaderRect(selectedColumnIndex);
491 header.repaint(repaintRect);
492 selectedColumnIndex = newColIndex;
493 repaintRect = header.getHeaderRect(newColIndex);
494 header.repaint(repaintRect);
495 if (doScroll) {
496 scrollToColumn(newColIndex);
497 }
498 return;
499 }
500 /**
501 * Used by selectColumn to scroll horizontally, if necessary,
502 * to ensure that the newly selected column is visible.
503 */
504 private void scrollToColumn(int col) {
505 Container container;
506 JTable table;
507
508 //Test whether the header is in a scroll pane and has a table.
509 if ((header.getParent() == null) ||
510 ((container = header.getParent().getParent()) == null) ||
511 !(container instanceof JScrollPane) ||
512 ((table = header.getTable()) == null)) {
513 return;
514 }
515
516 //Now scroll, if necessary.
517 Rectangle vis = table.getVisibleRect();
518 Rectangle cellBounds = table.getCellRect(0, col, true);
519 vis.x = cellBounds.x;
520 vis.width = cellBounds.width;
521 table.scrollRectToVisible(vis);
522 }
523
524 private int getSelectedColumnIndex() {
525 int numCols = header.getColumnModel().getColumnCount();
526 if (selectedColumnIndex >= numCols && numCols > 0) {
527 selectedColumnIndex = numCols - 1;
528 }
529 return selectedColumnIndex;
530 }
531
532 private static boolean canResize(TableColumn column,
533 JTableHeader header) {
534 return (column != null) && header.getResizingAllowed()
535 && column.getResizable();
536 }
537
538 private int changeColumnWidth(TableColumn resizingColumn,
539 JTableHeader th,
540 int oldWidth, int newWidth) {
541 resizingColumn.setWidth(newWidth);
542
543 Container container;
544 JTable table;
545
546 if ((th.getParent() == null) ||
547 ((container = th.getParent().getParent()) == null) ||
548 !(container instanceof JScrollPane) ||
549 ((table = th.getTable()) == null)) {
550 return 0;
551 }
552
553 if (!container.getComponentOrientation().isLeftToRight() &&
554 !th.getComponentOrientation().isLeftToRight()) {
555 JViewport viewport = ((JScrollPane)container).getViewport();
556 int viewportWidth = viewport.getWidth();
557 int diff = newWidth - oldWidth;
558 int newHeaderWidth = table.getWidth() + diff;
559
560 /* Resize a table */
561 Dimension tableSize = table.getSize();
562 tableSize.width += diff;
563 table.setSize(tableSize);
564
565 /* If this table is in AUTO_RESIZE_OFF mode and
566 * has a horizontal scrollbar, we need to update
567 * a view's position.
568 */
569 if ((newHeaderWidth >= viewportWidth) &&
570 (table.getAutoResizeMode() == JTable.AUTO_RESIZE_OFF)) {
571 Point p = viewport.getViewPosition();
572 p.x = Math.max(0, Math.min(newHeaderWidth - viewportWidth,
573 p.x + diff));
574 viewport.setViewPosition(p);
575 return diff;
576 }
577 }
578 return 0;
579 }
580
581//
582// Baseline
583//
584
585 /**
586 * Returns the baseline.
587 *
588 * @throws NullPointerException {@inheritDoc}
589 * @throws IllegalArgumentException {@inheritDoc}
590 * @see javax.swing.JComponent#getBaseline(int, int)
591 * @since 1.6
592 */
593 public int getBaseline(JComponent c, int width, int height) {
594 super.getBaseline(c, width, height);
595 int baseline = -1;
596 TableColumnModel columnModel = header.getColumnModel();
597 for(int column = 0; column < columnModel.getColumnCount();
598 column++) {
599 TableColumn aColumn = columnModel.getColumn(column);
600 Component comp = getHeaderRenderer(column);
601 Dimension pref = comp.getPreferredSize();
602 int columnBaseline = comp.getBaseline(pref.width, height);
603 if (columnBaseline >= 0) {
604 if (baseline == -1) {
605 baseline = columnBaseline;
606 }
607 else if (baseline != columnBaseline) {
608 baseline = -1;
609 break;
610 }
611 }
612 }
613 return baseline;
614 }
615
616//
617// Paint Methods and support
618//
619
620 public void paint(Graphics g, JComponent c) {
621 if (header.getColumnModel().getColumnCount() <= 0) {
622 return;
623 }
624 boolean ltr = header.getComponentOrientation().isLeftToRight();
625
626 Rectangle clip = g.getClipBounds();
627 Point left = clip.getLocation();
628 Point right = new Point( clip.x + clip.width - 1, clip.y );
629 TableColumnModel cm = header.getColumnModel();
630 int cMin = header.columnAtPoint( ltr ? left : right );
631 int cMax = header.columnAtPoint( ltr ? right : left );
632 // This should never happen.
633 if (cMin == -1) {
634 cMin = 0;
635 }
636 // If the table does not have enough columns to fill the view we'll get -1.
637 // Replace this with the index of the last column.
638 if (cMax == -1) {
639 cMax = cm.getColumnCount()-1;
640 }
641
642 TableColumn draggedColumn = header.getDraggedColumn();
643 int columnWidth;
644 Rectangle cellRect = header.getHeaderRect(ltr ? cMin : cMax);
645 TableColumn aColumn;
646 if (ltr) {
647 for(int column = cMin; column <= cMax ; column++) {
648 aColumn = cm.getColumn(column);
649 columnWidth = aColumn.getWidth();
650 cellRect.width = columnWidth;
651 if (aColumn != draggedColumn) {
652 paintCell(g, cellRect, column);
653 }
654 cellRect.x += columnWidth;
655 }
656 } else {
657 for(int column = cMax; column >= cMin; column--) {
658 aColumn = cm.getColumn(column);
659 columnWidth = aColumn.getWidth();
660 cellRect.width = columnWidth;
661 if (aColumn != draggedColumn) {
662 paintCell(g, cellRect, column);
663 }
664 cellRect.x += columnWidth;
665 }
666 }
667
668 // Paint the dragged column if we are dragging.
669 if (draggedColumn != null) {
670 int draggedColumnIndex = viewIndexForColumn(draggedColumn);
671 Rectangle draggedCellRect = header.getHeaderRect(draggedColumnIndex);
672
673 // Draw a gray well in place of the moving column.
674 g.setColor(header.getParent().getBackground());
675 g.fillRect(draggedCellRect.x, draggedCellRect.y,
676 draggedCellRect.width, draggedCellRect.height);
677
678 draggedCellRect.x += header.getDraggedDistance();
679
680 // Fill the background.
681 g.setColor(header.getBackground());
682 g.fillRect(draggedCellRect.x, draggedCellRect.y,
683 draggedCellRect.width, draggedCellRect.height);
684
685 paintCell(g, draggedCellRect, draggedColumnIndex);
686 }
687
688 // Remove all components in the rendererPane.
689 rendererPane.removeAll();
690 }
691
692 private Component getHeaderRenderer(int columnIndex) {
693 TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
694 TableCellRenderer renderer = aColumn.getHeaderRenderer();
695 if (renderer == null) {
696 renderer = header.getDefaultRenderer();
697 }
698
699 boolean hasFocus = !header.isPaintingForPrint()
700 && (columnIndex == getSelectedColumnIndex())
701 && header.hasFocus();
702 return renderer.getTableCellRendererComponent(header.getTable(),
703 aColumn.getHeaderValue(),
704 false, hasFocus,
705 -1, columnIndex);
706 }
707
708 private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
709 Component component = getHeaderRenderer(columnIndex);
710 rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
711 cellRect.width, cellRect.height, true);
712 }
713
714 private int viewIndexForColumn(TableColumn aColumn) {
715 TableColumnModel cm = header.getColumnModel();
716 for (int column = 0; column < cm.getColumnCount(); column++) {
717 if (cm.getColumn(column) == aColumn) {
718 return column;
719 }
720 }
721 return -1;
722 }
723
724//
725// Size Methods
726//
727
728 private int getHeaderHeight() {
729 int height = 0;
730 boolean accomodatedDefault = false;
731 TableColumnModel columnModel = header.getColumnModel();
732 for(int column = 0; column < columnModel.getColumnCount(); column++) {
733 TableColumn aColumn = columnModel.getColumn(column);
734 boolean isDefault = (aColumn.getHeaderRenderer() == null);
735
736 if (!isDefault || !accomodatedDefault) {
737 Component comp = getHeaderRenderer(column);
738 int rendererHeight = comp.getPreferredSize().height;
739 height = Math.max(height, rendererHeight);
740
741 // Configuring the header renderer to calculate its preferred size
742 // is expensive. Optimise this by assuming the default renderer
743 // always has the same height as the first non-zero height that
744 // it returns for a non-null/non-empty value.
745 if (isDefault && rendererHeight > 0) {
746 Object headerValue = aColumn.getHeaderValue();
747 if (headerValue != null) {
748 headerValue = headerValue.toString();
749
750 if (headerValue != null && !headerValue.equals("")) {
751 accomodatedDefault = true;
752 }
753 }
754 }
755 }
756 }
757 return height;
758 }
759
760 private Dimension createHeaderSize(long width) {
761 // None of the callers include the intercell spacing, do it here.
762 if (width > Integer.MAX_VALUE) {
763 width = Integer.MAX_VALUE;
764 }
765 return new Dimension((int)width, getHeaderHeight());
766 }
767
768
769 /**
770 * Return the minimum size of the header. The minimum width is the sum
771 * of the minimum widths of each column (plus inter-cell spacing).
772 */
773 public Dimension getMinimumSize(JComponent c) {
774 long width = 0;
775 Enumeration enumeration = header.getColumnModel().getColumns();
776 while (enumeration.hasMoreElements()) {
777 TableColumn aColumn = (TableColumn)enumeration.nextElement();
778 width = width + aColumn.getMinWidth();
779 }
780 return createHeaderSize(width);
781 }
782
783 /**
784 * Return the preferred size of the header. The preferred height is the
785 * maximum of the preferred heights of all of the components provided
786 * by the header renderers. The preferred width is the sum of the
787 * preferred widths of each column (plus inter-cell spacing).
788 */
789 public Dimension getPreferredSize(JComponent c) {
790 long width = 0;
791 Enumeration enumeration = header.getColumnModel().getColumns();
792 while (enumeration.hasMoreElements()) {
793 TableColumn aColumn = (TableColumn)enumeration.nextElement();
794 width = width + aColumn.getPreferredWidth();
795 }
796 return createHeaderSize(width);
797 }
798
799 /**
800 * Return the maximum size of the header. The maximum width is the sum
801 * of the maximum widths of each column (plus inter-cell spacing).
802 */
803 public Dimension getMaximumSize(JComponent c) {
804 long width = 0;
805 Enumeration enumeration = header.getColumnModel().getColumns();
806 while (enumeration.hasMoreElements()) {
807 TableColumn aColumn = (TableColumn)enumeration.nextElement();
808 width = width + aColumn.getMaxWidth();
809 }
810 return createHeaderSize(width);
811 }
812
813 private static class Actions extends UIAction {
814 public static final String TOGGLE_SORT_ORDER =
815 "toggleSortOrder";
816 public static final String SELECT_COLUMN_TO_LEFT =
817 "selectColumnToLeft";
818 public static final String SELECT_COLUMN_TO_RIGHT =
819 "selectColumnToRight";
820 public static final String MOVE_COLUMN_LEFT =
821 "moveColumnLeft";
822 public static final String MOVE_COLUMN_RIGHT =
823 "moveColumnRight";
824 public static final String RESIZE_LEFT =
825 "resizeLeft";
826 public static final String RESIZE_RIGHT =
827 "resizeRight";
828 public static final String FOCUS_TABLE =
829 "focusTable";
830
831 public Actions(String name) {
832 super(name);
833 }
834
835 public boolean isEnabled(Object sender) {
836 if (sender instanceof JTableHeader) {
837 JTableHeader th = (JTableHeader)sender;
838 TableColumnModel cm = th.getColumnModel();
839 if (cm.getColumnCount() <= 0) {
840 return false;
841 }
842
843 String key = getName();
844 BasicTableHeaderUI ui =
845 (BasicTableHeaderUI)BasicLookAndFeel.getUIOfType(th.getUI(),
846 BasicTableHeaderUI.class);
847 if (ui != null) {
848 if (key == MOVE_COLUMN_LEFT) {
849 return th.getReorderingAllowed()
850 && maybeMoveColumn(true, th, ui, false);
851 } else if (key == MOVE_COLUMN_RIGHT) {
852 return th.getReorderingAllowed()
853 && maybeMoveColumn(false, th, ui, false);
854 } else if (key == RESIZE_LEFT ||
855 key == RESIZE_RIGHT) {
856 return canResize(cm.getColumn(ui.getSelectedColumnIndex()), th);
857 } else if (key == FOCUS_TABLE) {
858 return (th.getTable() != null);
859 }
860 }
861 }
862 return true;
863 }
864
865 public void actionPerformed(ActionEvent e) {
866 JTableHeader th = (JTableHeader)e.getSource();
867 BasicTableHeaderUI ui =
868 (BasicTableHeaderUI)BasicLookAndFeel.
869 getUIOfType(th.getUI(),
870 BasicTableHeaderUI.class);
871 if (ui == null) {
872 return;
873 }
874
875 String name = getName();
876 if (TOGGLE_SORT_ORDER == name) {
877 JTable table = th.getTable();
878 RowSorter sorter = table == null ? null : table.getRowSorter();
879 if (sorter != null) {
880 int columnIndex = ui.getSelectedColumnIndex();
881 columnIndex = table.convertColumnIndexToModel(
882 columnIndex);
883 sorter.toggleSortOrder(columnIndex);
884 }
885 } else if (SELECT_COLUMN_TO_LEFT == name) {
886 if (th.getComponentOrientation().isLeftToRight()) {
887 ui.selectPreviousColumn(true);
888 } else {
889 ui.selectNextColumn(true);
890 }
891 } else if (SELECT_COLUMN_TO_RIGHT == name) {
892 if (th.getComponentOrientation().isLeftToRight()) {
893 ui.selectNextColumn(true);
894 } else {
895 ui.selectPreviousColumn(true);
896 }
897 } else if (MOVE_COLUMN_LEFT == name) {
898 moveColumn(true, th, ui);
899 } else if (MOVE_COLUMN_RIGHT == name) {
900 moveColumn(false, th, ui);
901 } else if (RESIZE_LEFT == name) {
902 resize(true, th, ui);
903 } else if (RESIZE_RIGHT == name) {
904 resize(false, th, ui);
905 } else if (FOCUS_TABLE == name) {
906 JTable table = th.getTable();
907 if (table != null) {
908 table.requestFocusInWindow();
909 }
910 }
911 }
912
913 private void moveColumn(boolean leftArrow, JTableHeader th,
914 BasicTableHeaderUI ui) {
915 maybeMoveColumn(leftArrow, th, ui, true);
916 }
917
918 private boolean maybeMoveColumn(boolean leftArrow, JTableHeader th,
919 BasicTableHeaderUI ui, boolean doIt) {
920 int oldIndex = ui.getSelectedColumnIndex();
921 int newIndex;
922
923 if (th.getComponentOrientation().isLeftToRight()) {
924 newIndex = leftArrow ? ui.selectPreviousColumn(doIt)
925 : ui.selectNextColumn(doIt);
926 } else {
927 newIndex = leftArrow ? ui.selectNextColumn(doIt)
928 : ui.selectPreviousColumn(doIt);
929 }
930
931 if (newIndex != oldIndex) {
932 if (doIt) {
933 th.getColumnModel().moveColumn(oldIndex, newIndex);
934 } else {
935 return true; // we'd do the move if asked
936 }
937 }
938
939 return false;
940 }
941
942 private void resize(boolean leftArrow, JTableHeader th,
943 BasicTableHeaderUI ui) {
944 int columnIndex = ui.getSelectedColumnIndex();
945 TableColumn resizingColumn =
946 th.getColumnModel().getColumn(columnIndex);
947
948 th.setResizingColumn(resizingColumn);
949 int oldWidth = resizingColumn.getWidth();
950 int newWidth = oldWidth;
951
952 if (th.getComponentOrientation().isLeftToRight()) {
953 newWidth = newWidth + (leftArrow ? -1 : 1);
954 } else {
955 newWidth = newWidth + (leftArrow ? 1 : -1);
956 }
957
958 ui.changeColumnWidth(resizingColumn, th, oldWidth, newWidth);
959 }
960 }
961} // End of Class BasicTableHeaderUI