001: /*
002: * $Id: JGraphpadCellAction.java,v 1.4 2005/10/15 16:36:17 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.action;
011:
012: import java.awt.event.ActionEvent;
013: import java.awt.geom.Point2D;
014: import java.awt.geom.Rectangle2D;
015: import java.util.ArrayList;
016: import java.util.HashSet;
017: import java.util.Hashtable;
018: import java.util.Iterator;
019: import java.util.LinkedList;
020: import java.util.List;
021: import java.util.Map;
022:
023: import javax.swing.SwingConstants;
024:
025: import org.jgraph.JGraph;
026: import org.jgraph.graph.AttributeMap;
027: import org.jgraph.graph.CellView;
028: import org.jgraph.graph.ConnectionSet;
029: import org.jgraph.graph.DefaultGraphModel;
030: import org.jgraph.graph.GraphConstants;
031: import org.jgraph.graph.GraphLayoutCache;
032: import org.jgraph.graph.GraphModel;
033: import org.jgraph.graph.ParentMap;
034: import org.jgraph.graph.PortView;
035:
036: import com.jgraph.JGraphEditor;
037: import com.jgraph.JGraphpad;
038: import com.jgraph.editor.JGraphEditorAction;
039: import com.jgraph.pad.dialog.JGraphpadDialogs;
040: import com.jgraph.pad.factory.JGraphpadLibraryPane;
041: import com.jgraph.pad.graph.JGraphpadBusinessObject;
042: import com.jgraph.pad.graph.JGraphpadGraphConstants;
043: import com.jgraph.pad.graph.JGraphpadGraphModel;
044:
045: /**
046: * Implements all actions of the cell menu. Extends format action to use some of
047: * the helper methods.
048: */
049: public class JGraphpadCellAction extends JGraphpadFormatAction {
050:
051: /**
052: * Defines the constants to be passed to {@link #doAlignCells(JGraph, int)}.
053: */
054: public static final int ALIGN_LEFT = SwingConstants.LEFT,
055: ALIGN_RIGHT = SwingConstants.RIGHT,
056: ALIGN_TOP = SwingConstants.TOP,
057: ALIGN_BOTTOM = SwingConstants.BOTTOM,
058: ALIGN_CENTER = SwingConstants.CENTER,
059: ALIGN_MIDDLE = SwingConstants.NEXT;
060:
061: /**
062: * Key under which the cell prototype is stored in the actions values. This
063: * is used to store the prototype for connect and group actions, which
064: * require to create new edges and groups respectively.
065: */
066: public static final String KEY_PROTOTYPE = "prototype";
067:
068: /**
069: * Specifies the name for the <code>cloneValue</code> action.
070: */
071: public static final String NAME_CLONEVALUE = "cloneValue";
072:
073: /**
074: * Specifies the name for the <code>cloneSize</code> action.
075: */
076: public static final String NAME_CLONESIZE = "cloneSize";
077:
078: /**
079: * Specifies the name for the <code>cloneAttributes</code> action.
080: */
081: public static final String NAME_CLONEATTRIBUTES = "cloneAttributes";
082:
083: /**
084: * Specifies the name for the <code>cellsAlignTop</code> action.
085: */
086: public static final String NAME_CELLSALIGNTOP = "cellsAlignTop";
087:
088: /**
089: * Specifies the name for the <code>cellsAlignMiddle</code> action.
090: */
091: public static final String NAME_CELLSALIGNMIDDLE = "cellsAlignMiddle";
092:
093: /**
094: * Specifies the name for the <code>cellsAlignBottom</code> action.
095: */
096: public static final String NAME_CELLSALIGNBOTTOM = "cellsAlignBottom";
097:
098: /**
099: * Specifies the name for the <code>cellsAlignLeft</code> action.
100: */
101: public static final String NAME_CELLSALIGNLEFT = "cellsAlignLeft";
102:
103: /**
104: * Specifies the name for the <code>cellsAlignCenter</code> action.
105: */
106: public static final String NAME_CELLSALIGNCENTER = "cellsAlignCenter";
107:
108: /**
109: * Specifies the name for the <code>cellsAlignRight</code> action.
110: */
111: public static final String NAME_CELLSALIGNRIGHT = "cellsAlignRight";
112:
113: /**
114: * Specifies the name for the <code>toggleSelectable</code> action.
115: */
116: public static final String NAME_TOGGLESELECTABLE = "toggleSelectable";
117:
118: /**
119: * Specifies the name for the <code>allSelectable</code> action.
120: */
121: public static final String NAME_ALLSELECTABLE = "allSelectable";
122:
123: /**
124: * Specifies the name for the <code>toggleChildrenSelectable</code>
125: * action.
126: */
127: public static final String NAME_TOGGLECHILDRENSELECTABLE = "toggleChildrenSelectable";
128:
129: /**
130: * Specifies the name for the <code>collapse</code> action.
131: */
132: public static final String NAME_COLLAPSE = "collapse";
133:
134: /**
135: * Specifies the name for the <code>collapse</code> action.
136: */
137: public static final String NAME_TOGGLECOLLAPSED = "toggleCollapsed";
138:
139: /**
140: * Specifies the name for the <code>expand</code> action.
141: */
142: public static final String NAME_EXPAND = "expand";
143:
144: /**
145: * Specifies the name for the <code>expandAll</code> action.
146: */
147: public static final String NAME_EXPANDALL = "expandAll";
148:
149: /**
150: * Specifies the name for the <code>toBack</code> action.
151: */
152: public static final String NAME_TOBACK = "toBack";
153:
154: /**
155: * Specifies the name for the <code>toFront</code> action.
156: */
157: public static final String NAME_TOFRONT = "toFront";
158:
159: /**
160: * Specifies the name for the <code>group</code> action.
161: */
162: public static final String NAME_GROUP = "group";
163:
164: /**
165: * Specifies the name for the <code>groupAsEdge</code> action.
166: */
167: public static final String NAME_GROUPASEDGE = "groupAsEdge";
168:
169: /**
170: * Specifies the name for the <code>ungroup</code> action.
171: */
172: public static final String NAME_UNGROUP = "ungroup";
173:
174: /**
175: * Specifies the name for the <code>removeFromGroup</code> action.
176: */
177: public static final String NAME_REMOVEFROMGROUP = "removeFromGroup";
178:
179: /**
180: * Specifies the name for the <code>connect</code> action.
181: */
182: public static final String NAME_CONNECT = "connect";
183:
184: /**
185: * Specifies the name for the <code>disconnect</code> action.
186: */
187: public static final String NAME_DISCONNECT = "disconnect";
188:
189: /**
190: * Specifies the name for the <code>addProperty</code> action.
191: */
192: public static final String NAME_ADDPROPERTY = "addProperty";
193:
194: /**
195: * Specifies the name for the <code>removeProperty</code> action.
196: */
197: public static final String NAME_REMOVEPROPERTY = "removeProperty";
198:
199: /**
200: * Specifies the name for the <code>invert</code> action.
201: */
202: public static final String NAME_INVERT = "invert";
203:
204: /**
205: * Constructs a new cell action for the specified name. If the action name
206: * starts with <code>toggle</code> or <code>switch</code> then the
207: * action is configured to be a toggle action.
208: *
209: * @param name
210: * The name of the action to be created.
211: */
212: public JGraphpadCellAction(String name) {
213: super (name);
214: setToggleAction(name.startsWith("toggle")
215: || name.startsWith("switch")
216: && name.equals(NAME_TOGGLECOLLAPSED));
217: }
218:
219: /**
220: * Executes the action based on the action name.
221: *
222: * @param e
223: * The object that describes the event.
224: */
225: public void actionPerformed(ActionEvent e) {
226:
227: // Fetches the focus owner before showing dialogs
228: JGraph graph = getPermanentFocusOwnerGraph();
229: if (graph != null) {
230: GraphLayoutCache cache = graph.getGraphLayoutCache();
231: if (getName().equals(NAME_CLONEVALUE))
232: doClone(graph, true, false);
233: else if (getName().equals(NAME_CLONESIZE))
234: doClone(graph, false, true);
235: else if (getName().equals(NAME_CLONEATTRIBUTES))
236: doClone(graph, false, false);
237: else if (getName().equals(NAME_CELLSALIGNTOP))
238: doAlignCells(graph, ALIGN_TOP);
239: else if (getName().equals(NAME_CELLSALIGNMIDDLE))
240: doAlignCells(graph, ALIGN_MIDDLE);
241: else if (getName().equals(NAME_CELLSALIGNBOTTOM))
242: doAlignCells(graph, ALIGN_BOTTOM);
243: else if (getName().equals(NAME_CELLSALIGNLEFT))
244: doAlignCells(graph, ALIGN_LEFT);
245: else if (getName().equals(NAME_CELLSALIGNCENTER))
246: doAlignCells(graph, ALIGN_CENTER);
247: else if (getName().equals(NAME_CELLSALIGNRIGHT))
248: doAlignCells(graph, ALIGN_RIGHT);
249: else if (getName().equals(NAME_TOGGLESELECTABLE))
250: doToggleAttribute(graph, GraphConstants.SELECTABLE,
251: true);
252: else if (getName().equals(NAME_TOGGLECHILDRENSELECTABLE))
253: doToggleAttribute(graph,
254: GraphConstants.CHILDRENSELECTABLE, true);
255: else if (getName().equals(NAME_ALLSELECTABLE))
256: setAttributes(graph,
257: new String[] { GraphConstants.SELECTABLE },
258: new Object[] { null }, true);
259: else if (getName().equals(NAME_TOGGLECOLLAPSED))
260: cache.toggleCollapsedState(graph.getSelectionCells(),
261: false, false);
262: else if (getName().equals(NAME_COLLAPSE))
263: cache.toggleCollapsedState(graph.getSelectionCells(),
264: true, false);
265: else if (getName().equals(NAME_EXPAND))
266: cache.toggleCollapsedState(graph.getSelectionCells(),
267: false, true);
268: else if (getName().equals(NAME_EXPANDALL))
269: cache.toggleCollapsedState(graph.getDescendants(graph
270: .getSelectionCells()), false, true);
271: else if (getName().equals(NAME_TOBACK))
272: graph.getGraphLayoutCache().toBack(
273: graph.getSelectionCells());
274: else if (getName().equals(NAME_TOFRONT))
275: graph.getGraphLayoutCache().toFront(
276: graph.getSelectionCells());
277: else if (getName().equals(NAME_GROUP))
278: doGroup(graph, getValue(KEY_PROTOTYPE));
279: else if (getName().equals(NAME_GROUPASEDGE))
280: doGroupAsEdge(graph, getValue(KEY_PROTOTYPE));
281: else if (getName().equals(NAME_REMOVEFROMGROUP))
282: graph.getGraphLayoutCache().edit(null, null,
283: new ParentMap(graph.getSelectionCells(), null),
284: null);
285: else if (getName().equals(NAME_UNGROUP))
286: graph.setSelectionCells(graph.getGraphLayoutCache()
287: .ungroup(graph.getSelectionCells()));
288: else if (getName().equals(NAME_CONNECT))
289: doConnect(graph, getValue(KEY_PROTOTYPE));
290: else if (getName().equals(NAME_DISCONNECT))
291: doDisconnect(graph);
292: else if (getName().equals(NAME_ADDPROPERTY))
293: doCellProperty(graph, true);
294: else if (getName().equals(NAME_REMOVEPROPERTY))
295: doCellProperty(graph, false);
296: else if (getName().equals(NAME_INVERT))
297: doInvert(graph);
298: }
299:
300: // Fetches the focus owner before showing dialogs
301: JGraphpadLibraryPane libraryPane = JGraphpadFileAction
302: .getPermanentFocusOwnerLibraryPane();
303: if (libraryPane != null && !libraryPane.isReadOnly()) {
304: if (getName().equals(NAME_TOBACK))
305: libraryPane.sendEntryToBack();
306: else if (getName().equals(NAME_TOFRONT))
307: libraryPane.bringEntryToFront();
308: }
309: }
310:
311: /**
312: * Inverts all selected cells by swapping the source and target of edges and
313: * inverting all control points, or by swapping width and height of
314: * vertices.
315: *
316: * @param graph
317: * The graph to perform the operation in.
318: */
319: protected void doInvert(JGraph graph) {
320: if (!graph.isSelectionEmpty()) {
321: CellView[] views = graph.getGraphLayoutCache().getMapping(
322: graph.getSelectionCells());
323: ConnectionSet cs = new ConnectionSet();
324: Map nested = new Hashtable();
325: GraphModel model = graph.getModel();
326: for (int i = 0; i < views.length; i++) {
327: Object cell = views[i].getCell();
328: Map change = new Hashtable();
329: Rectangle2D bounds = GraphConstants.getBounds(views[i]
330: .getAllAttributes());
331: if (model.isEdge(cell)) {
332:
333: // Swaps source and target port
334: Object source = model.getSource(cell);
335: Object target = model.getTarget(cell);
336: if (source != null)
337: cs.connect(cell, source, false);
338: if (target != null)
339: cs.connect(cell, target, true);
340:
341: // Inverts the control points
342: List pts = GraphConstants.getPoints(views[i]
343: .getAllAttributes());
344: if (pts != null) {
345: LinkedList inverted = new LinkedList();
346: Iterator it = pts.iterator();
347: while (it.hasNext())
348: inverted.addFirst(it.next());
349: GraphConstants.setPoints(change, inverted);
350: }
351: }
352:
353: // Inverts the bounds
354: else if (bounds != null) {
355: bounds = new Rectangle2D.Double(bounds.getX(),
356: bounds.getY(), bounds.getHeight(), bounds
357: .getWidth());
358: GraphConstants.setBounds(change, bounds);
359: }
360: if (!change.isEmpty())
361: nested.put(cell, change);
362: }
363: graph.getGraphLayoutCache().edit(nested, cs, null, null);
364: }
365: }
366:
367: /**
368: * Displays a value dialog and adds or removes the entered value as a
369: * property to/from the user objects of the selection cells.
370: *
371: * @param graph
372: * The graph to perform the operation in.
373: * @param add
374: * Whether the property should be added or removed.
375: */
376: protected void doCellProperty(JGraph graph, boolean add) {
377: if (!graph.isSelectionEmpty()) {
378: String property = JGraphpadDialogs.getSharedInstance()
379: .valueDialog(getString("EnterPropertyName"));
380: if (property != null) {
381: Object[] cells = graph.getSelectionCells();
382:
383: // Contains the shared change description
384: Map change = new Hashtable();
385: change.put(property, (add) ? ""
386: : JGraphpadGraphModel.VALUE_EMPTY);
387:
388: // Creates a nested map for all business objects
389: Map nested = new Hashtable();
390: for (int i = 0; i < cells.length; i++) {
391: Object obj = graph.getModel().getValue(cells[i]);
392: if (obj instanceof JGraphpadBusinessObject)
393: nested.put(obj, change);
394: }
395:
396: // Calls the model instead of the layout cache
397: // to update the business objects
398: if (nested != null)
399: graph.getModel().edit(nested, null, null, null);
400: }
401: }
402: }
403:
404: /**
405: * Clones the value, size or attributes of the first selection cell to the
406: * other selection cells. If value is true then the value is cloned, if size
407: * if true then the size is cloned. If both are false, then the attributes
408: * (except the bounds and points) are cloned. <br>
409: * Note: If value and size are true at the same time, then the value is
410: * cloned.
411: *
412: * @param graph
413: * The graph to perform the operation in.
414: * @param value
415: * Whether to clone the value.
416: * @param size
417: * Whether to clone the size.
418: */
419: protected void doClone(JGraph graph, boolean value, boolean size) {
420: GraphLayoutCache cache = graph.getGraphLayoutCache();
421: CellView master = cache.getMapping(graph.getSelectionCell(),
422: false);
423: if (master != null && graph.getSelectionCount() > 1) {
424: if (value) {
425:
426: // Clone the value directly by doing a cast.
427: // An alternative would be to use the model's
428: // clone method on the cell and get the cloned
429: // user object from there.
430: Map nested = new Hashtable();
431: Object userObject = graph.getModel().getValue(
432: master.getCell());
433: Object[] cells = graph.getSelectionCells();
434: for (int i = 0; i < cells.length; i++) {
435: Map change = new Hashtable();
436: if (userObject instanceof JGraphpadBusinessObject)
437: userObject = ((JGraphpadBusinessObject) userObject)
438: .clone();
439: GraphConstants.setValue(change, userObject);
440: nested.put(cells[i], change);
441: }
442: cache.edit(nested);
443: } else if (size) {
444: Rectangle2D bounds = master.getBounds();
445: Map nested = new Hashtable();
446: Object[] cells = graph.getSelectionCells();
447:
448: // Updates the size for all bounds-attributes
449: for (int i = 1; i < cells.length; i++) {
450: CellView view = cache.getMapping(cells[i], false);
451: Rectangle2D tmp = GraphConstants.getBounds(view
452: .getAllAttributes());
453:
454: // Ignores the cell if it has no bounds
455: if (tmp != null) {
456: Map change = new Hashtable();
457: GraphConstants.setBounds(change,
458: new Rectangle2D.Double(tmp.getX(), tmp
459: .getY(), bounds.getWidth(),
460: bounds.getHeight()));
461: nested.put(view.getCell(), change);
462: }
463: }
464: cache.edit(nested);
465: } else {
466: Map change = new Hashtable(master.getAllAttributes());
467: change.remove(GraphConstants.BOUNDS);
468: change.remove(GraphConstants.POINTS);
469: cache.edit(graph.getSelectionCells(), change);
470: }
471:
472: }
473: }
474:
475: /**
476: * Connects the selection vertices using clones of <code>prototype</code>
477: * as edges. {@link JGraph#getDefaultPortForCell(Object)} is used to find
478: * the connection points of the vertices.
479: *
480: * @param graph
481: * The graph to perform the operation in.
482: * @param prototype
483: * The cell to be cloned for creating edges.
484: *
485: * @see GraphLayoutCache#getCells(boolean, boolean, boolean, boolean)
486: * @see DefaultGraphModel#cloneCell(GraphModel, Object)
487: * @see DefaultGraphModel#containsEdgeBetween(GraphModel, Object, Object)
488: */
489: protected void doConnect(JGraph graph, Object prototype) {
490: if (prototype != null) {
491: Object[] v = graph.getSelectionCells(graph
492: .getGraphLayoutCache().getCells(false, true, false,
493: false));
494:
495: // Replaces all vertices with their default ports
496: PortView[] pv = new PortView[v.length];
497: for (int i = 0; i < v.length; i++)
498: pv[i] = graph.getDefaultPortForCell(v[i]);
499:
500: // Constructs the edges and connection set
501: GraphModel model = graph.getModel();
502: ConnectionSet cs = new ConnectionSet();
503: for (int i = 0; i < v.length; i++) {
504: for (int j = i + 1; j < v.length; j++) {
505:
506: // Checks if not already connected
507: if (!DefaultGraphModel.containsEdgeBetween(model,
508: v[i], v[j])) {
509:
510: // Creates a new edge and connection
511: Object edge = DefaultGraphModel.cloneCell(
512: model, prototype);
513: cs.connect(edge, pv[i].getCell(), pv[j]
514: .getCell());
515: }
516: }
517: }
518:
519: // Inserts the edges if any connections have been made
520: if (!cs.isEmpty())
521: graph.getGraphLayoutCache().insert(
522: cs.getChangedEdges().toArray(), null, cs, null,
523: null);
524: }
525: }
526:
527: /**
528: * Disconnects the selection vertices by removing all edges between them.
529: *
530: * @param graph
531: * The graph to perform the operation in.
532: *
533: * @see GraphLayoutCache#getCells(boolean, boolean, boolean, boolean)
534: * @see DefaultGraphModel#getEdgesBetween(GraphModel, Object, Object,
535: * boolean)
536: */
537: protected void doDisconnect(JGraph graph) {
538: Object[] v = graph.getSelectionCells(graph
539: .getGraphLayoutCache().getCells(false, true, false,
540: false));
541: if (v != null && v.length > 0) {
542: HashSet result = new HashSet();
543: GraphModel model = graph.getModel();
544:
545: // Gets the edges (undirected) for all vertex pairs
546: for (int i = 0; i < v.length; i++) {
547: for (int j = i + 1; j < v.length; j++) {
548: Object[] e = DefaultGraphModel.getEdgesBetween(
549: model, v[i], v[j], false);
550: for (int k = 0; k < e.length; k++)
551: result.add(e[k]);
552: }
553: }
554: if (result.size() > 0)
555: graph.getGraphLayoutCache().remove(result.toArray());
556: }
557: }
558:
559: /**
560: * Creates a new group cell that contains the selection cells as children
561: * using a clone of <code>prototype</code> as the group cell.
562: *
563: * @param graph
564: * The graph to perform the operation in.
565: * @param prototype
566: * The cell to be cloned for creating groups.
567: *
568: * @see DefaultGraphModel#cloneCell(GraphModel, Object)
569: * @see JGraph#order(Object[])
570: * @see GraphLayoutCache#insertGroup(Object, Object[])
571: */
572: protected void doGroup(JGraph graph, Object prototype) {
573: if (prototype != null) {
574:
575: // Reorders the selection according to the layering
576: Object[] cells = graph.order(graph.getSelectionCells());
577: if (cells != null && cells.length > 0) {
578:
579: // Gets a clone of the prototype group cell
580: Object group = DefaultGraphModel.cloneCell(graph
581: .getModel(), prototype);
582: graph.getGraphLayoutCache().insertGroup(group, cells);
583: }
584: }
585: }
586:
587: /**
588: * Creates a new group cell that contains the selection cells as children
589: * using a clone of <code>prototype</code> as the group cell. The
590: * prototype is assumed to be an edge.
591: *
592: * @param graph
593: * The graph to perform the operation in.
594: * @param prototype
595: * The cell to be cloned for creating groups.
596: */
597: protected void doGroupAsEdge(JGraph graph, Object prototype) {
598: if (prototype != null) {
599: prototype = DefaultGraphModel.cloneCell(graph.getModel(),
600: prototype);
601: Rectangle2D bounds = graph.getCellBounds(graph
602: .getSelectionCells());
603: if (bounds != null) {
604: Map change = new Hashtable();
605: List pts = new ArrayList();
606: pts
607: .add(new Point2D.Double(bounds.getX(), bounds
608: .getY()));
609: pts.add(new Point2D.Double(bounds.getX()
610: + bounds.getWidth(), bounds.getY()
611: + bounds.getHeight()));
612: GraphConstants.setPoints(change, pts);
613: graph.getModel().getAttributes(prototype).applyMap(
614: change);
615: doGroup(graph, prototype);
616: }
617: }
618: }
619:
620: /**
621: * Aligns the selection vertices according to <code>constraint</code>.
622: * Valid constraints are: {@link #ALIGN_TOP}, {@link #ALIGN_MIDDLE},
623: * {@link #ALIGN_BOTTOM}, {@link #ALIGN_LEFT}, {@link #ALIGN_CENTER} and
624: * {@link #ALIGN_RIGHT}.
625: *
626: * @param graph
627: * The graph to perform the operation in.
628: * @param constraint
629: * The constraint that describes the alignment.
630: * @see #alignRectangle2D(Rectangle2D, Rectangle2D, int)
631: * @see GraphLayoutCache#getCells(boolean, boolean, boolean, boolean)
632: */
633: protected void doAlignCells(JGraph graph, int constraint) {
634: Object[] cells = graph.getSelectionCells(graph
635: .getGraphLayoutCache().getCells(false, true, false,
636: false));
637: Rectangle2D bounds = graph.getCellBounds(cells);
638: if (bounds != null) {
639: GraphLayoutCache cache = graph.getGraphLayoutCache();
640: Map nested = new Hashtable();
641:
642: // Aligns all cells that have a bounds property
643: for (int i = 0; i < cells.length; i++) {
644: CellView cellView = cache.getMapping(cells[i], false);
645: if (cellView != null) {
646: Rectangle2D cellBounds = GraphConstants
647: .getBounds(cellView.getAllAttributes());
648: if (cellBounds != null) {
649: Map attrs = new Hashtable();
650: Rectangle2D newBounds = (Rectangle2D) cellBounds
651: .clone();
652: alignRectangle2D(newBounds, bounds, constraint);
653: GraphConstants.setBounds(attrs, newBounds);
654: nested.put(cellView.getCell(), attrs);
655: }
656: }
657: }
658: if (!nested.isEmpty())
659: cache.edit(nested, null, null, null);
660: }
661: }
662:
663: /**
664: * Helper methods that aligns <code>cellBounds</code> inside
665: * <code>outerBounds</code> according to <code>constraint</code>.
666: */
667: protected void alignRectangle2D(Rectangle2D cellBounds,
668: Rectangle2D outerBounds, int constraint) {
669: switch (constraint) {
670: case ALIGN_LEFT:
671: cellBounds.setFrame(outerBounds.getX(), cellBounds.getY(),
672: cellBounds.getWidth(), cellBounds.getHeight());
673: break;
674: case ALIGN_TOP:
675: cellBounds.setFrame(cellBounds.getX(), outerBounds.getY(),
676: cellBounds.getWidth(), cellBounds.getHeight());
677: break;
678: case ALIGN_RIGHT:
679: cellBounds.setFrame(outerBounds.getX()
680: + outerBounds.getWidth() - cellBounds.getWidth(),
681: cellBounds.getY(), cellBounds.getWidth(),
682: cellBounds.getHeight());
683: break;
684: case ALIGN_BOTTOM:
685: cellBounds.setFrame(cellBounds.getX(), outerBounds.getY()
686: + outerBounds.getHeight() - cellBounds.getHeight(),
687: cellBounds.getWidth(), cellBounds.getHeight());
688: break;
689: case ALIGN_CENTER:
690: double cx = outerBounds.getWidth() / 2;
691: cellBounds.setFrame(outerBounds.getX() + cx
692: - cellBounds.getWidth() / 2, cellBounds.getY(),
693: cellBounds.getWidth(), cellBounds.getHeight());
694: break;
695: case ALIGN_MIDDLE:
696: double cy = outerBounds.getHeight() / 2;
697: cellBounds.setFrame(cellBounds.getX(), outerBounds.getY()
698: + cy - cellBounds.getHeight() / 2, cellBounds
699: .getWidth(), cellBounds.getHeight());
700: break;
701: }
702: }
703:
704: /**
705: * Bundle of all actions in this class.
706: */
707: public static class AllActions implements Bundle {
708:
709: /**
710: * Holds the actions. The actionGroup and actionConnect are assigned the
711: * prototypes at construction time.
712: */
713: public JGraphEditorAction actionCloneValue = new JGraphpadCellAction(
714: NAME_CLONEVALUE),
715: actionCloneSize = new JGraphpadCellAction(
716: NAME_CLONESIZE),
717: actionCloneAttributes = new JGraphpadCellAction(
718: NAME_CLONEATTRIBUTES),
719: actionCellsAlignTop = new JGraphpadCellAction(
720: NAME_CELLSALIGNTOP),
721: actionCellsAlignMiddle = new JGraphpadCellAction(
722: NAME_CELLSALIGNMIDDLE),
723: actionCellsAlignBottom = new JGraphpadCellAction(
724: NAME_CELLSALIGNBOTTOM),
725: actionCellsAlignLeft = new JGraphpadCellAction(
726: NAME_CELLSALIGNLEFT),
727: actionCellsAlignCenter = new JGraphpadCellAction(
728: NAME_CELLSALIGNCENTER),
729: actionCellsAlignRight = new JGraphpadCellAction(
730: NAME_CELLSALIGNRIGHT),
731: actionToggleSelectable = new JGraphpadCellAction(
732: NAME_TOGGLESELECTABLE),
733: actionToggleChildrenSelectable = new JGraphpadCellAction(
734: NAME_TOGGLECHILDRENSELECTABLE),
735: actionAllSelectable = new JGraphpadCellAction(
736: NAME_ALLSELECTABLE),
737: actionCollapse = new JGraphpadCellAction(NAME_COLLAPSE),
738: actionToggleCollapsed = new JGraphpadCellAction(
739: NAME_TOGGLECOLLAPSED),
740: actionExpand = new JGraphpadCellAction(NAME_EXPAND),
741: actionExpandAll = new JGraphpadCellAction(
742: NAME_EXPANDALL),
743: actionToBack = new JGraphpadCellAction(NAME_TOBACK),
744: actionToFront = new JGraphpadCellAction(NAME_TOFRONT),
745: actionGroup = new JGraphpadCellAction(NAME_GROUP),
746: actionGroupAsEdge = new JGraphpadCellAction(
747: NAME_GROUPASEDGE),
748: actionUngroup = new JGraphpadCellAction(NAME_UNGROUP),
749: actionRemoveFromGroup = new JGraphpadCellAction(
750: NAME_REMOVEFROMGROUP),
751: actionConnect = new JGraphpadCellAction(NAME_CONNECT),
752: actionDisconnect = new JGraphpadCellAction(
753: NAME_DISCONNECT),
754: actionAddProperty = new JGraphpadCellAction(
755: NAME_ADDPROPERTY),
756: actionRemoveProperty = new JGraphpadCellAction(
757: NAME_REMOVEPROPERTY),
758: actionInvert = new JGraphpadCellAction(NAME_INVERT);
759:
760: /**
761: * Constructs the action bundle for the enclosing class.
762: *
763: * @param editor
764: * The enclosing editor.
765: */
766: public AllActions(JGraphEditor editor) {
767: Object groupPrototype = editor.getSettings().getObject(
768: JGraphpad.KEY_GROUPPROTOTYPE);
769: Object edgePrototype = editor.getSettings().getObject(
770: JGraphpad.KEY_EDGEPROTOTYPE);
771: actionGroup.putValue(KEY_PROTOTYPE, groupPrototype);
772: actionGroupAsEdge.putValue(KEY_PROTOTYPE, edgePrototype);
773: actionConnect.putValue(KEY_PROTOTYPE, edgePrototype);
774: }
775:
776: /*
777: * (non-Javadoc)
778: */
779: public JGraphEditorAction[] getActions() {
780: return new JGraphEditorAction[] { actionCloneValue,
781: actionCloneSize, actionCloneAttributes,
782: actionCellsAlignTop, actionCellsAlignMiddle,
783: actionCellsAlignBottom, actionCellsAlignLeft,
784: actionCellsAlignCenter, actionCellsAlignRight,
785: actionToggleSelectable,
786: actionToggleChildrenSelectable,
787: actionAllSelectable, actionCollapse,
788: actionToggleCollapsed, actionExpand,
789: actionExpandAll, actionToBack, actionToFront,
790: actionGroup, actionGroupAsEdge, actionUngroup,
791: actionRemoveFromGroup, actionConnect,
792: actionDisconnect, actionAddProperty,
793: actionRemoveProperty, actionInvert };
794: }
795:
796: /*
797: * (non-Javadoc)
798: */
799: public void update() {
800: JGraph graph = getPermanentFocusOwnerGraph();
801: boolean isCellSelected = graph != null
802: && !graph.isSelectionEmpty();
803: JGraphpadLibraryPane libraryPane = JGraphpadFileAction
804: .getPermanentFocusOwnerLibraryPane();
805: boolean isEntrySelected = libraryPane != null
806: && !libraryPane.isSelectionEmpty();
807:
808: actionToBack.setEnabled(isCellSelected || isEntrySelected);
809: actionToFront.setEnabled(isCellSelected || isEntrySelected);
810:
811: actionCloneValue.setEnabled(isCellSelected);
812: actionCloneSize.setEnabled(isCellSelected);
813: actionCloneAttributes.setEnabled(isCellSelected);
814: actionCellsAlignTop.setEnabled(isCellSelected);
815: actionCellsAlignMiddle.setEnabled(isCellSelected);
816: actionCellsAlignBottom.setEnabled(isCellSelected);
817: actionCellsAlignLeft.setEnabled(isCellSelected);
818: actionCellsAlignCenter.setEnabled(isCellSelected);
819: actionCellsAlignRight.setEnabled(isCellSelected);
820: actionToggleSelectable.setEnabled(isCellSelected);
821: actionAllSelectable.setEnabled(graph != null);
822: actionToggleChildrenSelectable.setEnabled(isCellSelected);
823: actionCollapse.setEnabled(isCellSelected);
824: actionToggleCollapsed.setEnabled(isCellSelected);
825: actionExpand.setEnabled(isCellSelected);
826: actionExpandAll.setEnabled(isCellSelected);
827: actionGroup.setEnabled(isCellSelected);
828: actionGroupAsEdge.setEnabled(isCellSelected);
829: actionUngroup.setEnabled(isCellSelected);
830: actionRemoveFromGroup.setEnabled(isCellSelected);
831: actionConnect.setEnabled(isCellSelected);
832: actionDisconnect.setEnabled(isCellSelected);
833: actionAddProperty.setEnabled(isCellSelected);
834: actionRemoveProperty.setEnabled(isCellSelected);
835: actionInvert.setEnabled(isCellSelected);
836:
837: // Update toggleable action states
838: if (graph != null) {
839: actionToggleSelectable.setSelected(getBooleanAttribute(
840: graph, GraphConstants.SELECTABLE, true));
841: actionToggleChildrenSelectable
842: .setSelected(getBooleanAttribute(graph,
843: GraphConstants.CHILDRENSELECTABLE, true));
844: }
845: }
846:
847: }
848:
849: }
|