KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * @(#)BasicTableHeaderUI.java 1.63 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.plaf.basic;
9
10 import javax.swing.table.*;
11 import javax.swing.*;
12 import javax.swing.event.*;
13 import java.util.Enumeration JavaDoc;
14 import java.awt.event.*;
15 import java.awt.*;
16 import javax.swing.plaf.*;
17
18 /**
19  * BasicTableHeaderUI implementation
20  *
21  * @version 1.63 12/19/03
22  * @author Alan Chung
23  * @author Philip Milne
24  */

25 public class BasicTableHeaderUI extends TableHeaderUI {
26
27     private static Cursor resizeCursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
28
29 //
30
// Instance Variables
31
//
32

33     /** The JTableHeader that is delegating the painting to this UI. */
34     protected JTableHeader header;
35     protected CellRendererPane rendererPane;
36
37     // Listeners that are attached to the JTable
38
protected MouseInputListener mouseInputListener;
39
40     /**
41      * This inner class is marked "public" due to a compiler bug.
42      * This class should be treated as a "protected" inner class.
43      * Instantiate it only within subclasses of BasicTableUI.
44      */

45     public class MouseInputHandler implements MouseInputListener {
46
47         private int mouseXOffset;
48     private Cursor otherCursor = resizeCursor;
49
50         public void mouseClicked(MouseEvent e) {}
51
52     private boolean canResize(TableColumn column) {
53         return (column != null) && header.getResizingAllowed() && column.getResizable();
54     }
55
56         private TableColumn getResizingColumn(Point p) {
57         return getResizingColumn(p, header.columnAtPoint(p));
58     }
59
60         private TableColumn getResizingColumn(Point p, int column) {
61             if (column == -1) {
62                  return null;
63             }
64         Rectangle r = header.getHeaderRect(column);
65         r.grow(-3, 0);
66         if (r.contains(p)) {
67         return null;
68         }
69         int midPoint = r.x + r.width/2;
70         int columnIndex;
71             if( header.getComponentOrientation().isLeftToRight() ) {
72                 columnIndex = (p.x < midPoint) ? column - 1 : column;
73             } else {
74                 columnIndex = (p.x < midPoint) ? column : column - 1;
75             }
76         if (columnIndex == -1) {
77         return null;
78         }
79         return header.getColumnModel().getColumn(columnIndex);
80         }
81
82         public void mousePressed(MouseEvent e) {
83             header.setDraggedColumn(null);
84             header.setResizingColumn(null);
85             header.setDraggedDistance(0);
86
87             Point p = e.getPoint();
88
89             // First find which header cell was hit
90
TableColumnModel columnModel = header.getColumnModel();
91             int index = header.columnAtPoint(p);
92
93             if (index != -1) {
94                 // The last 3 pixels + 3 pixels of next column are for resizing
95
TableColumn resizingColumn = getResizingColumn(p, index);
96                 if (canResize(resizingColumn)) {
97                     header.setResizingColumn(resizingColumn);
98                     if( header.getComponentOrientation().isLeftToRight() ) {
99                         mouseXOffset = p.x - resizingColumn.getWidth();
100                     } else {
101                         mouseXOffset = p.x + resizingColumn.getWidth();
102                     }
103                 }
104                 else if (header.getReorderingAllowed()) {
105                     TableColumn hitColumn = columnModel.getColumn(index);
106                     header.setDraggedColumn(hitColumn);
107             mouseXOffset = p.x;
108                 }
109             }
110         }
111
112     private void swapCursor() {
113         Cursor tmp = header.getCursor();
114         header.setCursor(otherCursor);
115         otherCursor = tmp;
116     }
117
118         public void mouseMoved(MouseEvent e) {
119             if (canResize(getResizingColumn(e.getPoint())) !=
120         (header.getCursor() == resizeCursor)) {
121                 swapCursor();
122             }
123        }
124
125         public void mouseDragged(MouseEvent e) {
126             int mouseX = e.getX();
127
128             TableColumn resizingColumn = header.getResizingColumn();
129             TableColumn draggedColumn = header.getDraggedColumn();
130
131             boolean headerLeftToRight = header.getComponentOrientation().isLeftToRight();
132
133             if (resizingColumn != null) {
134         int oldWidth = resizingColumn.getWidth();
135         int newWidth;
136         if (headerLeftToRight) {
137                     newWidth = mouseX - mouseXOffset;
138                 } else {
139                     newWidth = mouseXOffset - mouseX;
140         }
141                 resizingColumn.setWidth(newWidth);
142
143         Container container;
144         if ((header.getParent() == null) ||
145             ((container = header.getParent().getParent()) == null) ||
146             !(container instanceof JScrollPane)) {
147             return;
148         }
149
150         if (!container.getComponentOrientation().isLeftToRight() &&
151             !headerLeftToRight) {
152             JTable table = header.getTable();
153             if (table != null) {
154             JViewport viewport = ((JScrollPane)container).getViewport();
155             int viewportWidth = viewport.getWidth();
156             int diff = newWidth - oldWidth;
157             int newHeaderWidth = table.getWidth() + diff;
158
159             /* Resize a table */
160             Dimension tableSize = table.getSize();
161             tableSize.width += diff;
162             table.setSize(tableSize);
163
164             /* If this table is in AUTO_RESIZE_OFF mode and
165              * has a horizontal scrollbar, we need to update
166              * a view's position.
167              */

168             if ((newHeaderWidth >= viewportWidth) &&
169                 (table.getAutoResizeMode() == JTable.AUTO_RESIZE_OFF)) {
170                 Point p = viewport.getViewPosition();
171                 p.x = Math.max(0, Math.min(newHeaderWidth - viewportWidth, p.x + diff));
172                 viewport.setViewPosition(p);
173
174                 /* Update the original X offset value. */
175                 mouseXOffset += diff;
176             }
177             }
178         }
179             }
180             else if (draggedColumn != null) {
181         TableColumnModel cm = header.getColumnModel();
182         int draggedDistance = mouseX - mouseXOffset;
183         int direction = (draggedDistance < 0) ? -1 : 1;
184         int columnIndex = viewIndexForColumn(draggedColumn);
185         int newColumnIndex = columnIndex + (headerLeftToRight ? direction : -direction);
186         if (0 <= newColumnIndex && newColumnIndex < cm.getColumnCount()) {
187             int width = cm.getColumn(newColumnIndex).getWidth();
188             if (Math.abs(draggedDistance) > (width / 2)) {
189             mouseXOffset = mouseXOffset + direction * width;
190             header.setDraggedDistance(draggedDistance - direction * width);
191             cm.moveColumn(columnIndex, newColumnIndex);
192             return;
193             }
194         }
195         setDraggedDistance(draggedDistance, columnIndex);
196         }
197         }
198
199         public void mouseReleased(MouseEvent e) {
200         setDraggedDistance(0, viewIndexForColumn(header.getDraggedColumn()));
201
202             header.setResizingColumn(null);
203             header.setDraggedColumn(null);
204         }
205
206         public void mouseEntered(MouseEvent e) {}
207
208         public void mouseExited(MouseEvent e) {}
209 //
210
// Protected & Private Methods
211
//
212

213     private void setDraggedDistance(int draggedDistance, int column) {
214             header.setDraggedDistance(draggedDistance);
215         if (column != -1) {
216         header.getColumnModel().moveColumn(column, column);
217         }
218     }
219     }
220
221 //
222
// Factory methods for the Listeners
223
//
224

225     /**
226      * Creates the mouse listener for the JTable.
227      */

228     protected MouseInputListener createMouseInputListener() {
229         return new MouseInputHandler();
230     }
231
232 //
233
// The installation/uninstall procedures and support
234
//
235

236     public static ComponentUI createUI(JComponent h) {
237         return new BasicTableHeaderUI JavaDoc();
238     }
239
240 // Installation
241

242     public void installUI(JComponent c) {
243         header = (JTableHeader)c;
244
245         rendererPane = new CellRendererPane();
246         header.add(rendererPane);
247
248         installDefaults();
249         installListeners();
250         installKeyboardActions();
251     }
252
253     /**
254      * Initialize JTableHeader properties, e.g. font, foreground, and background.
255      * The font, foreground, and background properties are only set if their
256      * current value is either null or a UIResource, other properties are set
257      * if the current value is null.
258      *
259      * @see #installUI
260      */

261     protected void installDefaults() {
262         LookAndFeel.installColorsAndFont(header, "TableHeader.background",
263                                          "TableHeader.foreground", "TableHeader.font");
264         LookAndFeel.installProperty(header, "opaque", Boolean.TRUE);
265     }
266
267     /**
268      * Attaches listeners to the JTableHeader.
269      */

270     protected void installListeners() {
271         mouseInputListener = createMouseInputListener();
272
273         header.addMouseListener(mouseInputListener);
274         header.addMouseMotionListener(mouseInputListener);
275     }
276
277     /**
278      * Register all keyboard actions on the JTableHeader.
279      */

280     protected void installKeyboardActions() { }
281
282 // Uninstall methods
283

284     public void uninstallUI(JComponent c) {
285         uninstallDefaults();
286         uninstallListeners();
287         uninstallKeyboardActions();
288
289         header.remove(rendererPane);
290         rendererPane = null;
291         header = null;
292     }
293
294     protected void uninstallDefaults() {}
295
296     protected void uninstallListeners() {
297         header.removeMouseListener(mouseInputListener);
298         header.removeMouseMotionListener(mouseInputListener);
299
300         mouseInputListener = null;
301     }
302
303     protected void uninstallKeyboardActions() {}
304
305 //
306
// Paint Methods and support
307
//
308

309     public void paint(Graphics g, JComponent c) {
310     if (header.getColumnModel().getColumnCount() <= 0) {
311         return;
312     }
313         boolean ltr = header.getComponentOrientation().isLeftToRight();
314
315     Rectangle clip = g.getClipBounds();
316         Point left = clip.getLocation();
317         Point right = new Point( clip.x + clip.width - 1, clip.y );
318     TableColumnModel cm = header.getColumnModel();
319         int cMin = header.columnAtPoint( ltr ? left : right );
320         int cMax = header.columnAtPoint( ltr ? right : left );
321         // This should never happen.
322
if (cMin == -1) {
323         cMin = 0;
324         }
325         // If the table does not have enough columns to fill the view we'll get -1.
326
// Replace this with the index of the last column.
327
if (cMax == -1) {
328         cMax = cm.getColumnCount()-1;
329         }
330
331     TableColumn draggedColumn = header.getDraggedColumn();
332     int columnWidth;
333         Rectangle cellRect = header.getHeaderRect(ltr ? cMin : cMax);
334     TableColumn aColumn;
335     if (ltr) {
336         for(int column = cMin; column <= cMax ; column++) {
337         aColumn = cm.getColumn(column);
338         columnWidth = aColumn.getWidth();
339         cellRect.width = columnWidth;
340         if (aColumn != draggedColumn) {
341             paintCell(g, cellRect, column);
342         }
343         cellRect.x += columnWidth;
344         }
345     } else {
346         for(int column = cMax; column >= cMin; column--) {
347         aColumn = cm.getColumn(column);
348         columnWidth = aColumn.getWidth();
349         cellRect.width = columnWidth;
350         if (aColumn != draggedColumn) {
351             paintCell(g, cellRect, column);
352         }
353                 cellRect.x += columnWidth;
354         }
355     }
356
357         // Paint the dragged column if we are dragging.
358
if (draggedColumn != null) {
359             int draggedColumnIndex = viewIndexForColumn(draggedColumn);
360         Rectangle draggedCellRect = header.getHeaderRect(draggedColumnIndex);
361             
362             // Draw a gray well in place of the moving column.
363
g.setColor(header.getParent().getBackground());
364             g.fillRect(draggedCellRect.x, draggedCellRect.y,
365                                draggedCellRect.width, draggedCellRect.height);
366
367             draggedCellRect.x += header.getDraggedDistance();
368
369         // Fill the background.
370
g.setColor(header.getBackground());
371         g.fillRect(draggedCellRect.x, draggedCellRect.y,
372                draggedCellRect.width, draggedCellRect.height);
373  
374             paintCell(g, draggedCellRect, draggedColumnIndex);
375         }
376
377     // Remove all components in the rendererPane.
378
rendererPane.removeAll();
379     }
380
381     private Component getHeaderRenderer(int columnIndex) {
382         TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
383     TableCellRenderer renderer = aColumn.getHeaderRenderer();
384         if (renderer == null) {
385         renderer = header.getDefaultRenderer();
386     }
387     return renderer.getTableCellRendererComponent(header.getTable(),
388                         aColumn.getHeaderValue(), false, false,
389                                                 -1, columnIndex);
390     }
391
392     private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
393         Component component = getHeaderRenderer(columnIndex);
394         rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
395                             cellRect.width, cellRect.height, true);
396     }
397
398     private int viewIndexForColumn(TableColumn aColumn) {
399         TableColumnModel cm = header.getColumnModel();
400         for (int column = 0; column < cm.getColumnCount(); column++) {
401             if (cm.getColumn(column) == aColumn) {
402                 return column;
403             }
404         }
405         return -1;
406     }
407
408 //
409
// Size Methods
410
//
411

