Google Tag Manager

2025/01/31

Limit the area where TableColumns can be reordered by dragging

Limit the area where JTableHeader column reordering drags can be initiated to the top half of the TableColumn and perform mouse cursor changes and draw drag handle icons on the JLayer.

Code

class ColumnDragLayerUI extends LayerUI<JScrollPane> {
  private final Rectangle draggableRect = new Rectangle();

  @Override public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof JLayer) {
      ((JLayer<?>) c).setLayerEventMask(
          AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
    }
  }

  @Override public void uninstallUI(JComponent c) {
    if (c instanceof JLayer) {
      ((JLayer<?>) c).setLayerEventMask(0);
    }
    super.uninstallUI(c);
  }

  @Override public void paint(Graphics g, JComponent c) {
    super.paint(g, c);
    if (!draggableRect.isEmpty()) {
      Graphics2D g2 = (Graphics2D) g.create();
      // g2.fill(draggableRect);
      Icon icon = new DragAreaIcon();
      int x = (int) (draggableRect.getCenterX() - icon.getIconWidth() / 2d);
      int y = draggableRect.y + 1;
      icon.paintIcon(c, g2, x, y);
      g2.dispose();
    }
  }

  @Override protected void processMouseEvent(
      MouseEvent e, JLayer<? extends JScrollPane> l) {
    super.processMouseEvent(e, l);
    Component c = e.getComponent();
    if (c instanceof JTableHeader) {
      JTableHeader header = (JTableHeader) c;
      if (e.getID() == MouseEvent.MOUSE_PRESSED) {
        Point pt = e.getPoint();
        updateIconAndCursor(header, pt, l);
      } else if (e.getID() == MouseEvent.MOUSE_RELEASED) {
        header.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        draggableRect.setSize(0, 0);
      }
    }
  }

  @Override protected void processMouseMotionEvent(
      MouseEvent e, JLayer<? extends JScrollPane> l) {
    Component c = e.getComponent();
    if (c instanceof JTableHeader) {
      JTableHeader header = (JTableHeader) c;
      if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
        TableColumn draggedColumn = header.getDraggedColumn();
        if (!draggableRect.isEmpty() && draggedColumn != null) {
          EventQueue.invokeLater(() -> {
            int modelIndex = draggedColumn.getModelIndex();
            int viewIndex = header.getTable().convertColumnIndexToView(modelIndex);
            Rectangle rect = header.getHeaderRect(viewIndex);
            rect.x += header.getDraggedDistance();
            draggableRect.setRect(SwingUtilities.convertRectangle(header, rect, l));
            header.repaint(rect);
          });
        } else {
          e.consume(); // Refuse to start drag
        }
      } else if (e.getID() == MouseEvent.MOUSE_MOVED) {
        Point pt = e.getPoint();
        updateIconAndCursor(header, pt, l);
        header.repaint();
      }
    } else {
      c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      draggableRect.setSize(0, 0);
    }
  }

  private void updateIconAndCursor(JTableHeader header, Point pt, JLayer<?> l) {
    Rectangle r = header.getHeaderRect(header.columnAtPoint(pt));
    r.height /= 2;
    if (r.contains(pt)) {
      header.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
      draggableRect.setRect(SwingUtilities.convertRectangle(header, r, l));
    } else {
      header.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      draggableRect.setSize(0, 0);
    }
  }
}

References

No comments:

Post a Comment