summaryrefslogtreecommitdiffstats
path: root/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java')
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java351
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();
OpenPOWER on IntegriCloud