412     private int getHeaderHeight() {
413         int height = 0;
414     boolean accomodatedDefault = false;
415         TableColumnModel columnModel = header.getColumnModel();
416         for(int column = 0; column < columnModel.getColumnCount(); column++) {
417         TableColumn aColumn = columnModel.getColumn(column);
418         // Configuring the header renderer to calculate its preferred size is expensive.
419
// Optimise this by assuming the default renderer always has the same height.
420
if (aColumn.getHeaderRenderer() != null || !accomodatedDefault) {
421         Component comp = getHeaderRenderer(column);
422         int rendererHeight = comp.getPreferredSize().height;
423         height = Math.max(height, rendererHeight);
424         // If the header value is empty (== "") in the
425
// first column (and this column is set up
426
// to use the default renderer) we will
427
// return zero from this routine and the header
428
// will disappear altogether. Avoiding the calculation
429
// of the preferred size is such a performance win for
430
// most applications that we will continue to
431
// use this cheaper calculation, handling these
432
// issues as `edge cases'.
433
if (rendererHeight > 0) {
434             accomodatedDefault = true;
435         }
436         }
437         }
438         return height;
439     }
440
441     private Dimension createHeaderSize(long width) {
442         TableColumnModel columnModel = header.getColumnModel();
443         // None of the callers include the intercell spacing, do it here.
444
if (width > Integer.MAX_VALUE) {
445             width = Integer.MAX_VALUE;
446         }
447         return new Dimension((int)width, getHeaderHeight());
448     }
449
450
451     /**
452      * Return the minimum size of the header. The minimum width is the sum
453      * of the minimum widths of each column (plus inter-cell spacing).
454      */

