001: /*
002: * $Id: JGraphpadMarqueeHandler.java,v 1.4 2005/09/18 08:39:51 gaudenz Exp $
003: * Copyright (c) 2001-2005, Gaudenz Alder
004: *
005: * All rights reserved.
006: *
007: * See LICENSE file for license details. If you are unable to locate
008: * this file please contact info (at) jgraph (dot) com.
009: */
010: package com.jgraph.pad.graph;
011:
012: import java.awt.Component;
013: import java.awt.event.MouseEvent;
014: import java.awt.geom.Point2D;
015: import java.awt.geom.Rectangle2D;
016:
017: import javax.swing.JPopupMenu;
018: import javax.swing.SwingUtilities;
019:
020: import org.jgraph.JGraph;
021: import org.jgraph.graph.BasicMarqueeHandler;
022: import org.jgraph.graph.CellView;
023: import org.jgraph.graph.DefaultGraphModel;
024: import org.w3c.dom.Node;
025:
026: import com.jgraph.JGraphEditor;
027: import com.jgraph.JGraphpad;
028: import com.jgraph.editor.JGraphEditorSettings;
029:
030: /**
031: * Marquee handler that implements popup menus and folding (by icon). This
032: * implements the event processing order for all graphs in the following way:
033: * <ul>
034: * <li>If a folding icon is under the mouse pointer all processing is blocked
035: * until the mouse is released. On release, the group's collapsed state is
036: * toggled and the group is selected.</li>
037: * <li>If the right mouse button is used without holding down the shift key
038: * then a popup menu is displayed. If there is a cell under the mouse pointer
039: * which is not selected, then the cell is selected on mouse down. If the mouse
040: * is right-clicked on the background then the selection is cleared before the
041: * popup is displayed.</li>
042: * </li>
043: * </ul>
044: */
045: public class JGraphpadMarqueeHandler extends BasicMarqueeHandler {
046:
047: /**
048: * Defines the nodename used to configure the graphpopupmenu.
049: */
050: public static String NODENAME_GRAPHPOPUPMENU = "graphpopupmenu";
051:
052: /**
053: * Defines the nodename used to configure the cellpopupmenu.
054: */
055: public static String NODENAME_CELLPOPUPMENU = "cellpopupmenu";
056:
057: /**
058: * References the enclosing editor. The editor is used to configure and
059: * create the popup menus.
060: */
061: protected JGraphEditor editor = null;
062:
063: /**
064: * Holds the group view if the interaction started on a folding icon.
065: */
066: protected CellView groupView = null;
067:
068: /**
069: * Constructs a new editor using the specified editor to configure and
070: * create popup menus.
071: *
072: * @param editor
073: * The enclosing editor.
074: */
075: public JGraphpadMarqueeHandler(JGraphEditor editor) {
076: this .editor = editor;
077: }
078:
079: /**
080: * Extends the parent's implementation to implement the event processing
081: * order.
082: *
083: * @param event
084: * The object that describes the event.
085: */
086: public boolean isForceMarqueeEvent(MouseEvent event) {
087: JGraph graph = getGraphForEvent(event);
088:
089: // Checks if the popup menu should be triggered and fetches
090: // control for further event processing.
091: if (SwingUtilities.isRightMouseButton(event)
092: && !event.isShiftDown())
093: return true;
094:
095: // Checks if a folding icon is under the mouse pointer
096: // and stores the respective view in group view to block
097: // further event processing until mouseReleased is reached.
098: groupView = getGroupByFoldingHandle(graph, graph
099: .fromScreen((Point2D) event.getPoint().clone()));
100: if (groupView != null)
101: return true;
102:
103: return super .isForceMarqueeEvent(event);
104: }
105:
106: /**
107: * Overrides the parent's implementation to either block processing if a
108: * group view is scheduled to be collapsed/expanded or immediately select
109: * the cell under the mouse pointer if it is not selected.
110: *
111: * @param event
112: * The object that describes the event.
113: */
114: public void mousePressed(MouseEvent event) {
115: JGraph graph = getGraphForEvent(event);
116:
117: // Blocks processing if a folding icon was clicked
118: if (groupView != null)
119: event.consume();
120:
121: // Immediately selects unselected cells under the mouse
122: else if (graph.getSelectionCellAt(event.getPoint()) == null) {
123: Point2D pt = graph.fromScreen((Point2D) event.getPoint()
124: .clone());
125: CellView view = graph.getTopmostViewAt(pt.getX(),
126: pt.getY(), false, false);
127: if (view != null)
128: graph.getUI().selectCellsForEvent(graph,
129: new Object[] { view.getCell() }, event);
130: else
131: graph.clearSelection();
132: }
133: }
134:
135: /**
136: * Overrides the parent's implementation to display a popup menu using
137: * {@link #getPopupMenuConfiguration(MouseEvent)} to obtain the
138: * configuration or toggle the collapsed state of {@link #groupView} and
139: * select the respective cell. The state of the handler is reset after event
140: * processing.
141: *
142: * @param e
143: * The object that describes the event.
144: */
145: public void mouseReleased(MouseEvent e) {
146: if (SwingUtilities.isRightMouseButton(e)) {
147:
148: // Displays a popup menu by obtaining the menu configuration
149: // for the event. The menu configuration is created based
150: // on the current selection in the event source.
151: Node configuration = getPopupMenuConfiguration(e);
152: if (configuration != null) {
153: JPopupMenu popupMenu = editor.getFactory()
154: .createPopupMenu(configuration);
155: popupMenu.setFocusable(false);
156: popupMenu.show(e.getComponent(), e.getX(), e.getY());
157: e.consume();
158: }
159: }
160:
161: // Toggles the collapsed state of the group view, selects
162: // the group cell and resets the state of the handle.
163: else if (groupView != null) {
164: JGraph graph = getGraphForEvent(e);
165: graph.getGraphLayoutCache().toggleCollapsedState(
166: new Object[] { groupView.getCell() }, false, false);
167: graph.setSelectionCell(groupView.getCell());
168: groupView = null;
169: e.consume();
170: }
171:
172: // Else call parent's implementation
173: else
174: super .mouseReleased(e);
175: }
176:
177: /**
178: * Returns the popup menu configuration for the specified event. This
179: * implementation looks at the event source and returns a
180: * {@link #NODENAME_CELLPOPUPMENU} or {@link #NODENAME_GRAPHPOPUPMENU}
181: * configuration based on the selection state of the graph.
182: *
183: * @param event
184: * The event that triggered the display of the popup menu.
185: * @return Returns the popup menu configuration for <code>event</code>.
186: */
187: protected Node getPopupMenuConfiguration(MouseEvent event) {
188: JGraph graph = getGraphForEvent(event);
189: return JGraphEditorSettings.getNodeByName(editor.getSettings()
190: .getDocument(JGraphpad.NAME_UICONFIG)
191: .getDocumentElement().getChildNodes(), (graph
192: .isSelectionEmpty()) ? NODENAME_GRAPHPOPUPMENU
193: : NODENAME_CELLPOPUPMENU);
194: }
195:
196: /**
197: * Returns the cell view at the specified location if the location is over
198: * the cell view's folding icon.
199: *
200: * @param graph
201: * The graph to get the cell views from.
202: * @param pt
203: * The location to check for a folding icon.
204: * @return Returns the topmost cell view who's folding icon is under the
205: * mouse pointer.
206: */
207: protected CellView getGroupByFoldingHandle(JGraph graph, Point2D pt) {
208: CellView[] views = graph.getGraphLayoutCache().getCellViews();
209: for (int i = 0; i < views.length; i++) {
210: if (views[i].getBounds().contains(pt.getX(), pt.getY())) {
211: Rectangle2D rectBounds = views[i].getBounds();
212: Point2D containerPoint = (Point2D) pt.clone();
213: containerPoint.setLocation(containerPoint.getX()
214: - rectBounds.getX(), containerPoint.getY()
215: - rectBounds.getY());
216: Component renderer = views[i].getRendererComponent(
217: graph, false, false, false);
218: if (renderer instanceof JGraphpadVertexRenderer
219: && DefaultGraphModel.isGroup(graph.getModel(),
220: views[i].getCell())) {
221: JGraphpadVertexRenderer group = (JGraphpadVertexRenderer) renderer;
222: if (group.inHitRegion(containerPoint)) {
223: return views[i];
224: }
225: }
226: }
227: }
228: return null;
229: }
230: }
|