001: /*
002: * @(#)BasicMarqueeHandler.java 1.0 03-JUL-04
003: *
004: * Copyright (c) 2001-2004 Gaudenz Alder
005: *
006: */
007: package org.jgraph.graph;
008:
009: import java.awt.Color;
010: import java.awt.Cursor;
011: import java.awt.Graphics;
012: import java.awt.Rectangle;
013: import java.awt.event.MouseEvent;
014: import java.awt.geom.Point2D;
015: import java.awt.geom.Rectangle2D;
016: import java.util.ArrayList;
017:
018: import org.jgraph.JGraph;
019:
020: /**
021: * A simple implementation of a marquee handler for JGraph.
022: *
023: * @version 1.0 1/1/02
024: * @author Gaudenz Alder
025: */
026:
027: public class BasicMarqueeHandler {
028:
029: /* Restore previous cursor after operation. */
030: protected transient Cursor previousCursor = null;
031:
032: /* The rectangle that defines the current marquee selection. */
033: protected Rectangle2D marqueeBounds;
034:
035: /* The start start and current point of the marquee session. */
036: protected Point2D startPoint, currentPoint;
037:
038: /* Return true if this handler should be preferred over other handlers. */
039: public boolean isForceMarqueeEvent(MouseEvent event) {
040: return event.isAltDown();
041: }
042:
043: /**
044: * Stops the current marquee selection.
045: */
046: public void mouseReleased(MouseEvent e) {
047: try {
048: if (e != null && marqueeBounds != null) {
049: if (!(e.getSource() instanceof JGraph))
050: throw new IllegalArgumentException(
051: "MarqueeHandler cannot "
052: + "handle event from unknown source: "
053: + e);
054: JGraph graph = (JGraph) e.getSource();
055: Rectangle2D bounds = graph
056: .fromScreen((Rectangle2D) marqueeBounds.clone());
057: handleMarqueeEvent(e, graph, bounds);
058: graph.setCursor(previousCursor);
059: Rectangle dirty = new Rectangle((int) marqueeBounds
060: .getX(), (int) marqueeBounds.getY(),
061: (int) marqueeBounds.getWidth() + 1,
062: (int) marqueeBounds.getHeight() + 1);
063: dirty.width++;
064: dirty.height++;
065: graph.repaint(dirty);
066: }
067: } finally {
068: currentPoint = null;
069: startPoint = null;
070: marqueeBounds = null;
071: previousCursor = null;
072: }
073: }
074:
075: /**
076: * Hook for subclassers. Current implementation checks if graph selection is
077: * enabled. This is called from mouseReleased to execute the marquee
078: * selection.
079: */
080: public void handleMarqueeEvent(MouseEvent e, JGraph graph,
081: Rectangle2D bounds) {
082: CellView[] views = graph.getGraphLayoutCache().getRoots(bounds);
083: ArrayList list = new ArrayList();
084: for (int i = 0; i < views.length; i++)
085: // above returns intersection, we want containment
086: if (bounds.contains(views[i].getBounds()))
087: list.add(views[i].getCell());
088: Object[] cells = list.toArray();
089: graph.getUI().selectCellsForEvent(graph, cells, e);
090: }
091:
092: /**
093: * Includes the specified startPoint in the marquee selection. Calls
094: * overlay.
095: */
096: public void mouseDragged(MouseEvent e) {
097: if (startPoint != null) {
098: if (!(e.getSource() instanceof JGraph))
099: throw new IllegalArgumentException(
100: "MarqueeHandler cannot handle event from unknown source: "
101: + e);
102: JGraph graph = (JGraph) e.getSource();
103: Graphics g = graph.getGraphics();
104:
105: // Xor the current display
106: Color bg = graph.getBackground();
107: Color fg = graph.getMarqueeColor();
108: if (graph.isXorEnabled()) {
109: g.setColor(fg);
110: g.setXORMode(bg);
111: overlay(graph, g, true);
112: }
113: Rectangle2D dirty = (Rectangle2D) marqueeBounds.clone();
114: processMouseDraggedEvent(e);
115:
116: // Repaint
117: if (graph.isXorEnabled()) {
118: g.setColor(bg);
119: g.setXORMode(fg);
120: overlay(graph, g, false);
121: } else {
122: dirty.add(marqueeBounds);
123: graph.repaint((int) dirty.getX() - 1, (int) dirty
124: .getY() - 1, (int) dirty.getWidth() + 2,
125: (int) dirty.getHeight() + 2);
126: }
127: }
128: }
129:
130: /**
131: * Called from mouse dragged to update the marquee state during a repaint.
132: */
133: protected void processMouseDraggedEvent(MouseEvent e) {
134: if (startPoint != null) {
135: currentPoint = e.getPoint();
136: marqueeBounds = new Rectangle2D.Double(startPoint.getX(),
137: startPoint.getY(), 0, 0);
138: marqueeBounds.add(currentPoint);
139: }
140: }
141:
142: /**
143: * Called after the component was repainted (after autoscroll). This is used
144: * to indicate that the graphics is no more dirty.
145: */
146: public void paint(JGraph graph, Graphics g) {
147: if (marqueeBounds != null) {
148: if (graph.isXorEnabled()) {
149: Color bg = graph.getBackground();
150: Color fg = graph.getMarqueeColor();
151: g.setColor(fg);
152: g.setXORMode(bg);
153: }
154: overlay(graph, g, false);
155: }
156: }
157:
158: /**
159: * Draw the current state of the handler. This is called twice by the
160: * overlay method and also by the paint method. The caller's intention is
161: * that the overlay method draws exactly the current state of the handler so
162: * that it may be used for XOR paint. The drag method calls overlay, changes
163: * the state, and calls overlay again to use this. However, since it is not
164: * always possible to clear the screen with an exact repaint the caller
165: * passes a flag to indicate if the graphics object should be cleared with
166: * this call (eg. if a subsequent call follows).
167: *
168: * @param g
169: */
170: public void overlay(JGraph graph, Graphics g, boolean clear) {
171: if (marqueeBounds != null) {
172: if (!graph.isXorEnabled()) {
173: g.setColor(graph.getMarqueeColor());
174: }
175: g.drawRect((int) marqueeBounds.getX(), (int) marqueeBounds
176: .getY(), (int) marqueeBounds.getWidth(),
177: (int) marqueeBounds.getHeight());
178: }
179: }
180:
181: /**
182: * Start the marquee at the specified startPoint. This invokes
183: * expandMarqueeToPoint to initialize marquee selection.
184: */
185: public void mousePressed(MouseEvent e) {
186: startPoint = e.getPoint();
187: marqueeBounds = new Rectangle2D.Double(startPoint.getX(),
188: startPoint.getY(), 0, 0);
189: if (!(e.getSource() instanceof JGraph))
190: throw new IllegalArgumentException(
191: "MarqueeHandler cannot handle event from unknown source: "
192: + e);
193: JGraph graph = (JGraph) e.getSource();
194: if (isMarqueeTriggerEvent(e, graph)) {
195: previousCursor = graph.getCursor();
196: graph.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
197: }
198: }
199:
200: /**
201: * Hook for subclassers. Current implementation checks if graph selection is
202: * enabled. This is called from mousePressed before initiating the marquee
203: * selection.
204: */
205: public boolean isMarqueeTriggerEvent(MouseEvent e, JGraph graph) {
206: return graph.isSelectionEnabled();
207: }
208:
209: /**
210: * Empty.
211: */
212: public void mouseMoved(MouseEvent e) {
213: // do nothing
214: }
215:
216: /**
217: * Returns the currentPoint.
218: *
219: * @return Point
220: */
221: public Point2D getCurrentPoint() {
222: return currentPoint;
223: }
224:
225: /**
226: * Returns the marqueeBounds.
227: *
228: * @return Rectangle
229: */
230: public Rectangle2D getMarqueeBounds() {
231: return marqueeBounds;
232: }
233:
234: /**
235: * Returns the previousCursor.
236: *
237: * @return Cursor
238: */
239: public Cursor getPreviousCursor() {
240: return previousCursor;
241: }
242:
243: /**
244: * Returns the startPoint.
245: *
246: * @return Point
247: */
248: public Point2D getStartPoint() {
249: return startPoint;
250: }
251:
252: /**
253: * Sets the currentPoint.
254: *
255: * @param currentPoint
256: * The currentPoint to set
257: */
258: public void setCurrentPoint(Point2D currentPoint) {
259: this .currentPoint = currentPoint;
260: }
261:
262: /**
263: * Sets the marqueeBounds.
264: *
265: * @param marqueeBounds
266: * The marqueeBounds to set
267: */
268: public void setMarqueeBounds(Rectangle2D marqueeBounds) {
269: this .marqueeBounds = marqueeBounds;
270: }
271:
272: /**
273: * Sets the previousCursor.
274: *
275: * @param previousCursor
276: * The previousCursor to set
277: */
278: public void setPreviousCursor(Cursor previousCursor) {
279: this .previousCursor = previousCursor;
280: }
281:
282: /**
283: * Sets the startPoint.
284: *
285: * @param startPoint
286: * The startPoint to set
287: */
288: public void setStartPoint(Point2D startPoint) {
289: this .startPoint = startPoint;
290: }
291:
292: /**
293: * @return Returns the source of the event as a graph.
294: */
295: public static JGraph getGraphForEvent(MouseEvent event) {
296: if (event.getSource() instanceof JGraph)
297: return (JGraph) event.getSource();
298: return null;
299: }
300:
301: }
|