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+
26+package javax.swing.plaf.basic;
27+
28+import java.awt.*;
29+import java.awt.event.*;
30+import java.util.*;
31+import javax.swing.*;
32+import javax.swing.event.*;
33+import javax.swing.plaf.*;
34+import javax.swing.table.*;
35+
36+import sun.swing.*;
37+
38+/**
39+ * BasicTableHeaderUI implementation
40+ *
41+ * @author Alan Chung
42+ * @author Philip Milne
43+ */
44+public 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