/* * @(#)BasicMarqueeHandler.java 1.0 03-JUL-04 * * Copyright (c) 2001-2004 Gaudenz Alder * */ package org.jgraph.graph; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import org.jgraph.JGraph; /** * A simple implementation of a marquee handler for JGraph. * * @version 1.0 1/1/02 * @author Gaudenz Alder */ @SuppressWarnings ( "all" ) public class BasicMarqueeHandler { /* Restore previous cursor after operation. */ protected transient Cursor previousCursor = null; /* The rectangle that defines the current marquee selection. */ protected Rectangle2D marqueeBounds; /* The start start and current point of the marquee session. */ protected Point2D startPoint, currentPoint; /* Return true if this handler should be preferred over other handlers. */ public boolean isForceMarqueeEvent(MouseEvent event) { return event.isAltDown(); } /** * Stops the current marquee selection. */ public void mouseReleased(MouseEvent e) { try { if (e != null && marqueeBounds != null) { if (!(e.getSource() instanceof JGraph)) throw new IllegalArgumentException("MarqueeHandler cannot " + "handle event from unknown source: " + e); JGraph graph = (JGraph) e.getSource(); Rectangle2D bounds = graph .fromScreen((Rectangle2D) marqueeBounds.clone()); handleMarqueeEvent(e, graph, bounds); graph.setCursor(previousCursor); Rectangle dirty = new Rectangle((int) marqueeBounds.getX(), (int) marqueeBounds.getY(), (int) marqueeBounds .getWidth() + 1, (int) marqueeBounds .getHeight() + 1); dirty.width++; dirty.height++; graph.repaint(dirty); } } finally { currentPoint = null; startPoint = null; marqueeBounds = null; previousCursor = null; } } /** * Hook for subclassers. Current implementation checks if graph selection is * enabled. This is called from mouseReleased to execute the marquee * selection. */ public void handleMarqueeEvent(MouseEvent e, JGraph graph, Rectangle2D bounds) { CellView[] views = graph.getGraphLayoutCache().getRoots(bounds); ArrayList list = new ArrayList(); for (int i = 0; i < views.length; i++) // above returns intersection, we want containment if (bounds.contains(views[i].getBounds())) list.add(views[i].getCell()); Object[] cells = list.toArray(); graph.getUI().selectCellsForEvent(graph, cells, e); } /** * Includes the specified startPoint in the marquee selection. Calls * overlay. */ public void mouseDragged(MouseEvent e) { if (startPoint != null) { if (!(e.getSource() instanceof JGraph)) throw new IllegalArgumentException( "MarqueeHandler cannot handle event from unknown source: " + e); JGraph graph = (JGraph) e.getSource(); Graphics g = graph.getGraphics(); // Xor the current display Color bg = graph.getBackground(); Color fg = graph.getMarqueeColor(); if (graph.isXorEnabled()) { g.setColor(fg); g.setXORMode(bg); overlay(graph, g, true); } Rectangle2D dirty = (Rectangle2D) marqueeBounds.clone(); processMouseDraggedEvent(e); // Repaint if (graph.isXorEnabled()) { g.setColor(bg); g.setXORMode(fg); overlay(graph, g, false); } else { dirty.add(marqueeBounds); graph.repaint((int) dirty.getX()-1, (int) dirty.getY()-1, (int) dirty.getWidth()+2, (int) dirty.getHeight()+2); } } } /** * Called from mouse dragged to update the marquee state during a repaint. */ protected void processMouseDraggedEvent(MouseEvent e) { if (startPoint != null) { currentPoint = e.getPoint(); marqueeBounds = new Rectangle2D.Double(startPoint.getX(), startPoint.getY(), 0, 0); marqueeBounds.add(currentPoint); } } /** * Called after the component was repainted (after autoscroll). This is used * to indicate that the graphics is no more dirty. */ public void paint(JGraph graph, Graphics g) { if (marqueeBounds != null) { if (graph.isXorEnabled()) { Color bg = graph.getBackground(); Color fg = graph.getMarqueeColor(); g.setColor(fg); g.setXORMode(bg); } overlay(graph, g, false); } } /** * Draw the current state of the handler. This is called twice by the * overlay method and also by the paint method. The caller's intention is * that the overlay method draws exactly the current state of the handler so * that it may be used for XOR paint. The drag method calls overlay, changes * the state, and calls overlay again to use this. However, since it is not * always possible to clear the screen with an exact repaint the caller * passes a flag to indicate if the graphics object should be cleared with * this call (eg. if a subsequent call follows). * * @param g */ public void overlay(JGraph graph, Graphics g, boolean clear) { if (marqueeBounds != null) { if (!graph.isXorEnabled()) { g.setColor(graph.getMarqueeColor()); } g.drawRect((int) marqueeBounds.getX(), (int) marqueeBounds.getY(), (int) marqueeBounds.getWidth(), (int) marqueeBounds .getHeight()); } } /** * Start the marquee at the specified startPoint. This invokes * expandMarqueeToPoint to initialize marquee selection. */ public void mousePressed(MouseEvent e) { startPoint = e.getPoint(); marqueeBounds = new Rectangle2D.Double(startPoint.getX(), startPoint .getY(), 0, 0); if (!(e.getSource() instanceof JGraph)) throw new IllegalArgumentException( "MarqueeHandler cannot handle event from unknown source: " + e); JGraph graph = (JGraph) e.getSource(); if (isMarqueeTriggerEvent(e, graph)) { previousCursor = graph.getCursor(); graph.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); } } /** * Hook for subclassers. Current implementation checks if graph selection is * enabled. This is called from mousePressed before initiating the marquee * selection. */ public boolean isMarqueeTriggerEvent(MouseEvent e, JGraph graph) { return graph.isSelectionEnabled(); } /** * Empty. */ public void mouseMoved(MouseEvent e) { // do nothing } /** * Returns the currentPoint. * * @return Point */ public Point2D getCurrentPoint() { return currentPoint; } /** * Returns the marqueeBounds. * * @return Rectangle */ public Rectangle2D getMarqueeBounds() { return marqueeBounds; } /** * Returns the previousCursor. * * @return Cursor */ public Cursor getPreviousCursor() { return previousCursor; } /** * Returns the startPoint. * * @return Point */ public Point2D getStartPoint() { return startPoint; } /** * Sets the currentPoint. * * @param currentPoint * The currentPoint to set */ public void setCurrentPoint(Point2D currentPoint) { this.currentPoint = currentPoint; } /** * Sets the marqueeBounds. * * @param marqueeBounds * The marqueeBounds to set */ public void setMarqueeBounds(Rectangle2D marqueeBounds) { this.marqueeBounds = marqueeBounds; } /** * Sets the previousCursor. * * @param previousCursor * The previousCursor to set */ public void setPreviousCursor(Cursor previousCursor) { this.previousCursor = previousCursor; } /** * Sets the startPoint. * * @param startPoint * The startPoint to set */ public void setStartPoint(Point2D startPoint) { this.startPoint = startPoint; } /** * @return Returns the source of the event as a graph. */ public static JGraph getGraphForEvent(MouseEvent event) { if (event.getSource() instanceof JGraph) return (JGraph) event.getSource(); return null; } }