455     public Dimension getMinimumSize(JComponent c) {
456         long width = 0;
457         Enumeration JavaDoc enumeration = header.getColumnModel().getColumns();
458         while (enumeration.hasMoreElements()) {
459             TableColumn aColumn = (TableColumn)enumeration.nextElement();
460             width = width + aColumn.getMinWidth();
461         }
462         return createHeaderSize(width);
463     }
464
465     /**
466      * Return the preferred size of the header. The preferred height is the
467      * maximum of the preferred heights of all of the components provided
468      * by the header renderers. The preferred width is the sum of the
469      * preferred widths of each column (plus inter-cell spacing).
470      */

471     public Dimension getPreferredSize(JComponent c) {
472         long width = 0;
473         Enumeration JavaDoc enumeration = header.getColumnModel().getColumns();
474         while (enumeration.hasMoreElements()) {
475             TableColumn aColumn = (TableColumn)enumeration.nextElement();
476             width = width + aColumn.getPreferredWidth();
477         }
478         return createHeaderSize(width);
479     }
480
481     /**
482      * Return the maximum size of the header. The maximum width is the sum
483      * of the maximum widths of each column (plus inter-cell spacing).
484      */

485     public Dimension getMaximumSize(JComponent c) {
486         long width = 0;
487         Enumeration JavaDoc enumeration = header.getColumnModel().getColumns();
488         while (enumeration.hasMoreElements()) {
489             TableColumn aColumn = (TableColumn)enumeration.nextElement();
490             width = width + aColumn.getMaxWidth();
491         }
492         return createHeaderSize(width);
493     }
494
495 } // End of Class BasicTableHeaderUI
496

497
498
Popular Tags