001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.web.jsf.navigation.graph;
042:
043: import org.netbeans.modules.web.jsf.navigation.graph.layout.FreePlaceNodesLayouter;
044: import java.awt.Graphics2D;
045: import java.awt.Image;
046: import java.awt.Paint;
047: import java.awt.Point;
048: import java.awt.Rectangle;
049: import java.awt.TexturePaint;
050: import java.awt.image.BufferedImage;
051: import java.lang.ref.WeakReference;
052: import java.util.ArrayList;
053: import java.util.Arrays;
054: import java.util.Collection;
055: import org.netbeans.modules.web.jsf.navigation.graph.actions.LinkCreateProvider;
056: import org.netbeans.api.visual.action.ActionFactory;
057: import org.netbeans.api.visual.action.WidgetAction;
058: import org.netbeans.api.visual.anchor.Anchor;
059: import org.netbeans.api.visual.anchor.AnchorFactory;
060: import org.netbeans.api.visual.graph.GraphPinScene;
061: import org.netbeans.api.visual.layout.LayoutFactory;
062: import org.netbeans.api.visual.router.Router;
063: import org.netbeans.api.visual.router.RouterFactory;
064: import org.netbeans.api.visual.widget.ConnectionWidget;
065: import org.netbeans.api.visual.widget.LayerWidget;
066: import org.netbeans.api.visual.widget.Widget;
067: import org.netbeans.api.visual.widget.EventProcessingType;
068: import java.util.Collections;
069: import java.util.List;
070: import javax.swing.Action;
071: import javax.swing.ActionMap;
072: import javax.swing.BorderFactory;
073: import javax.swing.InputMap;
074: import javax.swing.KeyStroke;
075: import javax.swing.border.Border;
076: import org.netbeans.api.visual.action.EditProvider;
077: import org.netbeans.api.visual.action.PopupMenuProvider;
078: import org.netbeans.api.visual.action.SelectProvider;
079: import org.netbeans.api.visual.action.TextFieldInplaceEditor;
080: import org.netbeans.api.visual.action.WidgetAction.Chain;
081: import org.netbeans.api.visual.model.ObjectSceneEventType;
082: import org.netbeans.api.visual.model.ObjectState;
083: import org.netbeans.api.visual.vmd.VMDColorScheme;
084: import org.netbeans.api.visual.vmd.VMDConnectionWidget;
085: import org.netbeans.api.visual.vmd.VMDFactory;
086: import org.netbeans.api.visual.vmd.VMDNodeWidget;
087: import org.netbeans.api.visual.vmd.VMDPinWidget;
088: import org.netbeans.api.visual.widget.ImageWidget;
089: import org.netbeans.api.visual.widget.LabelWidget;
090: import org.netbeans.modules.web.jsf.navigation.NavigationCaseEdge;
091: import org.netbeans.modules.web.jsf.navigation.Page;
092: import org.netbeans.modules.web.jsf.navigation.PageFlowView;
093: import org.netbeans.modules.web.jsf.navigation.Pin;
094: import org.netbeans.modules.web.jsf.navigation.graph.actions.MapActionUtility;
095: import org.netbeans.modules.web.jsf.navigation.graph.actions.MyActionMapAction;
096: import org.netbeans.modules.web.jsf.navigation.graph.actions.PageFlowDeleteAction;
097: import org.netbeans.modules.web.jsf.navigation.graph.actions.PageFlowPopupProvider;
098: import org.netbeans.modules.web.jsf.navigation.graph.layout.ConnectionWrapperLayout;
099: import org.openide.actions.DeleteAction;
100: import org.openide.util.Utilities;
101: import org.openide.util.actions.CallbackSystemAction;
102: import org.openide.util.actions.SystemAction;
103:
104: /**
105: * This class represents a GraphPinScene for the Navigation Editor which is soon to be the Page Flow Editor.
106: * Nodes are represented by a Page, Edges by a Link, and components by a Pin.
107: * Graphics were taken from the VMDGraphScene designed by David Kaspar for mobility pack.
108: * The visualization is done by: VMDNodeWidget for nodes, VMDPinWidget for pins, ConnectionWidget fro edges.
109: * <p>
110: * The scene has 4 layers: background, main, connection, upper.
111: * <p>
112: * The scene has following actions: zoom, panning, rectangular selection.
113: *
114: * @author Joelle Lam
115: */
116: // TODO - remove popup menu action
117: public class PageFlowScene extends
118: GraphPinScene<Page, NavigationCaseEdge, Pin> {
119:
120: private static final VMDColorScheme scheme = VMDFactory
121: .getNetBeans60Scheme();
122: private final LayerWidget backgroundLayer = new LayerWidget(this );
123: private final LayerWidget mainLayer = new LayerWidget(this );
124: private final LayerWidget connectionLayer = new LayerWidget(this );
125: private final LayerWidget upperLayer = new LayerWidget(this );
126:
127: private Router router;
128: /**
129: * The maximum is used for determining which router to used. If either
130: * edges or pages exceed the max, the direct routing algorithm will be used
131: **/
132: private static final int MAX_EDGES = 20;
133: private static final int MAX_PAGES = 20;
134: private static final int MAX_ELEMENTS = 30;
135: private final Router routerDirect = RouterFactory
136: .createDirectRouter();
137:
138: private final WidgetAction moveControlPointAction = ActionFactory
139: .createOrthogonalMoveControlPointAction();
140: // private WidgetAction popupNodeAction = ActionFactory.createPopupMenuAction (new NodePopupMenuProvider(this));
141: private final WidgetAction moveAction = ActionFactory
142: .createMoveAction();
143: //private final WidgetAction dragNdropAction = ActionFactory.createAcceptAction(new PageFlowAcceptProvider());
144: private final WidgetAction connectAction = ActionFactory
145: .createConnectAction(connectionLayer,
146: new LinkCreateProvider(this ));
147: private final WidgetAction selectAction = ActionFactory
148: .createSelectAction(new PageFlowSelectProvider());
149: private final WidgetAction doubleClickAction = ActionFactory
150: .createEditAction(new PageNodeEditAction());
151: private final WidgetAction pagePopupAction = ActionFactory
152: .createPopupMenuAction(new PageFlowPopupProvider());
153:
154: private WeakReference<PageFlowView> refPageFlowView;
155: private PopupMenuProvider popupProvider; //Please see POPUP_HACK below.
156: private PFObjectSceneListener pfObjectSceneListener;
157: private static Paint PAINT_BACKGROUND;
158: static {
159: Image sourceImage = Utilities
160: .loadImage("org/netbeans/modules/web/jsf/navigation/graph/resources/paper_grid.png"); // NOI18N
161: int width = sourceImage.getWidth(null);
162: int height = sourceImage.getHeight(null);
163: BufferedImage image = new BufferedImage(width, height,
164: BufferedImage.TYPE_INT_RGB);
165: Graphics2D graphics = image.createGraphics();
166: graphics.drawImage(sourceImage, 0, 0, null);
167: graphics.dispose();
168: PAINT_BACKGROUND = new TexturePaint(image, new Rectangle(0, 0,
169: width, height));
170: }
171:
172: /**
173: * Creates a VMD graph scene.
174: * @param pageFlowView or TopComponent/container.
175: */
176: public PageFlowScene(PageFlowView view) {
177: super ();
178: refPageFlowView = new WeakReference<PageFlowView>(view);
179:
180: setOpaque(true);
181: setBackground(PAINT_BACKGROUND);
182:
183: setKeyEventProcessingType(EventProcessingType.FOCUSED_WIDGET_AND_ITS_PARENTS);
184:
185: addChild(backgroundLayer);
186: addChild(mainLayer);
187: addChild(connectionLayer);
188: addChild(upperLayer);
189:
190: router = RouterFactory.createOrthogonalSearchRouter(mainLayer,
191: connectionLayer);
192:
193: Chain actions = getActions();
194: actions.addAction(ActionFactory.createZoomAction());
195: actions.addAction(ActionFactory.createPanAction());
196: actions.addAction(ActionFactory.createRectangularSelectAction(
197: this , backgroundLayer));
198: /*** POPUP_HACK: I have no access to PopupAction so I can't look through the actions and determine which one is a popup.
199: * In order to added accessibility to popup I need access to this provider unless an API is created
200: * to figure this out another means.
201: **/
202: actions.addAction(pagePopupAction);
203: actions.addAction(createActionMap());
204: pfObjectSceneListener = new PFObjectSceneListener();
205: addObjectSceneListener(pfObjectSceneListener,
206: ObjectSceneEventType.OBJECT_SELECTION_CHANGED);
207:
208: /* Temporary workaround ISSUE# 107506 Still an issue. */
209: //InputMap inputMap = MapActionUtility.initInputMap();
210: //ActionMap actionMap = MapActionUtility.initActionMap();
211: //actions.addAction(ActionFactory.createActionMapAction(inputMap, actionMap));
212: //MyActionMapAction action = new MyActionMapAction(null, null);
213: fpnl = new FreePlaceNodesLayouter(this , view.getVisibleRect());
214:
215: }
216:
217: private FreePlaceNodesLayouter fpnl;
218:
219: /* Used to destroy everything in the scene. */
220: public void destoryPageFlowScene() {
221: removeObjectSceneListener(pfObjectSceneListener,
222: ObjectSceneEventType.OBJECT_SELECTION_CHANGED);
223: pfObjectSceneListener = null;
224:
225: popupProvider = null;
226:
227: fpnl.unregisterListeners(this );
228: fpnl = null;
229: router = null;
230:
231: Chain chainActions = getActions();
232: for (WidgetAction action : new ArrayList<WidgetAction>(
233: chainActions.getActions())) {
234: chainActions.removeAction(action);
235: }
236: }
237:
238: private WidgetAction createActionMap() {
239:
240: ActionMap actionMap = refPageFlowView.get().getActionMap();
241: CallbackSystemAction a = (CallbackSystemAction) SystemAction
242: .get(DeleteAction.class);
243: actionMap.put(a.getActionMapKey(), new PageFlowDeleteAction(
244: this ));
245:
246: //Temporary workaround ISSUE# 107506
247: return new MyActionMapAction(MapActionUtility.initInputMap(),
248: MapActionUtility.initActionMap());
249: //return ActionFactory.createActionMapAction(MapActionUtility.initInputMap(), MapActionUtility.initActionMap());
250: }
251:
252: /**
253: * Get the PageFlowView TopComponent
254: * @return PageFlowView
255: */
256: public PageFlowView getPageFlowView() {
257: return refPageFlowView.get();
258: }
259:
260: private final LabelWidget malFormedLabel = new LabelWidget(this ,
261: "Your XML is Malformed.");
262:
263: /**
264: * To show a mal formed page.
265: */
266: public void createMalFormedWidget() {
267: List<Widget> widgets = getChildren();
268: if (!widgets.contains(malFormedLabel)) {
269: addChild(malFormedLabel);
270: validate();
271: }
272: }
273:
274: /**
275: * Removed the mal formed notes on the screen.
276: */
277: public void removeMalFormedWidget() {
278: List<Widget> widgets = getChildren();
279: if (widgets.contains(malFormedLabel)) {
280: removeChild(malFormedLabel); //Removed major bug... Not sure what I was doing before...
281: validate();
282: }
283: }
284:
285: /**
286: * Implements attaching a widget to a node. The widget is VMDNodeWidget and has object-hover, select, popup-menu and move actions.
287: * @param node the node
288: * @return the widget attached to the node, will return null if
289: */
290: protected Widget attachNodeWidget(Page page) {
291: assert page != null;
292: VMDNodeWidget nodeWidget = new PFENodeWidget(this , scheme);
293: String displayName = page.getDisplayName();
294: nodeWidget.setNodeName(displayName);
295:
296: Widget header = nodeWidget.getHeader();
297: ImageWidget imageWidget = new DefaultAnchorWidget(
298: this ,
299: Utilities
300: .loadImage("org/netbeans/modules/visual/resources/vmd-pin.png"));
301: imageWidget.getActions().addAction(connectAction);
302: imageWidget.getActions().addAction(createWidgetHoverAction());
303: header.addChild(imageWidget);
304: header.getActions().addAction(createWidgetHoverAction());
305:
306: LabelWidget lblWidget = nodeWidget.getNodeNameWidget();
307: lblWidget
308: .getActions()
309: .addAction(
310: ActionFactory
311: .createInplaceEditorAction(new PageNodeTextFieldInplaceEditor(
312: nodeWidget)));
313:
314: mainLayer.addChild(nodeWidget);
315: //updateNodeActions(nodeWidget);
316: nodeWidget.getHeader().getActions().addAction(
317: createObjectHoverAction());
318: nodeWidget.getHeader().getActions()
319: .addAction(doubleClickAction); //not still the glory from pins.
320: nodeWidget.getActions().addAction(selectAction);
321: nodeWidget.getActions().addAction(moveAction);
322: nodeWidget.setMinimized(true);
323:
324: /*
325: if ( node.getPinNodes().size() == 0 ){
326: nodeWidget.setMinimized(true);
327: }
328: */
329:
330: return nodeWidget;
331: }
332:
333: private WidgetAction pageSpecificActionMapAction = null;
334:
335: public final void updateNodeWidgetActions(Page page) {
336: Widget nodeWidget = findWidget(page);
337: if (nodeWidget != null) {
338: if (pageSpecificActionMapAction != null) {
339: nodeWidget.getActions().removeAction(
340: pageSpecificActionMapAction);
341: }
342: pageSpecificActionMapAction = createActionMapAction(page);
343: if (pageSpecificActionMapAction != null) {
344: nodeWidget.getActions().addAction(
345: pageSpecificActionMapAction);
346: }
347: }
348: }
349:
350: private WidgetAction createActionMapAction(Page page) {
351: InputMap inputMap = new InputMap();
352: ActionMap actionMap = new ActionMap();
353: Action[] actions = page.getActions(true);
354: for (Action action : actions) {
355: KeyStroke keyStroke = (KeyStroke) action
356: .getValue(javax.swing.Action.ACCELERATOR_KEY);
357: if (keyStroke != null) {
358: inputMap.put(keyStroke, action.toString());
359: actionMap.put(action.toString(), action);
360: }
361: }
362: if (actionMap.size() < 1) {
363: return null;
364: }
365: /* Not sure if it is the right thing to create a new action map
366: * should I be adding it?
367: */
368: return new MyActionMapAction(inputMap, actionMap);
369:
370: //return ActionFactory.createActionMapAction(inputMap, actionMap);
371: }
372:
373: //private Map<VMDNodeWidget, Point> nodeWidget2Point = new HashMap<VMDNodeWidget, Point>();
374:
375: /* This is needed by PageFlowLayoutUtilities*/
376: public Rectangle getVisibleRect() {
377: return refPageFlowView.get().getVisibleRect();
378: }
379:
380: // private Queue emptyPositions = new LinkedList();
381: @Override
382: protected void detachNodeWidget(Page node, Widget widget) {
383: // Point p = widget.getPreferredLocation();
384: // if ( (p.getX() - BORDER_OFFSET) %
385: super .detachNodeWidget(node, widget);
386: }
387:
388: private static class DefaultAnchorWidget extends ImageWidget {
389:
390: public DefaultAnchorWidget(PageFlowScene scene, Image image) {
391: super (scene, image);
392: }
393:
394: @Override
395: protected void notifyStateChanged(ObjectState previousState,
396: ObjectState state) {
397: Border BORDER_HOVERED = javax.swing.BorderFactory
398: .createLineBorder(java.awt.Color.BLACK);
399: Border BORDER = BorderFactory.createEmptyBorder();
400: if (previousState.isHovered() == state.isHovered()) {
401: return;
402: }
403: setBorder(state.isHovered() ? BORDER_HOVERED : BORDER);
404: }
405: }
406:
407: /**
408: *
409: * @param pageNode
410: * @return
411: */
412: public Pin getDefaultPin(Page pageNode) {
413: Collection<Pin> pins = getNodePins(pageNode);
414: if (pins == null) {
415: System.err.println("Node is null?: " + pageNode);
416: }
417: for (Pin pin : pins) {
418: if (pin.isDefault()) {
419: return pin;
420: }
421: }
422: System.err.println("Some reason this node: " + pageNode
423: + " does not have a pin.");
424: return null;
425: }
426:
427: /**
428: * Implements attaching a widget to a pin. The widget is VMDPinWidget and has object-hover and select action.
429: * The the node id ends with "#default" then the pin is the default pin of a node and therefore it is non-visual.
430: * @param node the node
431: * @param pinNode
432: * @return the widget attached to the pin, null, if it is a default pin
433: */
434: protected Widget attachPinWidget(Page pageNode, Pin pinNode) {
435: assert pageNode != null;
436:
437: if (pinNode.isDefault()) {
438: return null;
439: }
440:
441: VMDPinWidget widget = new VMDPinWidget(this , scheme);
442: VMDNodeWidget nodeWidget = (VMDNodeWidget) findWidget(pageNode);
443: if (nodeWidget != null) {
444: nodeWidget.attachPinWidget(widget);
445: widget.setProperties(pinNode.getName(), Arrays
446: .asList(pinNode.getIcon(0)));
447:
448: Chain actions = widget.getActions();
449: actions.addAction(createObjectHoverAction());
450: actions.addAction(createSelectAction());
451: actions.addAction(connectAction);
452: actions.addAction(doubleClickAction);
453: } else {
454: System.err.println("Node widget should not be null.");
455: }
456:
457: return widget;
458: }
459:
460: // public void replaceWidgetNode( PageFlowNode oldNode, PageFlowNode newNode ) {
461: // VMDNodeWidget widget = (VMDNodeWidget)findWidget(oldNode);
462: // oldNode = newNode;
463: // // if ( widget != null ){
464: // // widget.setNodeName(newNode.getDisplayName());
465: // // }
466: // removeObject(oldNode);
467: // addObject(newNode, widget, widget.getChildren().get(0));
468: // }
469: /**
470: * Implements attaching a widget to an edge. the widget is ConnectionWidget and has object-hover, select and move-control-point actions.
471: * @param edge
472: * @return the widget attached to the edge
473: */
474: protected Widget attachEdgeWidget(NavigationCaseEdge edge) {
475: assert edge != null;
476:
477: VMDConnectionWidget connectionWidget;
478:
479: if (edge.isModifiable()) {
480: connectionWidget = new VMDConnectionWidget(this , scheme);
481: } else {
482: connectionWidget = new VMDConnectionWidget(this ,
483: new PFENotModifiableScheme());
484: }
485: /* Do this to avoid graph scene delays due to large number of elements */
486: if (getEdges().size() > MAX_EDGES
487: || getNodes().size() > MAX_PAGES
488: || getEdges().size() + getNodes().size() > MAX_ELEMENTS) {
489: connectionWidget.setRouter(routerDirect);
490: } else {
491: connectionWidget.setRouter(router);
492: }
493:
494: LabelWidget label = new LabelWidget(this , edge.getName());
495: label.setOpaque(true);
496: label
497: .getActions()
498: .addAction(
499: ActionFactory
500: .createInplaceEditorAction(new PageFlowScene.CaseNodeTextFieldInplaceEditor()));
501:
502: connectionLayer.addChild(connectionWidget);
503:
504: connectionWidget.getActions().addAction(
505: createObjectHoverAction());
506: connectionWidget.getActions().addAction(selectAction);
507: connectionWidget.getActions().addAction(moveControlPointAction);
508: connectionWidget.getActions().addAction(doubleClickAction);
509:
510: connectionWidget.setLayout(new ConnectionWrapperLayout(
511: connectionWidget, label));
512: connectionWidget
513: .setConstraint(
514: label,
515: LayoutFactory.ConnectionWidgetLayoutAlignment.TOP_RIGHT,
516: 10);
517: connectionWidget.addChild(label);
518:
519: return connectionWidget;
520: }
521:
522: /*
523: protected Widget attachEdgeWidget(NavigationCaseEdge edge, boolean directEdge){
524: ConnectionWidget connectionWidget = (ConnectionWidget)attachEdgeWidget(edge);
525: if( directEdge ){
526: connectionWidget.setRouter(router);
527: }
528: }
529: * */
530:
531: public void renameEdgeWidget(NavigationCaseEdge edge,
532: String newName, String oldName) {
533: VMDConnectionWidget edgeWidget = (VMDConnectionWidget) findWidget(edge);
534: List<Widget> widgets = edgeWidget.getChildren();
535: for (Widget widget : widgets) {
536: if (widget instanceof LabelWidget
537: && ((LabelWidget) widget).getLabel()
538: .equals(oldName)) {
539: ((LabelWidget) widget).setLabel(newName);
540: return;
541: }
542: }
543: }
544:
545: /**
546: * Attaches an anchor of a source pin an edge.
547: * The anchor is a ProxyAnchor that switches between the anchor attached to the pin widget directly and
548: * the anchor attached to the pin node widget based on the minimize-state of the node.
549: * @param edge the edge
550: * @param oldSourcePin the old source pin
551: * @param sourcePin the new source pin
552: */
553: protected void attachEdgeSourceAnchor(NavigationCaseEdge edge,
554: Pin oldSourcePin, Pin sourcePin) {
555: ConnectionWidget connectionWidget = (ConnectionWidget) findWidget(edge);
556: Anchor anchor = getPinAnchor(sourcePin);
557: connectionWidget.setSourceAnchor(anchor);
558: }
559:
560: /**
561: * Attaches an anchor of a target pin an edge.
562: * The anchor is a ProxyAnchor that switches between the anchor attached to the pin widget directly and
563: * the anchor attached to the pin node widget based on the minimize-state of the node.
564: * @param edge the edge
565: * @param oldTargetPin the old target pin
566: * @param targetPin the new target pin
567: */
568: protected void attachEdgeTargetAnchor(NavigationCaseEdge edge,
569: Pin oldTargetPin, Pin targetPin) {
570: ((ConnectionWidget) findWidget(edge))
571: .setTargetAnchor(getPinAnchor(targetPin));
572: }
573:
574: /*
575: * Returns the Anchor for a given pin
576: * @param pin The Pin
577: * @return Anchor the anchor location
578: */
579: private Anchor getPinAnchor(Pin pin) {
580: if (pin == null) {
581: return null;
582: }
583: VMDNodeWidget nodeWidget = (VMDNodeWidget) findWidget(getPinNode(pin));
584: Widget pinMainWidget = findWidget(pin);
585: Anchor anchor;
586: if (pinMainWidget != null) {
587: anchor = AnchorFactory.createDirectionalAnchor(
588: pinMainWidget,
589: AnchorFactory.DirectionalAnchorKind.HORIZONTAL, 8);
590: anchor = nodeWidget.createAnchorPin(anchor);
591: } else {
592: anchor = nodeWidget.getNodeAnchor();
593: }
594: return anchor;
595: }
596:
597: public LayerWidget getConnectionLayer() {
598: return connectionLayer;
599: }
600:
601: private final class PageFlowSelectProvider implements
602: SelectProvider {
603:
604: public boolean isAimingAllowed(Widget widget,
605: Point localLocation, boolean invertSelection) {
606: return false;
607: }
608:
609: public boolean isSelectionAllowed(Widget widget,
610: Point localLocation, boolean invertSelection) {
611: Object object = findObject(widget);
612: return object != null
613: && (invertSelection || !getSelectedObjects()
614: .contains(object));
615: }
616:
617: public void select(Widget widget, Point localLocation,
618: boolean invertSelection) {
619: Object object = findObject(widget);
620: if (object != null) {
621: setFocusedObject(object);
622: if (getSelectedObjects().contains(object)) {
623: return;
624: }
625: userSelectionSuggested(Collections.singleton(object),
626: invertSelection);
627: } else {
628: userSelectionSuggested(Collections.emptySet(),
629: invertSelection);
630: }
631: }
632: }
633:
634: public final class PageNodeEditAction implements EditProvider {
635:
636: public void edit(Widget widget) {
637: PageFlowScene scene = (PageFlowScene) widget.getScene();
638: PageFlowSceneElement element = (PageFlowSceneElement) scene
639: .findObject(widget);
640: MapActionUtility.openPageFlowSceneElement(element);
641: }
642: }
643:
644: public final class CaseNodeTextFieldInplaceEditor implements
645: TextFieldInplaceEditor {
646:
647: public boolean isEnabled(Widget widget) {
648: NavigationCaseEdge caseNode = (NavigationCaseEdge) findObject(widget
649: .getParentWidget());
650: return caseNode.isModifiable();
651: }
652:
653: public String getText(Widget widget) {
654: NavigationCaseEdge caseNode = (NavigationCaseEdge) findObject(widget
655: .getParentWidget());
656: return ((LabelWidget) widget).getLabel();
657: }
658:
659: public void setText(Widget widget, String newName) {
660: if (newName.equals("")) {
661: return;
662: }
663:
664: NavigationCaseEdge caseNode = (NavigationCaseEdge) findObject(widget
665: .getParentWidget());
666: String oldName = caseNode.getName();
667:
668: if (caseNode.canRename()) {
669: //Pin pin = getEdgeSource(caseNode);
670: //caseNode.setName(pin, newName);
671: caseNode.setName(newName);
672: }
673:
674: ((LabelWidget) widget).setLabel(newName);
675: }
676: }
677:
678: public final class PageNodeTextFieldInplaceEditor implements
679: TextFieldInplaceEditor {
680:
681: private final VMDNodeWidget nodeWidget;
682:
683: public PageNodeTextFieldInplaceEditor(VMDNodeWidget nodeWidget) {
684: this .nodeWidget = nodeWidget;
685: }
686:
687: public boolean isEnabled(Widget widget) {
688: return true;
689: }
690:
691: public String getText(Widget widget) {
692: Page pageNode = (Page) findObject(nodeWidget);
693: return pageNode.getName();
694: }
695:
696: public void setText(Widget widget, String text) {
697:
698: Page pageNode = (Page) findObject(nodeWidget);
699: if (pageNode.canRename()
700: && !text.equals(pageNode.getName())) {
701:
702: //Explicitly declared oldName and newName for ease of reading.
703: String oldName = pageNode.getDisplayName();
704: String newName;
705:
706: pageNode.setName(text);
707: newName = pageNode.getDisplayName();
708:
709: // if( oldName != newName ) {
710: // renamePin(pageNode, oldName + "pin", newName + "pin");
711: // }
712: if (widget instanceof LabelWidget) {
713: ((LabelWidget) widget).setLabel(newName);
714: } else if (widget instanceof VMDNodeWidget) {
715: ((VMDNodeWidget) widget).getNodeNameWidget()
716: .setLabel(newName);
717: }
718: validate();
719: }
720: }
721: }
722:
723: // private void renamePin( Node pageNode, PinNode oldPinName, PinNode newPinName ){
724: // assert pageNode != null;
725: // assert oldPinName != null;
726: // assert newPinName != null;
727: //
728: // Collection<NavigationCaseNode> navSourceCases;
729: // Collection<NavigationCaseNode> navTargetCases;
730: //
731: // if( oldPinName.equals(newPinName) ){
732: // //Don't do anything if they have the same name.
733: // return;
734: // }
735: //
736: //
737: // //Workaround: http://www.netbeans.org/issues/show_bug.cgi?id=98742
738: // try {
739: // navSourceCases = findPinEdges(oldPinName, true, false);
740: // } catch(NullPointerException npe) {
741: // npe.printStackTrace();
742: // System.err.println("Null Pointer Caught: ");
743: // System.err.println("http://www.netbeans.org/issues/show_bug.cgi?id=98742");
744: // navSourceCases = new ArrayList();
745: // }
746: //
747: // //Workaround: http://www.netbeans.org/issues/show_bug.cgi?id=98742
748: // try {
749: // navTargetCases = findPinEdges(oldPinName, false, true);
750: // } catch(NullPointerException npe) {
751: // npe.printStackTrace();
752: // System.err.println("Null Pointer Caught: ");
753: // System.err.println("http://www.netbeans.org/issues/show_bug.cgi?id=98742");
754: // navTargetCases = new ArrayList();
755: // }
756: //
757: // removePin(oldPinName);
758: // addPin(pageNode, newPinName);
759: //
760: // //Doing this to make sure the associate pins are taken care of.
761: // for( NavigationCaseNode navSourceCase : navSourceCases){
762: // attachEdgeSourceAnchor(navSourceCase, oldPinName, newPinName);
763: // }
764: //
765: // for( NavigationCaseNode navTargetCase : navTargetCases){
766: // attachEdgeTargetAnchor(navTargetCase, oldPinName, newPinName);
767: // }
768: //
769: //
770: // }
771:
772: public PopupMenuProvider getPopupMenuProvider() {
773: return popupProvider;
774: }
775:
776: static class SceneTestAccessor {
777: static FreePlaceNodesLayouter getFreePlaceNodesLayouter(
778: PageFlowScene scene) {
779: return scene.fpnl;
780: }
781:
782: static PopupMenuProvider getPopupProvider(PageFlowScene scene) {
783: return scene.popupProvider;
784: }
785:
786: static PFObjectSceneListener getPfObjectSceneListener(
787: PageFlowScene scene) {
788: return scene.pfObjectSceneListener;
789: }
790: }
791: }
|