diff options
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java')
-rw-r--r-- | libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java | 351 |
1 files changed, 334 insertions, 17 deletions
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java index 9c8a5ef9598..1e8e39f38c2 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -39,14 +39,18 @@ exception statement from your version. */ package javax.swing.plaf.basic; import java.awt.Component; +import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import javax.swing.CellRendererPane; import javax.swing.JComponent; import javax.swing.LookAndFeel; +import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.event.MouseInputListener; @@ -57,62 +61,346 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; +/** + * Basic pluggable look and feel interface for JTableHeader. + */ public class BasicTableHeaderUI extends TableHeaderUI { - + /** + * The width of the space (in both direction) around the column boundary, + * where mouse cursor changes shape into "resize" + */ + static int COLUMN_BOUNDARY_TOLERANCE = 3; + public static ComponentUI createUI(JComponent h) { return new BasicTableHeaderUI(); } - + + /** + * The table header that is using this interface. + */ protected JTableHeader header; + + /** + * The mouse input listener, responsible for mouse manipulations with + * the table header. + */ protected MouseInputListener mouseInputListener; + + /** + * Paint the header cell. + */ protected CellRendererPane rendererPane; + + /** + * The header cell border. + */ protected Border cellBorder; - - public class MouseInputHandler implements MouseInputListener + + /** + * If not null, one of the columns is currently being dragged. + */ + Rectangle draggingHeaderRect; + + /** + * Handles column movement and rearrangement by mouse. The same instance works + * both as mouse listener and the mouse motion listner. + */ + public class MouseInputHandler + implements MouseInputListener { + /** + * If true, the cursor is being already shown in the alternative "resize" + * shape. + */ + boolean showingResizeCursor; + + /** + * The position, from where the cursor is dragged during resizing. Double + * purpose field (absolute value during resizing and relative offset during + * column dragging). + */ + int draggingFrom = - 1; + + /** + * The number of the column being dragged. + */ + int draggingColumnNumber; + + /** + * The previous preferred width of the column. + */ + int prevPrefWidth = - 1; + + /** + * The timer to coalesce column resizing events. + */ + Timer timer; + + /** + * Returns without action, part of the MouseInputListener interface. + */ public void mouseClicked(MouseEvent e) { - // TODO: Implement this properly. + // Nothing to do. } + /** + * If being in the resizing mode, handle resizing. + */ public void mouseDragged(MouseEvent e) { - // TODO: Implement this properly. + TableColumn resizeIt = header.getResizingColumn(); + if (resizeIt != null && header.getResizingAllowed()) + { + // The timer is intialised on demand. + if (timer == null) + { + // The purpose of timer is to coalesce events. If the queue + // is free, the repaint event is fired immediately. + timer = new Timer(1, new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + header.getTable().doLayout(); + } + }); + timer.setRepeats(false); + timer.setCoalesce(true); + } + resizeIt.setPreferredWidth(prevPrefWidth + e.getX() - draggingFrom); + timer.restart(); + } + else if (draggingHeaderRect != null && header.getReorderingAllowed()) + { + draggingHeaderRect.x = e.getX() + draggingFrom; + header.repaint(); + } } + /** + * Returns without action, part of the MouseInputListener interface. + */ public void mouseEntered(MouseEvent e) { - // TODO: Implement this properly. + // Nothing to do. } + /** + * Reset drag information of the column resizing. + */ public void mouseExited(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingColumn() != null && header.getResizingAllowed()) + endResizing(); + if (header.getDraggedColumn() != null && header.getReorderingAllowed()) + endDragging(null); } + /** + * Change the mouse cursor if the mouse if above the column boundary. + */ public void mouseMoved(MouseEvent e) { - // TODO: Implement this properly. + // When dragging, the functionality is handled by the mouseDragged. + if (e.getButton() == 0 && header.getResizingAllowed()) + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n < 2) + // It must be at least two columns to have at least one boundary. + // Otherwise, nothing to do. + return; + + boolean onBoundary = false; + + int x = e.getX(); + int a = x - COLUMN_BOUNDARY_TOLERANCE; + int b = x + COLUMN_BOUNDARY_TOLERANCE; + + int p = 0; + + Scan: for (int i = 0; i < n - 1; i++) + { + p += model.getColumn(i).getWidth(); + + if (p >= a && p <= b) + { + TableColumn column = model.getColumn(i); + onBoundary = true; + + draggingFrom = x; + prevPrefWidth = column.getWidth(); + header.setResizingColumn(column); + break Scan; + } + } + + if (onBoundary != showingResizeCursor) + { + // Change the cursor shape, if needed. + if (onBoundary) + { + + if (p < x) + header.setCursor(Cursor.getPredefinedCursor + (Cursor.W_RESIZE_CURSOR)); + else + header.setCursor(Cursor.getPredefinedCursor + (Cursor.E_RESIZE_CURSOR)); + } + else + { + header.setCursor(Cursor.getDefaultCursor()); + header.setResizingColumn(null); + } + + showingResizeCursor = onBoundary; + } + } } + /** + * Starts the dragging/resizing procedure. + */ public void mousePressed(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingAllowed()) + { + TableColumn resizingColumn = header.getResizingColumn(); + if (resizingColumn != null) + { + resizingColumn.setPreferredWidth(resizingColumn.getWidth()); + return; + } + } + + if (header.getReorderingAllowed()) + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n < 2) + // It must be at least two columns to change the column location. + return; + + boolean onBoundary = false; + + int x = e.getX(); + int p = 0; + int col = - 1; + + Scan: for (int i = 0; i < n; i++) + { + p += model.getColumn(i).getWidth(); + if (p > x) + { + col = i; + break Scan; + } + } + if (col < 0) + return; + + TableColumn dragIt = model.getColumn(col); + header.setDraggedColumn(dragIt); + + draggingFrom = (p - dragIt.getWidth()) - x; + draggingHeaderRect = new Rectangle(header.getHeaderRect(col)); + draggingColumnNumber = col; + } } + /** + * Set all column preferred width to the current width to prevend abrupt + * width changes during the next resize. + */ public void mouseReleased(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingColumn() != null && header.getResizingAllowed()) + endResizing(); + if (header.getDraggedColumn() != null && header.getReorderingAllowed()) + endDragging(e); + } + + /** + * Stop resizing session. + */ + void endResizing() + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n > 2) + { + TableColumn c; + for (int i = 0; i < n; i++) + { + c = model.getColumn(i); + c.setPreferredWidth(c.getWidth()); + } + } + header.setResizingColumn(null); + showingResizeCursor = false; + if (timer != null) + timer.stop(); + header.setCursor(Cursor.getDefaultCursor()); } - } + /** + * Stop the dragging session. + * + * @param e the "mouse release" mouse event, needed to determing the final + * location for the dragged column. + */ + void endDragging(MouseEvent e) + { + header.setDraggedColumn(null); + + // Return if the mouse have left the header area while pressed. + if (e == null) + { + header.repaint(draggingHeaderRect); + draggingHeaderRect = null; + return; + } + else + draggingHeaderRect = null; + + TableColumnModel model = header.getColumnModel(); + + // Find where have we dragged the column. + int x = e.getX(); + int p = 0; + int col = - 1; + int n = model.getColumnCount(); + + Scan: for (int i = 0; i < n; i++) + { + p += model.getColumn(i).getWidth(); + if (p > x) + { + col = i; + break Scan; + } + } + if (col >= 0) + header.getTable().moveColumn(draggingColumnNumber, col); + } + } + + /** + * Create and return the mouse input listener. + * + * @return the mouse listener ({@link MouseInputHandler}, if not overridden. + */ protected MouseInputListener createMouseInputListener() { return new MouseInputHandler(); } - + + /** + * Construct a new BasicTableHeaderUI, create mouse listeners. + */ public BasicTableHeaderUI() { mouseInputListener = createMouseInputListener(); @@ -131,9 +419,15 @@ public class BasicTableHeaderUI extends TableHeaderUI // TODO: Implement this properly. } + /** + * Add the mouse listener and the mouse motion listener to the table + * header. The listeners support table column resizing and rearrangement + * by mouse. + */ protected void installListeners() { header.addMouseListener(mouseInputListener); + header.addMouseMotionListener(mouseInputListener); } public void installUI(JComponent c) @@ -156,10 +450,14 @@ public class BasicTableHeaderUI extends TableHeaderUI { // TODO: Implement this properly. } - + + /** + * Remove the previously installed listeners. + */ protected void uninstallListeners() { header.removeMouseListener(mouseInputListener); + header.removeMouseMotionListener(mouseInputListener); } public void uninstallUI(JComponent c) @@ -168,7 +466,10 @@ public class BasicTableHeaderUI extends TableHeaderUI uninstallKeyboardActions(); uninstallDefaults(); } - + + /** + * Repaint the table header. + */ public void paint(Graphics gfx, JComponent c) { TableColumnModel cmod = header.getColumnModel(); @@ -206,10 +507,26 @@ public class BasicTableHeaderUI extends TableHeaderUI bounds.width, bounds.height); } } - + + // This displays a running rectangle that is much simplier than the total + // animation, as it is seen in Sun's application. + // TODO animate the collumn dragging like in Sun's jre. + if (draggingHeaderRect!=null) + { + gfx.setColor(header.getForeground()); + gfx.drawRect(draggingHeaderRect.x, draggingHeaderRect.y+2, + draggingHeaderRect.width-1, draggingHeaderRect.height-6); + } } - public Dimension getPreferredSize(JComponent c) + /** + * Get the preferred header size. + * + * @param ignored unused + * + * @return the preferred size of the associated header. + */ + public Dimension getPreferredSize(JComponent ignored) { TableColumnModel cmod = header.getColumnModel(); TableCellRenderer defaultRend = header.getDefaultRenderer(); |