0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.vmd.api.flow.visual;
0042:
0043: import org.netbeans.api.visual.action.*;
0044: import org.netbeans.api.visual.anchor.Anchor;
0045: import org.netbeans.api.visual.graph.GraphPinScene;
0046: import org.netbeans.api.visual.graph.layout.GridGraphLayout;
0047: import org.netbeans.api.visual.layout.LayoutFactory;
0048: import org.netbeans.api.visual.layout.SceneLayout;
0049: import org.netbeans.api.visual.model.ObjectSceneEvent;
0050: import org.netbeans.api.visual.model.ObjectSceneEventType;
0051: import org.netbeans.api.visual.model.ObjectSceneListener;
0052: import org.netbeans.api.visual.model.ObjectState;
0053: import org.netbeans.api.visual.router.Router;
0054: import org.netbeans.api.visual.router.RouterFactory;
0055: import org.netbeans.api.visual.widget.*;
0056: import org.netbeans.modules.vmd.api.flow.FlowPinOrderPresenter;
0057: import org.netbeans.modules.vmd.api.flow.FlowPresenter;
0058: import org.netbeans.modules.vmd.api.flow.FlowScenePresenter;
0059: import org.netbeans.modules.vmd.api.model.DesignComponent;
0060: import org.netbeans.modules.vmd.api.model.DesignDocument;
0061: import org.netbeans.modules.vmd.api.model.presenters.actions.ActionsSupport;
0062: import org.netbeans.modules.vmd.api.palette.PaletteSupport;
0063: import org.netbeans.modules.vmd.flow.FlowViewController;
0064: import org.openide.util.Utilities;
0065:
0066: import javax.swing.*;
0067: import java.awt.*;
0068: import java.awt.datatransfer.Transferable;
0069: import java.awt.image.BufferedImage;
0070: import java.util.*;
0071: import java.util.List;
0072:
0073: /**
0074: * @author David Kaspar
0075: */
0076: // TODO - should badges be a part of selection?
0077: // TODO - maybe updateBadges method should not be called from inside the attach*Widget, but it should be called from each particular presenter instead
0078: public final class FlowScene
0079: extends
0080: GraphPinScene<FlowNodeDescriptor, FlowEdgeDescriptor, FlowPinDescriptor> {
0081:
0082: private static Paint PAINT_BACKGROUND;
0083:
0084: static {
0085: Image sourceImage = Utilities
0086: .loadImage("org/netbeans/modules/vmd/flow/resources/paper_grid.png"); // NOI18N
0087: int width = sourceImage.getWidth(null);
0088: int height = sourceImage.getHeight(null);
0089: BufferedImage image = new BufferedImage(width, height,
0090: BufferedImage.TYPE_INT_RGB);
0091: Graphics2D graphics = image.createGraphics();
0092: graphics.drawImage(sourceImage, 0, 0, null);
0093: graphics.dispose();
0094: PAINT_BACKGROUND = new TexturePaint(image, new Rectangle(0, 0,
0095: width, height));
0096: // PAINT_BACKGROUND = Color.WHITE;
0097: }
0098:
0099: private DesignDocument document;
0100:
0101: private LayerWidget backgroundLayer;
0102: private LayerWidget mainLayer;
0103: private LayerWidget connectionLayer;
0104: private LayerWidget interractionLayer;
0105:
0106: private WidgetAction moveAction;
0107: private WidgetAction acceptAction;
0108: private WidgetAction connectAction;
0109: private WidgetAction reconnectAction;
0110: private WidgetAction moveControlPointAction;
0111: private WidgetAction renameAction;
0112: private WidgetAction popupMenuAction;
0113: private WidgetAction editAction;
0114: private WidgetAction sceneSelectAction;
0115: private WidgetAction sceneKeyAction;
0116:
0117: private Router edgeRouter;
0118:
0119: private HashMap<CacheNodeDescriptor, Point> preferredNodeLocationCache = new HashMap<CacheNodeDescriptor, Point>();
0120: private HashMap<Long, Point> preferredNodeLocationMap = new HashMap<Long, Point>();
0121: private Long eventID;
0122:
0123: private HashMap<FlowNodeDescriptor, FlowPresenter.FlowUIResolver> nodeUIregistry = new HashMap<FlowNodeDescriptor, FlowPresenter.FlowUIResolver>();
0124: private HashMap<FlowPinDescriptor, FlowPresenter.FlowUIResolver> pinUIregistry = new HashMap<FlowPinDescriptor, FlowPresenter.FlowUIResolver>();
0125: private HashMap<FlowEdgeDescriptor, FlowPresenter.FlowUIResolver> edgeUIregistry = new HashMap<FlowEdgeDescriptor, FlowPresenter.FlowUIResolver>();
0126: private HashMap<FlowBadgeDescriptor, FlowPresenter.FlowUIResolver> pinBadgeUIregistry = new HashMap<FlowBadgeDescriptor, FlowPresenter.FlowUIResolver>();
0127: private HashMap<FlowDescriptor, ArrayList<FlowBadgeDescriptor>> badges = new HashMap<FlowDescriptor, ArrayList<FlowBadgeDescriptor>>();
0128: private HashSet<FlowNodeDescriptor> nodesForOrdering = new HashSet<FlowNodeDescriptor>();
0129:
0130: private GridGraphLayout<FlowNodeDescriptor, FlowEdgeDescriptor> graphLayout;
0131: private SceneLayout sceneLayout;
0132:
0133: public FlowScene(DesignDocument document) {
0134: this .document = document;
0135:
0136: setOpaque(true);
0137: setBackground(PAINT_BACKGROUND);
0138:
0139: setKeyEventProcessingType(EventProcessingType.FOCUSED_WIDGET_AND_ITS_PARENTS);
0140:
0141: addChild(backgroundLayer = new LayerWidget(this ));
0142: addChild(mainLayer = new LayerWidget(this ));
0143: addChild(connectionLayer = new LayerWidget(this ));
0144: addChild(interractionLayer = new LayerWidget(this ));
0145:
0146: moveAction = ActionFactory.createMoveAction(null,
0147: new FlowMoveProvider());
0148: acceptAction = ActionFactory
0149: .createAcceptAction(new FlowAcceptProvider());
0150: FlowConnectDecoratorProvider flowConnectDecoratorProvider = new FlowConnectDecoratorProvider();
0151: connectAction = ActionFactory.createConnectAction(
0152: flowConnectDecoratorProvider, interractionLayer,
0153: flowConnectDecoratorProvider);
0154: FlowReconnectDecoratorProvider flowReconnectDecoratorProvider = new FlowReconnectDecoratorProvider();
0155: reconnectAction = ActionFactory.createReconnectAction(
0156: flowReconnectDecoratorProvider,
0157: flowReconnectDecoratorProvider);
0158: moveControlPointAction = ActionFactory
0159: .createMoveControlPointAction(
0160: ActionFactory
0161: .createOrthogonalMoveControlPointProvider(),
0162: ConnectionWidget.RoutingPolicy.DISABLE_ROUTING_UNTIL_END_POINT_IS_MOVED);
0163: renameAction = ActionFactory
0164: .createInplaceEditorAction(new FlowRenameEditor());
0165: editAction = ActionFactory
0166: .createEditAction(new FlowEditProvider());
0167: popupMenuAction = ActionFactory
0168: .createPopupMenuAction(new FlowPopupMenuProvider());
0169: sceneSelectAction = new FlowSceneSelectAction();
0170: sceneKeyAction = new FlowSceneKeyAction(); // HINT - FlowDescriptor.KeyActionBehaviour is used for FlowScene/rootComponent only
0171:
0172: edgeRouter = RouterFactory
0173: .createOrthogonalSearchRouter(new OrthogonalCollisionsCollector(
0174: mainLayer, connectionLayer));
0175:
0176: getActions().addAction(
0177: ActionFactory.createMouseCenteredZoomAction(1.2));
0178: getActions().addAction(ActionFactory.createPanAction());
0179: getActions().addAction(sceneSelectAction);
0180: getActions().addAction(createSelectAction());
0181: getActions().addAction(createAcceptAction());
0182: getActions().addAction(popupMenuAction);
0183: getActions().addAction(
0184: ActionFactory.createRectangularSelectAction(this ,
0185: backgroundLayer));
0186: getActions().addAction(
0187: ActionFactory.createCycleObjectSceneFocusAction());
0188: getActions().addAction(sceneKeyAction);
0189:
0190: graphLayout = new GridGraphLayout<FlowNodeDescriptor, FlowEdgeDescriptor>()
0191: .setChecker(true);
0192: sceneLayout = LayoutFactory.createSceneGraphLayout(this ,
0193: graphLayout);
0194:
0195: addObjectSceneListener(new FlowObjectSceneListener(),
0196: ObjectSceneEventType.OBJECT_SELECTION_CHANGED);
0197: }
0198:
0199: public DesignDocument getDocument() {
0200: return document;
0201: }
0202:
0203: // TODO - should not be in API
0204: public void setCurrentEventIDForPreferredNodeLocationProcessing(
0205: Long eventID) {
0206: this .eventID = eventID;
0207: if (eventID != null) {
0208: Iterator<Map.Entry<Long, Point>> iterator = preferredNodeLocationMap
0209: .entrySet().iterator();
0210: while (iterator.hasNext()) {
0211: Map.Entry<Long, Point> entry = iterator.next();
0212: if (entry.getKey() < eventID)
0213: iterator.remove();
0214: }
0215: }
0216: }
0217:
0218: protected Widget attachNodeWidget(FlowNodeDescriptor node) {
0219: Widget widget = getDecorator(node).createWidget(node, this );
0220: Point preferredLocation = preferredNodeLocationCache
0221: .get(new CacheNodeDescriptor(node));
0222: if (preferredLocation == null)
0223: preferredLocation = eventID != null ? preferredNodeLocationMap
0224: .get(eventID)
0225: : null;
0226: if (preferredLocation == null)
0227: preferredLocation = new Point(50, 50);
0228: widget.setPreferredLocation(preferredLocation);
0229: mainLayer.addChild(widget);
0230: return widget;
0231: }
0232:
0233: @Override
0234: protected void detachNodeWidget(FlowNodeDescriptor descriptor,
0235: Widget widget) {
0236: if (widget != null)
0237: preferredNodeLocationCache.put(new CacheNodeDescriptor(
0238: descriptor), widget.getPreferredLocation());
0239: super .detachNodeWidget(descriptor, widget);
0240: }
0241:
0242: protected Widget attachPinWidget(FlowNodeDescriptor node,
0243: FlowPinDescriptor pin) {
0244: FlowPinDescriptor.PinDecorator decorator = getDecorator(pin);
0245: Widget widget = decorator.createWidget(pin, this );
0246: if (widget != null)
0247: getDecorator((FlowNodeDescriptor) findStoredObject(node))
0248: .attachPinWidget(node, this , widget);
0249: return widget;
0250: }
0251:
0252: protected Widget attachEdgeWidget(FlowEdgeDescriptor edge) {
0253: Widget widget = getDecorator(edge).create(edge, this );
0254: assert widget instanceof ConnectionWidget;
0255: connectionLayer.addChild(widget);
0256: return widget;
0257: }
0258:
0259: protected void attachEdgeSourceAnchor(FlowEdgeDescriptor edge,
0260: FlowPinDescriptor oldSourcePin, FlowPinDescriptor sourcePin) {
0261: Anchor anchor = null;
0262: if (sourcePin != null)
0263: anchor = getDecorator(sourcePin).createAnchor(sourcePin,
0264: this );
0265: getDecorator(edge).setSourceAnchor(edge, this , anchor);
0266: }
0267:
0268: protected void attachEdgeTargetAnchor(FlowEdgeDescriptor edge,
0269: FlowPinDescriptor oldTargetPin, FlowPinDescriptor targetPin) {
0270: Anchor anchor = null;
0271: if (targetPin != null)
0272: anchor = getDecorator(targetPin).createAnchor(targetPin,
0273: this );
0274: getDecorator(edge).setTargetAnchor(edge, this , anchor);
0275: }
0276:
0277: public Router createEdgeRouter() {
0278: return edgeRouter;
0279: }
0280:
0281: public WidgetAction createMoveAction() {
0282: return moveAction;
0283: }
0284:
0285: public WidgetAction createAcceptAction() {
0286: return acceptAction;
0287: }
0288:
0289: public WidgetAction createMoveControlPointAction() {
0290: return moveControlPointAction;
0291: }
0292:
0293: public WidgetAction createRenameAction() {
0294: return renameAction;
0295: }
0296:
0297: public WidgetAction createConnectAction() {
0298: return connectAction;
0299: }
0300:
0301: public WidgetAction createReconnectAction() {
0302: return reconnectAction;
0303: }
0304:
0305: public WidgetAction createPopupMenuAction() {
0306: return popupMenuAction;
0307: }
0308:
0309: public WidgetAction createEditAction() {
0310: return editAction;
0311: }
0312:
0313: @Override
0314: public void userSelectionSuggested(
0315: final Set<? extends Object> suggestedSelectedObjects,
0316: boolean invertSelection) {
0317: super .userSelectionSuggested(suggestedSelectedObjects,
0318: invertSelection);
0319:
0320: document.getTransactionManager().writeAccess(new Runnable() {
0321: public void run() {
0322: ArrayList<DesignComponent> selection = new ArrayList<DesignComponent>();
0323: for (Object object : getSelectedObjects()) {
0324: DesignComponent component = object instanceof FlowDescriptor ? ((FlowDescriptor) object)
0325: .getRepresentedComponent()
0326: : null;
0327: if (component != null)
0328: selection.add(component);
0329: }
0330: if (selection.isEmpty()) {
0331: DesignComponent rootComponent = document
0332: .getRootComponent();
0333: if (rootComponent != null)
0334: selection.add(rootComponent);
0335: }
0336: document.setSelectedComponents(
0337: FlowViewController.FLOW_ID, selection);
0338: }
0339: });
0340: }
0341:
0342: public void addNodeCommonActions(Widget widget) {
0343: WidgetAction.Chain actions = widget.getActions();
0344: actions.addAction(createObjectHoverAction());
0345: actions.addAction(createSelectAction());
0346: actions.addAction(createMoveAction());
0347: actions.addAction(createAcceptAction());
0348: actions.addAction(createPopupMenuAction());
0349: actions.addAction(createEditAction());
0350: }
0351:
0352: public void addEdgeCommonActions(ConnectionWidget widget) {
0353: WidgetAction.Chain actions = widget.getActions();
0354: actions.addAction(createObjectHoverAction());
0355: actions.addAction(createSelectAction());
0356: actions.addAction(createReconnectAction());
0357: actions.addAction(createPopupMenuAction());
0358: actions.addAction(createEditAction());
0359: }
0360:
0361: public void addPinCommonActions(Widget widget) {
0362: WidgetAction.Chain actions = widget.getActions();
0363: actions.addAction(createObjectHoverAction());
0364: widget.getActions().addAction(createSelectAction());
0365: widget.getActions().addAction(createAcceptAction());
0366: widget.getActions().addAction(createConnectAction());
0367: actions.addAction(createPopupMenuAction());
0368: actions.addAction(createEditAction());
0369: }
0370:
0371: public void addBadge(FlowDescriptor descriptor,
0372: FlowBadgeDescriptor badge) {
0373: if (badge == null)
0374: return;
0375: ArrayList<FlowBadgeDescriptor> list = badges.get(descriptor);
0376: if (list == null)
0377: badges.put(descriptor,
0378: list = new ArrayList<FlowBadgeDescriptor>());
0379: list.add(badge);
0380: }
0381:
0382: public void removeBadge(FlowDescriptor descriptor,
0383: FlowBadgeDescriptor badge) {
0384: ArrayList<FlowBadgeDescriptor> list = badges.get(descriptor);
0385: if (list == null)
0386: return;
0387: list.remove(badge);
0388: if (list.isEmpty())
0389: badges.remove(descriptor);
0390: }
0391:
0392: public void updateBadges(FlowDescriptor descriptor) {
0393: FlowDescriptor.BadgeDecorator decorator = getAbstractDecorator(
0394: descriptor, FlowDescriptor.BadgeDecorator.class);
0395: if (decorator == null)
0396: return;
0397: ArrayList<FlowBadgeDescriptor> list = badges.get(descriptor);
0398: if (list != null) {
0399: Collections.sort(list,
0400: new Comparator<FlowBadgeDescriptor>() {
0401: public int compare(FlowBadgeDescriptor o1,
0402: FlowBadgeDescriptor o2) {
0403: return getDecorator(o1).getOrder(o1)
0404: - getDecorator(o2).getOrder(o2);
0405: }
0406: });
0407: decorator.updateBadges(descriptor, this , list);
0408: } else {
0409: decorator.updateBadges(descriptor, this , Collections
0410: .<FlowBadgeDescriptor> emptyList());
0411: }
0412: }
0413:
0414: public void registerUI(FlowNodeDescriptor descriptor,
0415: FlowPresenter.FlowUIResolver resolver) {
0416: assert resolver != null;
0417: nodeUIregistry.put(descriptor, resolver);
0418: }
0419:
0420: public void unregisterUI(FlowNodeDescriptor descriptor,
0421: FlowPresenter.FlowUIResolver resolver) {
0422: FlowPresenter.FlowUIResolver resolver2 = nodeUIregistry
0423: .remove(descriptor);
0424: assert resolver == resolver2;
0425: }
0426:
0427: public FlowNodeDescriptor.NodeDecorator getDecorator(
0428: FlowNodeDescriptor node) {
0429: return (FlowNodeDescriptor.NodeDecorator) nodeUIregistry.get(
0430: node).getDecorator();
0431: }
0432:
0433: public FlowNodeDescriptor.NodeBehaviour getBehaviour(
0434: FlowNodeDescriptor node) {
0435: return (FlowNodeDescriptor.NodeBehaviour) nodeUIregistry.get(
0436: node).getBehaviour();
0437: }
0438:
0439: public void registerUI(FlowPinDescriptor descriptor,
0440: FlowPresenter.FlowUIResolver resolver) {
0441: assert resolver != null;
0442: pinUIregistry.put(descriptor, resolver);
0443: }
0444:
0445: public void unregisterUI(FlowPinDescriptor descriptor,
0446: FlowPresenter.FlowUIResolver resolver) {
0447: FlowPresenter.FlowUIResolver resolver2 = pinUIregistry
0448: .remove(descriptor);
0449: assert resolver == resolver2;
0450: }
0451:
0452: public FlowPinDescriptor.PinDecorator getDecorator(
0453: FlowPinDescriptor pin) {
0454: return (FlowPinDescriptor.PinDecorator) pinUIregistry.get(pin)
0455: .getDecorator();
0456: }
0457:
0458: public FlowPinDescriptor.PinBehaviour getBehaviour(
0459: FlowPinDescriptor pin) {
0460: return (FlowPinDescriptor.PinBehaviour) pinUIregistry.get(pin)
0461: .getBehaviour();
0462: }
0463:
0464: public void registerUI(FlowEdgeDescriptor descriptor,
0465: FlowPresenter.FlowUIResolver resolver) {
0466: assert resolver != null;
0467: edgeUIregistry.put(descriptor, resolver);
0468: }
0469:
0470: public void unregisterUI(FlowEdgeDescriptor descriptor,
0471: FlowPresenter.FlowUIResolver resolver) {
0472: FlowPresenter.FlowUIResolver resolver2 = edgeUIregistry
0473: .remove(descriptor);
0474: assert resolver == resolver2;
0475: }
0476:
0477: public FlowEdgeDescriptor.EdgeDecorator getDecorator(
0478: FlowEdgeDescriptor edge) {
0479: return (FlowEdgeDescriptor.EdgeDecorator) edgeUIregistry.get(
0480: edge).getDecorator();
0481: }
0482:
0483: public FlowEdgeDescriptor.EdgeBehaviour getBehaviour(
0484: FlowEdgeDescriptor edge) {
0485: return (FlowEdgeDescriptor.EdgeBehaviour) edgeUIregistry.get(
0486: edge).getBehaviour();
0487: }
0488:
0489: public void registerUI(FlowBadgeDescriptor descriptor,
0490: FlowPresenter.FlowUIResolver resolver) {
0491: assert resolver != null;
0492: pinBadgeUIregistry.put(descriptor, resolver);
0493: }
0494:
0495: public void unregisterUI(FlowBadgeDescriptor descriptor,
0496: FlowPresenter.FlowUIResolver resolver) {
0497: FlowPresenter.FlowUIResolver resolver2 = pinBadgeUIregistry
0498: .remove(descriptor);
0499: assert resolver == resolver2;
0500: }
0501:
0502: public FlowBadgeDescriptor.BadgeDecorator getDecorator(
0503: FlowBadgeDescriptor pinBadge) {
0504: return (FlowBadgeDescriptor.BadgeDecorator) pinBadgeUIregistry
0505: .get(pinBadge).getDecorator();
0506: }
0507:
0508: public FlowBadgeDescriptor.BadgeBehaviour getBehaviour(
0509: FlowBadgeDescriptor pinBadge) {
0510: return (FlowBadgeDescriptor.BadgeBehaviour) pinBadgeUIregistry
0511: .get(pinBadge).getBehaviour();
0512: }
0513:
0514: private <T extends FlowDescriptor.Decorator> T getAbstractDecorator(
0515: FlowDescriptor descriptor, Class<T> clazz) {
0516: if (descriptor == null)
0517: return null;
0518: FlowPresenter.FlowUIResolver presenter = nodeUIregistry
0519: .get(descriptor);
0520: if (presenter == null) {
0521: presenter = pinUIregistry.get(descriptor);
0522: if (presenter == null) {
0523: presenter = edgeUIregistry.get(descriptor);
0524: if (presenter == null) {
0525: presenter = pinBadgeUIregistry.get(descriptor);
0526: if (presenter == null)
0527: return null;
0528: }
0529: }
0530: }
0531: FlowDescriptor.Decorator decorator = presenter.getDecorator();
0532: return clazz.isInstance(decorator) ? (T) decorator : null;
0533: }
0534:
0535: private <T extends FlowDescriptor.Behaviour> T getAbstractBehaviour(
0536: FlowDescriptor descriptor, Class<T> clazz) {
0537: if (descriptor == null)
0538: return null;
0539: FlowPresenter.FlowUIResolver presenter = nodeUIregistry
0540: .get(descriptor);
0541: if (presenter == null) {
0542: presenter = pinUIregistry.get(descriptor);
0543: if (presenter == null) {
0544: presenter = edgeUIregistry.get(descriptor);
0545: if (presenter == null) {
0546: presenter = pinBadgeUIregistry.get(descriptor);
0547: if (presenter == null)
0548: return null;
0549: }
0550: }
0551: }
0552: FlowDescriptor.Behaviour behaviour = presenter.getBehaviour();
0553: return clazz.isInstance(behaviour) ? (T) behaviour : null;
0554: }
0555:
0556: public void scheduleNodeDescriptorForOrdering(
0557: FlowNodeDescriptor node) {
0558: nodesForOrdering.add(node);
0559: }
0560:
0561: public void resolveOrderInNodeDescriptors() {
0562: for (FlowNodeDescriptor node : nodesForOrdering) {
0563: if (!isNode(node))
0564: continue;
0565: FlowNodeDescriptor.NodeDecorator decorator = getDecorator(node);
0566:
0567: DesignComponent orderComponent = decorator
0568: .getComponentWithPinOrderPresenters();
0569: if (orderComponent == null) {
0570: decorator.orderPins(node, this , Collections
0571: .<String, List<FlowPinDescriptor>> emptyMap());
0572: continue;
0573: }
0574: Collection<? extends FlowPinOrderPresenter> presenters = orderComponent
0575: .getPresenters(FlowPinOrderPresenter.class);
0576:
0577: if (presenters.isEmpty()) {
0578: decorator.orderPins(node, this , Collections
0579: .<String, List<FlowPinDescriptor>> emptyMap());
0580: continue;
0581: }
0582:
0583: HashMap<String, ArrayList<FlowPinDescriptor>> categories = new HashMap<String, ArrayList<FlowPinDescriptor>>();
0584:
0585: for (FlowPinDescriptor pin : getNodePins(node)) {
0586: String category = getDecorator(pin).getOrderCategory(
0587: pin);
0588: ArrayList<FlowPinDescriptor> list = categories
0589: .get(category);
0590: if (list == null) {
0591: list = new ArrayList<FlowPinDescriptor>();
0592: categories.put(category, list);
0593: }
0594: list.add(pin);
0595: }
0596:
0597: HashMap<String, List<FlowPinDescriptor>> order = new HashMap<String, List<FlowPinDescriptor>>();
0598: for (FlowPinOrderPresenter presenter : presenters) {
0599: String category = presenter.getCategoryID();
0600: ArrayList<FlowPinDescriptor> descriptors = categories
0601: .get(category);
0602: if (descriptors != null)
0603: order.put(presenter.getCategoryDisplayName(),
0604: presenter.sortCategory(descriptors));
0605: }
0606:
0607: decorator.orderPins(node, this , order);
0608: }
0609: nodesForOrdering.clear();
0610: }
0611:
0612: /**
0613: * Invokes layout of the scene.
0614: */
0615: public void layoutScene() {
0616: sceneLayout.invokeLayout();
0617: }
0618:
0619: private Anchor createAnchorForDescriptor(FlowDescriptor descriptor) {
0620: Anchor anchor = null;
0621: if (descriptor != null) {
0622: if (descriptor instanceof FlowNodeDescriptor) {
0623: FlowNodeDescriptor node = (FlowNodeDescriptor) descriptor;
0624: FlowNodeDescriptor.NodeDecorator decorator = getDecorator(node);
0625: if (decorator != null)
0626: anchor = decorator.createAnchor(node, this );
0627: } else if (descriptor instanceof FlowPinDescriptor) {
0628: FlowPinDescriptor pin = (FlowPinDescriptor) descriptor;
0629: FlowPinDescriptor.PinDecorator decorator = getDecorator(pin);
0630: if (decorator != null)
0631: anchor = decorator.createAnchor(pin, this );
0632: }
0633: }
0634: return anchor;
0635: }
0636:
0637: private class FlowObjectSceneListener implements
0638: ObjectSceneListener {
0639:
0640: public void objectAdded(ObjectSceneEvent event,
0641: Object addedObject) {
0642: }
0643:
0644: public void objectRemoved(ObjectSceneEvent event,
0645: Object removedObject) {
0646: }
0647:
0648: public void objectStateChanged(ObjectSceneEvent event,
0649: Object changedObject, ObjectState previousState,
0650: ObjectState newState) {
0651: }
0652:
0653: public void selectionChanged(ObjectSceneEvent event,
0654: Set<Object> previousSelection, Set<Object> newSelection) {
0655: HashSet<Object> set = new HashSet<Object>();
0656: for (Object object : newSelection) {
0657: if (isNode(object)) {
0658: for (FlowPinDescriptor pin : getNodePins((FlowNodeDescriptor) object))
0659: set.addAll(findPinEdges(pin, true, true));
0660: } else if (isPin(object))
0661: set.addAll(findPinEdges((FlowPinDescriptor) object,
0662: true, true));
0663: }
0664: setHighlightedObjects(set);
0665: }
0666:
0667: public void highlightingChanged(ObjectSceneEvent event,
0668: Set<Object> previousHighlighting,
0669: Set<Object> newHighlighting) {
0670: }
0671:
0672: public void hoverChanged(ObjectSceneEvent event,
0673: Object previousHoveredObject, Object newHoveredObject) {
0674: }
0675:
0676: public void focusChanged(ObjectSceneEvent event,
0677: Object previousFocusedObject, Object newFocusedObject) {
0678: }
0679:
0680: }
0681:
0682: private class FlowAcceptProvider implements AcceptProvider {
0683:
0684: public ConnectorState isAcceptable(final Widget widget,
0685: Point point, final Transferable transferable) {
0686: if (widget == null)
0687: return ConnectorState.REJECT_AND_STOP;
0688: final ConnectorState[] ret = new ConnectorState[] { ConnectorState.REJECT };
0689: document.getTransactionManager().readAccess(new Runnable() {
0690: public void run() {
0691: if (widget == FlowScene.this ) {
0692: DesignComponent rootComponent = document
0693: .getRootComponent();
0694: FlowDescriptor rootDescriptor = new FlowDescriptor(
0695: rootComponent, "accept") {
0696: }; // NOI18N
0697: Collection<? extends FlowScenePresenter> presenters = rootComponent
0698: .getPresenters(FlowScenePresenter.class);
0699: for (FlowScenePresenter presenter : presenters) {
0700: FlowDescriptor.Behaviour behavior = presenter
0701: .getBehavior();
0702: if (behavior instanceof FlowDescriptor.AcceptActionBehaviour) {
0703: FlowDescriptor.AcceptActionBehaviour acceptBehaviour = (FlowDescriptor.AcceptActionBehaviour) behavior;
0704: if (acceptBehaviour.isAcceptable(
0705: rootDescriptor, transferable)) {
0706: ret[0] = ConnectorState.ACCEPT;
0707: break;
0708: }
0709: }
0710: }
0711: } else {
0712: FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
0713: FlowDescriptor.AcceptActionBehaviour behaviour = getAbstractBehaviour(
0714: descriptor,
0715: FlowDescriptor.AcceptActionBehaviour.class);
0716: if (behaviour != null)
0717: if (behaviour.isAcceptable(descriptor,
0718: transferable))
0719: ret[0] = ConnectorState.ACCEPT;
0720: }
0721: }
0722: });
0723: return ret[0];
0724: }
0725:
0726: public void accept(final Widget widget, Point point,
0727: final Transferable transferable) {
0728: if (widget == null)
0729: return;
0730: long eventID = document.getTransactionManager()
0731: .writeAccess(new Runnable() {
0732: public void run() {
0733: if (widget == FlowScene.this ) {
0734: DesignComponent rootComponent = document
0735: .getRootComponent();
0736: FlowDescriptor rootDescriptor = new FlowDescriptor(
0737: rootComponent, "accept") {
0738: }; // NOI18N
0739: Collection<? extends FlowScenePresenter> presenters = rootComponent
0740: .getPresenters(FlowScenePresenter.class);
0741: for (FlowScenePresenter presenter : presenters) {
0742: FlowDescriptor.Behaviour behavior = presenter
0743: .getBehavior();
0744: if (behavior instanceof FlowDescriptor.AcceptActionBehaviour) {
0745: FlowDescriptor.AcceptActionBehaviour acceptBehaviour = (FlowDescriptor.AcceptActionBehaviour) behavior;
0746: if (acceptBehaviour
0747: .isAcceptable(
0748: rootDescriptor,
0749: transferable))
0750: acceptBehaviour.accept(
0751: rootDescriptor,
0752: transferable);
0753: }
0754: }
0755: } else {
0756: FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
0757: FlowDescriptor.AcceptActionBehaviour behaviour = getAbstractBehaviour(
0758: descriptor,
0759: FlowDescriptor.AcceptActionBehaviour.class);
0760: if (behaviour != null)
0761: behaviour.accept(descriptor,
0762: transferable);
0763: }
0764: }
0765: });
0766: preferredNodeLocationMap.put(eventID, widget
0767: .convertLocalToScene(point));
0768: PaletteSupport.getPaletteController(document)
0769: .clearSelection();
0770: }
0771:
0772: }
0773:
0774: private class FlowSceneSelectAction extends WidgetAction.Adapter {
0775:
0776: @Override
0777: public State mousePressed(final Widget widget,
0778: final WidgetMouseEvent event) {
0779: final boolean[] ret = new boolean[] { false };
0780: long eventID = document.getTransactionManager()
0781: .writeAccess(new Runnable() {
0782: public void run() {
0783: if (widget == FlowScene.this ) {
0784: DesignComponent rootComponent = document
0785: .getRootComponent();
0786: if (rootComponent == null)
0787: return;
0788: FlowDescriptor rootDescriptor = new FlowDescriptor(
0789: rootComponent, "select") {
0790: }; // NOI18N
0791: Collection<? extends FlowScenePresenter> presenters = rootComponent
0792: .getPresenters(FlowScenePresenter.class);
0793: for (FlowScenePresenter presenter : presenters) {
0794: FlowDescriptor.Behaviour behavior = presenter
0795: .getBehavior();
0796: if (behavior instanceof FlowDescriptor.SelectActionBehaviour) {
0797: FlowDescriptor.SelectActionBehaviour selectBehaviour = (FlowDescriptor.SelectActionBehaviour) behavior;
0798: if (selectBehaviour
0799: .select(
0800: rootDescriptor,
0801: event
0802: .getModifiers())) {
0803: ret[0] = true;
0804: return;
0805: }
0806: }
0807: }
0808: }
0809: }
0810: });
0811: preferredNodeLocationMap.put(eventID, widget
0812: .convertLocalToScene(event.getPoint()));
0813:
0814: return ret[0] ? State.CONSUMED : State.REJECTED;
0815: }
0816:
0817: }
0818:
0819: private class FlowConnectDecoratorProvider implements
0820: ConnectDecorator, ConnectProvider {
0821:
0822: private FlowPinDescriptor source = null;
0823: private FlowDescriptor target = null;
0824:
0825: public ConnectionWidget createConnectionWidget(Scene scene) {
0826: return ActionFactory.createDefaultConnectDecorator()
0827: .createConnectionWidget(scene);
0828: }
0829:
0830: public Anchor createSourceAnchor(Widget sourceWidget) {
0831: return createAnchorForDescriptor(source);
0832: }
0833:
0834: public Anchor createTargetAnchor(Widget targetWidget) {
0835: return createAnchorForDescriptor(target);
0836: }
0837:
0838: public Anchor createFloatAnchor(Point point) {
0839: return ActionFactory.createDefaultConnectDecorator()
0840: .createFloatAnchor(point);
0841: }
0842:
0843: public boolean isSourceWidget(final Widget sourceWidget) {
0844: final boolean[] ret = new boolean[] { false };
0845: document.getTransactionManager().readAccess(new Runnable() {
0846: public void run() {
0847: Object object = findObject(sourceWidget);
0848: if (isPin(object)) {
0849: source = (FlowPinDescriptor) object;
0850: ret[0] = getBehaviour(source)
0851: .isConnectionSource(source);
0852: } else
0853: ret[0] = false;
0854: }
0855: });
0856: return ret[0];
0857: }
0858:
0859: public ConnectorState isTargetWidget(Widget sourceWidget,
0860: final Widget targetWidget) {
0861: final ConnectorState[] ret = new ConnectorState[] { ConnectorState.REJECT };
0862: document.getTransactionManager().readAccess(new Runnable() {
0863: public void run() {
0864: target = (FlowDescriptor) findObject(targetWidget);
0865: ret[0] = getBehaviour(source).isConnectionTarget(
0866: source, target) ? ConnectorState.ACCEPT
0867: : ConnectorState.REJECT;
0868: }
0869: });
0870: return ret[0];
0871: }
0872:
0873: public boolean hasCustomTargetWidgetResolver(Scene scene) {
0874: return false;
0875: }
0876:
0877: public Widget resolveTargetWidget(Scene scene, Point point) {
0878: return null;
0879: }
0880:
0881: public void createConnection(Widget sourceWidget,
0882: Widget targetWidget) {
0883: document.getTransactionManager().writeAccess(
0884: new Runnable() {
0885: public void run() {
0886: FlowPinDescriptor.PinBehaviour behaviour = getBehaviour(source);
0887: if (behaviour.isConnectionTarget(source,
0888: target))
0889: behaviour.createConnection(source,
0890: target);
0891: }
0892: });
0893: }
0894:
0895: }
0896:
0897: private class FlowReconnectDecoratorProvider implements
0898: ReconnectDecorator, ReconnectProvider {
0899:
0900: private FlowDescriptor replacement = null;
0901:
0902: public Anchor createReplacementWidgetAnchor(
0903: Widget replacementWidget) {
0904: return createAnchorForDescriptor(replacement);
0905: }
0906:
0907: public Anchor createFloatAnchor(Point point) {
0908: return ActionFactory.createDefaultReconnectDecorator()
0909: .createFloatAnchor(point);
0910: }
0911:
0912: public boolean isSourceReconnectable(
0913: final ConnectionWidget connectionWidget) {
0914: final boolean[] ret = new boolean[] { false };
0915: document.getTransactionManager().readAccess(new Runnable() {
0916: public void run() {
0917: Object object = findObject(connectionWidget);
0918: if (!isEdge(object))
0919: return;
0920: FlowEdgeDescriptor edge = (FlowEdgeDescriptor) object;
0921: ret[0] = getBehaviour(edge).isSourceReconnectable(
0922: edge);
0923: }
0924: });
0925: return ret[0];
0926: }
0927:
0928: public boolean isTargetReconnectable(
0929: final ConnectionWidget connectionWidget) {
0930: final boolean[] ret = new boolean[] { false };
0931: document.getTransactionManager().readAccess(new Runnable() {
0932: public void run() {
0933: Object object = findObject(connectionWidget);
0934: if (!isEdge(object))
0935: return;
0936: FlowEdgeDescriptor edge = (FlowEdgeDescriptor) object;
0937: ret[0] = getBehaviour(edge).isTargetReconnectable(
0938: edge);
0939: }
0940: });
0941: return ret[0];
0942: }
0943:
0944: public void reconnectingStarted(
0945: ConnectionWidget connectionWidget, boolean b) {
0946: }
0947:
0948: public void reconnectingFinished(
0949: ConnectionWidget connectionWidget, boolean b) {
0950: }
0951:
0952: public ConnectorState isReplacementWidget(
0953: final ConnectionWidget connectionWidget,
0954: final Widget replacementWidget,
0955: final boolean reconnectingSource) {
0956: final ConnectorState[] ret = new ConnectorState[1];
0957: document.getTransactionManager().readAccess(new Runnable() {
0958: public void run() {
0959: Object object = findObject(connectionWidget);
0960: if (!isEdge(object))
0961: return;
0962: FlowEdgeDescriptor edge = (FlowEdgeDescriptor) object;
0963: replacement = (FlowDescriptor) findObject(replacementWidget);
0964: ret[0] = getBehaviour(edge).isReplacement(edge,
0965: replacement, reconnectingSource) ? ConnectorState.ACCEPT
0966: : ConnectorState.REJECT;
0967: }
0968: });
0969: return ret[0];
0970: }
0971:
0972: public boolean hasCustomReplacementWidgetResolver(Scene scene) {
0973: return false;
0974: }
0975:
0976: public Widget resolveReplacementWidget(Scene scene, Point point) {
0977: return null;
0978: }
0979:
0980: public void reconnect(final ConnectionWidget connectionWidget,
0981: final Widget replacementWidget,
0982: final boolean reconnectingSource) {
0983: document.getTransactionManager().writeAccess(
0984: new Runnable() {
0985: public void run() {
0986: Object object = findObject(connectionWidget);
0987: if (!isEdge(object))
0988: return;
0989: FlowEdgeDescriptor edge = (FlowEdgeDescriptor) object;
0990: replacement = (FlowDescriptor) findObject(replacementWidget);
0991: FlowEdgeDescriptor.EdgeBehaviour behaviour = getBehaviour(edge);
0992: if (behaviour.isReplacement(edge,
0993: replacement, reconnectingSource))
0994: behaviour
0995: .setReplacement(edge,
0996: replacement,
0997: reconnectingSource);
0998: }
0999: });
1000: }
1001:
1002: }
1003:
1004: private class FlowPopupMenuProvider implements PopupMenuProvider {
1005:
1006: public JPopupMenu getPopupMenu(Widget widget,
1007: Point localLocation) {
1008: JComponent component = FlowScene.this .getView();
1009:
1010: if (widget == FlowScene.this ) {
1011: final DesignComponent[] ret = new DesignComponent[1];
1012: document.getTransactionManager().readAccess(
1013: new Runnable() {
1014: public void run() {
1015: ret[0] = document.getRootComponent();
1016: }
1017: });
1018:
1019: if (!getSelectedObjects().isEmpty())
1020: userSelectionSuggested(Collections.emptySet(),
1021: false);
1022:
1023: return Utilities.actionsToPopup(ActionsSupport
1024: .createActionsArray(ret[0]), component);
1025: }
1026:
1027: FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1028: if (descriptor == null)
1029: return null;
1030:
1031: setFocusedObject(descriptor);
1032: if (!getSelectedObjects().contains(descriptor))
1033: userSelectionSuggested(Collections
1034: .singleton(descriptor), false);
1035:
1036: return Utilities.actionsToPopup(ActionsSupport
1037: .createActionsArray(descriptor
1038: .getRepresentedComponent()), component);
1039: }
1040: }
1041:
1042: private class FlowSceneKeyAction extends WidgetAction.Adapter {
1043:
1044: @Override
1045: public State keyPressed(Widget widget, WidgetKeyEvent event) {
1046: // HINT - FlowDescriptor.KeyActionBehaviour is used for FlowScene/rootComponent only
1047: final FlowDescriptor.KeyActionBehaviour[] ret = new FlowDescriptor.KeyActionBehaviour[1];
1048: document.getTransactionManager().readAccess(new Runnable() {
1049: public void run() {
1050: DesignComponent root = document.getRootComponent();
1051: if (root != null) {
1052: FlowScenePresenter presenter = root
1053: .getPresenter(FlowScenePresenter.class);
1054: if (presenter != null) {
1055: FlowDescriptor.Behaviour behavior = presenter
1056: .getBehavior();
1057: if (behavior instanceof FlowDescriptor.KeyActionBehaviour)
1058: ret[0] = (FlowDescriptor.KeyActionBehaviour) behavior;
1059: }
1060: }
1061: }
1062: });
1063: return ret[0] != null && ret[0].keyPressed(event) ? State.CONSUMED
1064: : State.REJECTED;
1065: }
1066: }
1067:
1068: private class FlowRenameEditor implements TextFieldInplaceEditor {
1069:
1070: public boolean isEnabled(final Widget widget) {
1071: final FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1072: if (descriptor == null)
1073: return false;
1074: final boolean[] ret = new boolean[] { false };
1075: document.getTransactionManager().readAccess(new Runnable() {
1076: public void run() {
1077: FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1078: FlowDescriptor.RenameActionBehaviour behaviour = getAbstractBehaviour(
1079: descriptor,
1080: FlowDescriptor.RenameActionBehaviour.class);
1081: if (behaviour != null)
1082: ret[0] = behaviour.isEditable(descriptor);
1083: }
1084: });
1085: return ret[0];
1086: }
1087:
1088: public String getText(final Widget widget) {
1089: final FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1090: if (descriptor == null)
1091: return null;
1092: final String[] ret = new String[] { null };
1093: document.getTransactionManager().readAccess(new Runnable() {
1094: public void run() {
1095: FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1096: FlowDescriptor.RenameActionBehaviour behaviour = getAbstractBehaviour(
1097: descriptor,
1098: FlowDescriptor.RenameActionBehaviour.class);
1099: if (behaviour != null)
1100: ret[0] = behaviour.getText(descriptor);
1101: }
1102: });
1103: return ret[0];
1104: }
1105:
1106: public void setText(final Widget widget, final String text) {
1107: final FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1108: if (descriptor == null)
1109: return;
1110: document.getTransactionManager().writeAccess(
1111: new Runnable() {
1112: public void run() {
1113: FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1114: FlowDescriptor.RenameActionBehaviour behaviour = getAbstractBehaviour(
1115: descriptor,
1116: FlowDescriptor.RenameActionBehaviour.class);
1117: if (behaviour != null)
1118: behaviour.setText(descriptor, text);
1119: }
1120: });
1121: }
1122:
1123: }
1124:
1125: private class FlowEditProvider implements EditProvider {
1126:
1127: public void edit(final Widget widget) {
1128: final FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1129: if (descriptor == null)
1130: return;
1131: document.getTransactionManager().writeAccess(
1132: new Runnable() {
1133: public void run() {
1134: FlowDescriptor descriptor = (FlowDescriptor) findObject(widget);
1135: FlowDescriptor.EditActionBehaviour behaviour = getAbstractBehaviour(
1136: descriptor,
1137: FlowDescriptor.EditActionBehaviour.class);
1138: if (behaviour != null)
1139: behaviour.edit(descriptor);
1140: }
1141: });
1142: }
1143: }
1144:
1145: private class FlowMoveProvider implements MoveProvider {
1146:
1147: private HashMap<Widget, Point> originals = new HashMap<Widget, Point>();
1148: private Point original;
1149:
1150: public void movementStarted(Widget widget) {
1151: Object object = findObject(widget);
1152: if (isNode(object)) {
1153: for (Object o : getSelectedObjects())
1154: if (isNode(o)) {
1155: Widget w = findWidget(o);
1156: if (w != null)
1157: originals.put(w, w.getPreferredLocation());
1158: }
1159: } else {
1160: originals.put(widget, widget.getPreferredLocation());
1161: }
1162: }
1163:
1164: public void movementFinished(Widget widget) {
1165: originals.clear();
1166: original = null;
1167: }
1168:
1169: public Point getOriginalLocation(Widget widget) {
1170: original = widget.getPreferredLocation();
1171: return original;
1172: }
1173:
1174: public void setNewLocation(Widget widget, Point location) {
1175: int dx = location.x - original.x;
1176: int dy = location.y - original.y;
1177: for (Map.Entry<Widget, Point> entry : originals.entrySet()) {
1178: Point point = entry.getValue();
1179: entry.getKey().setPreferredLocation(
1180: new Point(point.x + dx, point.y + dy));
1181: }
1182: }
1183:
1184: }
1185:
1186: private final static class CacheNodeDescriptor {
1187:
1188: private long componentid;
1189: private String descriptorid;
1190:
1191: public CacheNodeDescriptor(FlowNodeDescriptor node) {
1192: componentid = node.getRepresentedComponent()
1193: .getComponentID();
1194: descriptorid = node.getDescriptorID();
1195: }
1196:
1197: @Override
1198: public boolean equals(Object o) {
1199: if (this == o)
1200: return true;
1201: if (o == null || getClass() != o.getClass())
1202: return false;
1203: final CacheNodeDescriptor desc = (CacheNodeDescriptor) o;
1204: return componentid == desc.componentid
1205: && descriptorid.equals(desc.descriptorid);
1206: }
1207:
1208: @Override
1209: public int hashCode() {
1210: int result;
1211: result = (int) (componentid ^ (componentid >>> 32));
1212: result = 29
1213: * result
1214: + (descriptorid != null ? descriptorid.hashCode()
1215: : 0);
1216: return result;
1217: }
1218:
1219: }
1220:
1221: }
|