Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / javax / swing / plaf / basic / BasicTableHeaderUI.java
blob1e8e39f38c2d4a7becd52dba02666de8d63d05e8
1 /* BasicTableHeaderUI.java --
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.plaf.basic;
41 import java.awt.Component;
42 import java.awt.Cursor;
43 import java.awt.Dimension;
44 import java.awt.Graphics;
45 import java.awt.Rectangle;
46 import java.awt.event.ActionEvent;
47 import java.awt.event.ActionListener;
48 import java.awt.event.MouseEvent;
50 import javax.swing.CellRendererPane;
51 import javax.swing.JComponent;
52 import javax.swing.LookAndFeel;
53 import javax.swing.Timer;
54 import javax.swing.UIManager;
55 import javax.swing.border.Border;
56 import javax.swing.event.MouseInputListener;
57 import javax.swing.plaf.ComponentUI;
58 import javax.swing.plaf.TableHeaderUI;
59 import javax.swing.table.JTableHeader;
60 import javax.swing.table.TableCellRenderer;
61 import javax.swing.table.TableColumn;
62 import javax.swing.table.TableColumnModel;
64 /**
65 * Basic pluggable look and feel interface for JTableHeader.
67 public class BasicTableHeaderUI extends TableHeaderUI
69 /**
70 * The width of the space (in both direction) around the column boundary,
71 * where mouse cursor changes shape into "resize"
73 static int COLUMN_BOUNDARY_TOLERANCE = 3;
75 public static ComponentUI createUI(JComponent h)
77 return new BasicTableHeaderUI();
80 /**
81 * The table header that is using this interface.
83 protected JTableHeader header;
85 /**
86 * The mouse input listener, responsible for mouse manipulations with
87 * the table header.
89 protected MouseInputListener mouseInputListener;
91 /**
92 * Paint the header cell.
94 protected CellRendererPane rendererPane;
96 /**
97 * The header cell border.
99 protected Border cellBorder;
102 * If not null, one of the columns is currently being dragged.
104 Rectangle draggingHeaderRect;
107 * Handles column movement and rearrangement by mouse. The same instance works
108 * both as mouse listener and the mouse motion listner.
110 public class MouseInputHandler
111 implements MouseInputListener
114 * If true, the cursor is being already shown in the alternative "resize"
115 * shape.
117 boolean showingResizeCursor;
120 * The position, from where the cursor is dragged during resizing. Double
121 * purpose field (absolute value during resizing and relative offset during
122 * column dragging).
124 int draggingFrom = - 1;
127 * The number of the column being dragged.
129 int draggingColumnNumber;
132 * The previous preferred width of the column.
134 int prevPrefWidth = - 1;
137 * The timer to coalesce column resizing events.
139 Timer timer;
142 * Returns without action, part of the MouseInputListener interface.
144 public void mouseClicked(MouseEvent e)
146 // Nothing to do.
150 * If being in the resizing mode, handle resizing.
152 public void mouseDragged(MouseEvent e)
154 TableColumn resizeIt = header.getResizingColumn();
155 if (resizeIt != null && header.getResizingAllowed())
157 // The timer is intialised on demand.
158 if (timer == null)
160 // The purpose of timer is to coalesce events. If the queue
161 // is free, the repaint event is fired immediately.
162 timer = new Timer(1, new ActionListener()
164 public void actionPerformed(ActionEvent e)
166 header.getTable().doLayout();
169 timer.setRepeats(false);
170 timer.setCoalesce(true);
172 resizeIt.setPreferredWidth(prevPrefWidth + e.getX() - draggingFrom);
173 timer.restart();
175 else if (draggingHeaderRect != null && header.getReorderingAllowed())
177 draggingHeaderRect.x = e.getX() + draggingFrom;
178 header.repaint();
183 * Returns without action, part of the MouseInputListener interface.
185 public void mouseEntered(MouseEvent e)
187 // Nothing to do.
191 * Reset drag information of the column resizing.
193 public void mouseExited(MouseEvent e)
195 if (header.getResizingColumn() != null && header.getResizingAllowed())
196 endResizing();
197 if (header.getDraggedColumn() != null && header.getReorderingAllowed())
198 endDragging(null);
202 * Change the mouse cursor if the mouse if above the column boundary.
204 public void mouseMoved(MouseEvent e)
206 // When dragging, the functionality is handled by the mouseDragged.
207 if (e.getButton() == 0 && header.getResizingAllowed())
209 TableColumnModel model = header.getColumnModel();
210 int n = model.getColumnCount();
211 if (n < 2)
212 // It must be at least two columns to have at least one boundary.
213 // Otherwise, nothing to do.
214 return;
216 boolean onBoundary = false;
218 int x = e.getX();
219 int a = x - COLUMN_BOUNDARY_TOLERANCE;
220 int b = x + COLUMN_BOUNDARY_TOLERANCE;
222 int p = 0;
224 Scan: for (int i = 0; i < n - 1; i++)
226 p += model.getColumn(i).getWidth();
228 if (p >= a && p <= b)
230 TableColumn column = model.getColumn(i);
231 onBoundary = true;
233 draggingFrom = x;
234 prevPrefWidth = column.getWidth();
235 header.setResizingColumn(column);
236 break Scan;
240 if (onBoundary != showingResizeCursor)
242 // Change the cursor shape, if needed.
243 if (onBoundary)
246 if (p < x)
247 header.setCursor(Cursor.getPredefinedCursor
248 (Cursor.W_RESIZE_CURSOR));
249 else
250 header.setCursor(Cursor.getPredefinedCursor
251 (Cursor.E_RESIZE_CURSOR));
253 else
255 header.setCursor(Cursor.getDefaultCursor());
256 header.setResizingColumn(null);
259 showingResizeCursor = onBoundary;
265 * Starts the dragging/resizing procedure.
267 public void mousePressed(MouseEvent e)
269 if (header.getResizingAllowed())
271 TableColumn resizingColumn = header.getResizingColumn();
272 if (resizingColumn != null)
274 resizingColumn.setPreferredWidth(resizingColumn.getWidth());
275 return;
279 if (header.getReorderingAllowed())
281 TableColumnModel model = header.getColumnModel();
282 int n = model.getColumnCount();
283 if (n < 2)
284 // It must be at least two columns to change the column location.
285 return;
287 boolean onBoundary = false;
289 int x = e.getX();
290 int p = 0;
291 int col = - 1;
293 Scan: for (int i = 0; i < n; i++)
295 p += model.getColumn(i).getWidth();
296 if (p > x)
298 col = i;
299 break Scan;
302 if (col < 0)
303 return;
305 TableColumn dragIt = model.getColumn(col);
306 header.setDraggedColumn(dragIt);
308 draggingFrom = (p - dragIt.getWidth()) - x;
309 draggingHeaderRect = new Rectangle(header.getHeaderRect(col));
310 draggingColumnNumber = col;
315 * Set all column preferred width to the current width to prevend abrupt
316 * width changes during the next resize.
318 public void mouseReleased(MouseEvent e)
320 if (header.getResizingColumn() != null && header.getResizingAllowed())
321 endResizing();
322 if (header.getDraggedColumn() != null && header.getReorderingAllowed())
323 endDragging(e);
327 * Stop resizing session.
329 void endResizing()
331 TableColumnModel model = header.getColumnModel();
332 int n = model.getColumnCount();
333 if (n > 2)
335 TableColumn c;
336 for (int i = 0; i < n; i++)
338 c = model.getColumn(i);
339 c.setPreferredWidth(c.getWidth());
342 header.setResizingColumn(null);
343 showingResizeCursor = false;
344 if (timer != null)
345 timer.stop();
346 header.setCursor(Cursor.getDefaultCursor());
350 * Stop the dragging session.
352 * @param e the "mouse release" mouse event, needed to determing the final
353 * location for the dragged column.
355 void endDragging(MouseEvent e)
357 header.setDraggedColumn(null);
359 // Return if the mouse have left the header area while pressed.
360 if (e == null)
362 header.repaint(draggingHeaderRect);
363 draggingHeaderRect = null;
364 return;
366 else
367 draggingHeaderRect = null;
369 TableColumnModel model = header.getColumnModel();
371 // Find where have we dragged the column.
372 int x = e.getX();
373 int p = 0;
374 int col = - 1;
375 int n = model.getColumnCount();
377 Scan: for (int i = 0; i < n; i++)
379 p += model.getColumn(i).getWidth();
380 if (p > x)
382 col = i;
383 break Scan;
386 if (col >= 0)
387 header.getTable().moveColumn(draggingColumnNumber, col);
392 * Create and return the mouse input listener.
394 * @return the mouse listener ({@link MouseInputHandler}, if not overridden.
396 protected MouseInputListener createMouseInputListener()
398 return new MouseInputHandler();
402 * Construct a new BasicTableHeaderUI, create mouse listeners.
404 public BasicTableHeaderUI()
406 mouseInputListener = createMouseInputListener();
409 protected void installDefaults()
411 LookAndFeel.installColorsAndFont(header, "TableHeader.background",
412 "TableHeader.foreground",
413 "TableHeader.font");
414 cellBorder = UIManager.getBorder("TableHeader.cellBorder");
417 protected void installKeyboardActions()
419 // TODO: Implement this properly.
423 * Add the mouse listener and the mouse motion listener to the table
424 * header. The listeners support table column resizing and rearrangement
425 * by mouse.
427 protected void installListeners()
429 header.addMouseListener(mouseInputListener);
430 header.addMouseMotionListener(mouseInputListener);
433 public void installUI(JComponent c)
435 header = (JTableHeader) c;
436 rendererPane = new CellRendererPane();
437 installDefaults();
438 installKeyboardActions();
439 installListeners();
442 protected void uninstallDefaults()
444 header.setBackground(null);
445 header.setForeground(null);
446 header.setFont(null);
449 protected void uninstallKeyboardActions()
451 // TODO: Implement this properly.
455 * Remove the previously installed listeners.
457 protected void uninstallListeners()
459 header.removeMouseListener(mouseInputListener);
460 header.removeMouseMotionListener(mouseInputListener);
463 public void uninstallUI(JComponent c)
465 uninstallListeners();
466 uninstallKeyboardActions();
467 uninstallDefaults();
471 * Repaint the table header.
473 public void paint(Graphics gfx, JComponent c)
475 TableColumnModel cmod = header.getColumnModel();
476 int ncols = cmod.getColumnCount();
477 if (ncols == 0)
478 return;
480 Rectangle clip = gfx.getClipBounds();
481 TableCellRenderer defaultRend = header.getDefaultRenderer();
483 for (int i = 0; i < ncols; ++i)
485 Rectangle bounds = header.getHeaderRect(i);
486 if (bounds.intersects(clip))
488 Rectangle oldClip = gfx.getClipBounds();
489 TableColumn col = cmod.getColumn(i);
490 TableCellRenderer rend = col.getHeaderRenderer();
491 if (rend == null)
492 rend = defaultRend;
493 Object val = col.getHeaderValue();
494 Component comp = rend.getTableCellRendererComponent(header.getTable(),
495 val,
496 false, // isSelected
497 false, // isFocused
498 -1, i);
499 // FIXME: The following settings should be performed in
500 // rend.getTableCellRendererComponent().
501 comp.setFont(header.getFont());
502 comp.setBackground(header.getBackground());
503 comp.setForeground(header.getForeground());
504 if (comp instanceof JComponent)
505 ((JComponent)comp).setBorder(cellBorder);
506 rendererPane.paintComponent(gfx, comp, header, bounds.x, bounds.y,
507 bounds.width, bounds.height);
511 // This displays a running rectangle that is much simplier than the total
512 // animation, as it is seen in Sun's application.
513 // TODO animate the collumn dragging like in Sun's jre.
514 if (draggingHeaderRect!=null)
516 gfx.setColor(header.getForeground());
517 gfx.drawRect(draggingHeaderRect.x, draggingHeaderRect.y+2,
518 draggingHeaderRect.width-1, draggingHeaderRect.height-6);
523 * Get the preferred header size.
525 * @param ignored unused
527 * @return the preferred size of the associated header.
529 public Dimension getPreferredSize(JComponent ignored)
531 TableColumnModel cmod = header.getColumnModel();
532 TableCellRenderer defaultRend = header.getDefaultRenderer();
533 int ncols = cmod.getColumnCount();
534 Dimension ret = new Dimension(0,0);
535 int spacing = 0;
537 if (header.getTable() != null
538 && header.getTable().getIntercellSpacing() != null)
539 spacing = header.getTable().getIntercellSpacing().width;
541 for (int i = 0; i < ncols; ++i)
543 TableColumn col = cmod.getColumn(i);
544 TableCellRenderer rend = col.getHeaderRenderer();
545 if (rend == null)
546 rend = defaultRend;
547 Object val = col.getHeaderValue();
548 Component comp = rend.getTableCellRendererComponent(header.getTable(),
549 val,
550 false, // isSelected
551 false, // isFocused
552 -1, i);
553 comp.setFont(header.getFont());
554 comp.setBackground(header.getBackground());
555 comp.setForeground(header.getForeground());
556 if (comp instanceof JComponent)
557 ((JComponent)comp).setBorder(cellBorder);
559 Dimension d = comp.getPreferredSize();
560 ret.width += spacing;
561 ret.height = Math.max(d.height, ret.height);
563 ret.width = cmod.getTotalColumnWidth();
564 return ret;