]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sg/DiagramSceneGraphProvider.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / sg / DiagramSceneGraphProvider.java
diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sg/DiagramSceneGraphProvider.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sg/DiagramSceneGraphProvider.java
new file mode 100644 (file)
index 0000000..21a8057
--- /dev/null
@@ -0,0 +1,481 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.modeling.ui.sg;
+
+import java.awt.Color;\r
+import java.awt.event.AWTEventListener;\r
+\r
+import org.eclipse.core.runtime.NullProgressMonitor;\r
+import org.simantics.Simantics;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.ResourceArray;\r
+import org.simantics.db.common.primitiverequest.PossibleAdapter;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
+import org.simantics.db.exception.NoSingleResultException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.diagram.adapter.DefaultConnectionClassFactory;\r
+import org.simantics.diagram.adapter.FlagClassFactory;\r
+import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;\r
+import org.simantics.diagram.handler.CopyPasteHandler;\r
+import org.simantics.diagram.handler.CopyPasteStrategy;\r
+import org.simantics.diagram.handler.DefaultCopyPasteStrategy;\r
+import org.simantics.diagram.handler.DeleteHandler;\r
+import org.simantics.diagram.handler.SimpleElementTransformHandler;\r
+import org.simantics.diagram.query.DiagramRequests;\r
+import org.simantics.diagram.runtime.RuntimeDiagramManager;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.diagram.synchronization.CopyAdvisor;\r
+import org.simantics.diagram.synchronization.SynchronizationHints;\r
+import org.simantics.diagram.ui.DiagramModelHints;\r
+import org.simantics.g2d.canvas.Hints;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.canvas.impl.CanvasContext;\r
+import org.simantics.g2d.diagram.DiagramHints;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.participant.DiagramParticipant;\r
+import org.simantics.g2d.diagram.participant.ElementInteractor;\r
+import org.simantics.g2d.diagram.participant.ElementPainter;\r
+import org.simantics.g2d.diagram.participant.Selection;\r
+import org.simantics.g2d.diagram.participant.ZOrderHandler;\r
+import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;\r
+import org.simantics.g2d.element.ElementClassProviders;\r
+import org.simantics.g2d.element.ElementClasses;\r
+import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;\r
+import org.simantics.g2d.multileveldiagram.TransitionFunction;\r
+import org.simantics.g2d.multileveldiagram.ZoomTransitionParticipant;\r
+import org.simantics.g2d.page.DiagramDesc;\r
+import org.simantics.g2d.participant.BackgroundPainter;\r
+import org.simantics.g2d.participant.CanvasBoundsParticipant;\r
+import org.simantics.g2d.participant.CanvasGrab;\r
+import org.simantics.g2d.participant.GridPainter;\r
+import org.simantics.g2d.participant.KeyToCommand;\r
+import org.simantics.g2d.participant.KeyUtil;\r
+import org.simantics.g2d.participant.MouseUtil;\r
+import org.simantics.g2d.participant.MultitouchPanZoomRotateInteractor;\r
+import org.simantics.g2d.participant.Notifications;\r
+import org.simantics.g2d.participant.PageBorderParticipant;\r
+import org.simantics.g2d.participant.PanZoomRotateHandler;\r
+import org.simantics.g2d.participant.PointerPainter;\r
+import org.simantics.g2d.participant.RulerPainter;\r
+import org.simantics.g2d.participant.SymbolUtil;\r
+import org.simantics.g2d.participant.TimeParticipant;\r
+import org.simantics.g2d.participant.TransformUtil;\r
+import org.simantics.g2d.participant.ZoomToAreaHandler;\r
+import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.modeling.mapping.ComponentCopyAdvisor;\r
+import org.simantics.modeling.mapping.ElementCopyAdvisor;\r
+import org.simantics.modeling.mapping.MappedElementCopyAdvisor;\r
+import org.simantics.modeling.mapping.ModelingSynchronizationHints;\r
+import org.simantics.modeling.ui.diagramEditor.PopulateElementDropParticipant;\r
+import org.simantics.modeling.ui.diagramEditor.PopulateElementMonitorDropParticipant;\r
+import org.simantics.modeling.ui.diagramEditor.handlers.HeadlessStructuralBrowsingHandler;\r
+import org.simantics.modeling.ui.diagramEditor.handlers.HeadlessStructuralBrowsingHandler.IDiagramUpdateSupport;\r
+import org.simantics.scenegraph.g2d.G2DSceneGraph;\r
+import org.simantics.scenegraph.g2d.events.adapter.AWTRemoteEventAdapter;\r
+import org.simantics.scenegraph.g2d.events.command.CommandKeyBinding;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.structural2.modelingRules.IModelingRules;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.utils.datastructures.hints.HintContext;\r
+import org.simantics.utils.datastructures.hints.IHintContext;\r
+import org.simantics.utils.page.PageDesc;\r
+import org.simantics.utils.page.PageOrientation;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.IThreadWorkQueue;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+
+
+/**
+ * ISceneGraphProvider implementation for diagrams.
+ * TODO: decide if this should be stateless or stateful class
+ * 
+ * @author J-P Laine
+ *
+ */
+public class DiagramSceneGraphProvider implements ICanvasSceneGraphProvider, IDiagramUpdateSupport {
+\r
+       protected boolean isSymbol = false;
+    protected Resource resource;
+    protected ResourceArray structuralPath = null;
+    protected IDiagram diagram = null;
+    protected CanvasContext ctx = null;\r
+    protected boolean ownsContext = false;
+    protected GraphToDiagramSynchronizer synchronizer = null;
+    protected String view = null;
+    protected Boolean navigation = null;
+
+    protected AWTRemoteEventAdapter listener = null;
+\r
+    final IHintContext initialHints = new HintContext();\r
+
+    public DiagramSceneGraphProvider(ReadGraph g, final Resource diagramOrComposite) {\r
+        this.structuralPath = new ResourceArray();
+        try {\r
+\r
+            StructuralResource2 sr = StructuralResource2.getInstance(g);\r
+               DiagramResource DIA = DiagramResource.getInstance(g);\r
+               \r
+               Resource diagram = diagramOrComposite;\r
+               if(!g.isInstanceOf(diagram, DIA.Composite)) {\r
+                       \r
+                ModelingResources mr = ModelingResources.getInstance(g);\r
+                       diagram = g.getPossibleObject(diagramOrComposite, mr.CompositeToDiagram);\r
+                       if(diagram == null) {\r
+                    // looks like we have a component without direct relation to composite.. try to solve this\r
+                    // FIXME: use adapter to get composite directly from resource\r
+                    final Resource type = g.getSingleType(diagramOrComposite, sr.Component);\r
+                    if (type == null)\r
+                        return;\r
+\r
+                    final Resource definedBy = g.getPossibleObject(type, sr.IsDefinedBy);\r
+                    if (definedBy == null)\r
+                        return;\r
+\r
+                    this.structuralPath = new ResourceArray(diagramOrComposite);\r
+                    diagram =  g.getPossibleObject(definedBy, mr.CompositeToDiagram);\r
+                       }\r
+                       \r
+               } else {\r
+                       \r
+                       Resource possibleSymbol = g.getPossibleObject(diagram, sr.Defines);\r
+                       if(possibleSymbol != null && g.isInstanceOf(possibleSymbol, DIA.ElementClass)) isSymbol = true;\r
+                       \r
+               }\r
+               \r
+                       this.resource = diagram;\r
+               \r
+        } catch (ManyObjectsForFunctionalRelationException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (ServiceException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (NoSingleResultException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+\r
+    protected CopyPasteStrategy getCopyPasteStrategy() {\r
+               try {\r
+                       CopyPasteStrategy cpStrategy = Simantics.getSession().syncRequest(new PossibleAdapter<CopyPasteStrategy>(resource, CopyPasteStrategy.class));\r
+                       if(cpStrategy != null) return cpStrategy;\r
+               } catch (DatabaseException e) {\r
+               }\r
+               return new DefaultCopyPasteStrategy();\r
+    }\r
+    \r
+    protected CopyAdvisor getCopyAdvisor() {\r
+               try {\r
+                       CopyAdvisor advisor = Simantics.getSession().syncRequest(new PossibleAdapter<CopyAdvisor>(resource, CopyAdvisor.class));\r
+                       if(advisor != null) return advisor;\r
+               } catch (DatabaseException e) {\r
+               }\r
+               return new MappedElementCopyAdvisor(new ElementCopyAdvisor(), new ComponentCopyAdvisor());\r
+    }\r
+    
+    private void initContext(CanvasContext ctx) {\r
+        boolean unlock = false;\r
+        if (!ctx.isLocked()) {
+            ctx.setLocked(true);\r
+            unlock = true;\r
+        }\r
+\r
+        IHintContext h = ctx.getDefaultHintContext();
+
+        // Support & Util Participants
+        ctx.add( new TransformUtil() );
+        ctx.add( new MouseUtil() );
+        ctx.add( new KeyUtil() );
+        ctx.add( new CanvasGrab() );
+        ctx.add( new SymbolUtil() );
+        ctx.add( new TimeParticipant() );
+        ctx.add( new CanvasBoundsParticipant() );
+        ctx.add( new Notifications() );
+
+        // SGFocusParticipant does not work for remote viewer at the moment.
+        //ctx.add( new SGFocusParticipant() );
+
+        h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
+\r
+        ctx.add( new PanZoomRotateHandler(navigation == null || navigation == true) );
+        ctx.add( new MultitouchPanZoomRotateInteractor() );
+        ctx.add( new ZoomToAreaHandler() );
+        ctx.add( new SimpleElementTransformHandler() );
+        \r
+        // Key bindings
+        if(navigation == null || navigation == true)
+            ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );
+
+        // Grid & Ruler & Background
+        h.setHint(RulerPainter.KEY_RULER_ENABLED, false);
+        h.setHint(GridPainter.KEY_GRID_ENABLED, false);
+
+        ctx.add( new GridPainter() );
+        ctx.add( new RulerPainter() );
+        ctx.add( new BackgroundPainter() );\r
+        
+        h.setHint(Hints.KEY_DISPLAY_PAGE, Boolean.FALSE);\r
+        h.setHint(Hints.KEY_DISPLAY_MARGINS, Boolean.TRUE);\r
+        ctx.add( new PageBorderParticipant() );
+\r
+        h.setHint(Hints.KEY_GRID_COLOR, new Color(0.95f, 0.95f, 0.95f));
+        h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.WHITE);
+        h.setHint(RulerPainter.KEY_RULER_BACKGROUND_COLOR, new Color(0.9f, 0.9f, 0.9f, 0.75f));
+        h.setHint(RulerPainter.KEY_RULER_TEXT_COLOR, Color.BLACK);
+
+        ////// Diagram Participants //////
+        ctx.add( new PointerInteractor(false, false, false, false, true, true, synchronizer.getElementClassProvider(), null) );
+        ctx.add( new ElementInteractor() );
+        ctx.add( new Selection() );
+        ctx.add( new DiagramParticipant() );
+        ctx.add( new ElementPainter(false) );
+
+        //ctx.add( new ElementHeartbeater() );
+        ctx.add( new ZOrderHandler() );
+        ctx.add( new ZoomTransitionParticipant(TransitionFunction.SIGMOID) );
+
+        /////// D'n'D ///////
+        ctx.add(new PopulateElementDropParticipant(synchronizer));
+        ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));
+
+        h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
+
+        h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 1000.0);
+        h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);
+
+        // Add visual browsing capabilities for structural models
+        ISessionContext sessionContext = Simantics.getSessionContext();
+        ctx.add(new HeadlessStructuralBrowsingHandler(this, sessionContext, structuralPath));
+
+        // Page settings
+        PageDesc pageDesc = PageDesc.DEFAULT.withOrientation(PageOrientation.Landscape);
+        // TODO: load page desc from graph
+        h.setHint(Hints.KEY_PAGE_DESC, pageDesc);
+\r
+        ctx.add(new CopyPasteHandler(getCopyPasteStrategy()));\r
+        ctx.add(new DeleteHandler(null));\r
+\r
+        if (resource != null)\r
+            loadPageSettings(ctx, resource);\r
+\r
+        ctx.assertParticipantDependencies();\r
+        if (unlock)
+            ctx.setLocked(false);\r
+    }
+\r
+    protected void loadPageSettings(ICanvasContext ctx, Resource diagramResource) {\r
+        try {\r
+            DiagramDesc diagramDesc = Simantics.getSession().syncRequest(DiagramRequests.getDiagramDesc(diagramResource));\r
+            if (diagramDesc != null)\r
+                setDiagramDesc(ctx, diagramDesc);\r
+        } catch (DatabaseException e) {\r
+            ErrorLogger.defaultLogError(e);\r
+        }\r
+    }\r
+\r
+    protected void setDiagramDesc(ICanvasContext ctx, DiagramDesc diagramDesc) {\r
+        IHintContext hints = ctx.getDefaultHintContext();\r
+        hints.setHint(Hints.KEY_PAGE_DESC, diagramDesc.getPageDesc());\r
+        //hints.setHint(Hints.KEY_DISPLAY_PAGE, diagramDesc.isPageBordersVisible());\r
+        hints.setHint(Hints.KEY_DISPLAY_MARGINS, diagramDesc.isMarginsVisible());\r
+    }\r
+
+    @Override
+    public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg) {
+        return initializeSceneGraph(sg, null);
+    }
+
+    @Override\r
+    public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String view) {\r
+        return initializeSceneGraph(sg, "", "", view);\r
+    }\r
+\r
+    @Override\r
+    public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String modelURI, String RVI) {\r
+        return initializeSceneGraph(sg, modelURI, RVI, "");\r
+    }\r
+\r
+    @Override\r
+    public G2DSceneGraph initializeSceneGraph(ICanvasContext context, String modelURI, String RVI) {\r
+        G2DSceneGraph sg = context.getSceneGraph();\r
+        return initializeSceneGraph(context, sg, modelURI, RVI, "");\r
+    }\r
+
+    /**\r
+     * @param sg\r
+     * @param view\r
+     * @param initialHints\r
+     * @return\r
+     */\r
+    private G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String modelURI, String RVI, String view) {\r
+        IThreadWorkQueue thread = AWTThread.getThreadAccess();\r
+        ctx = new CanvasContext(thread, sg); // By giving the scene graph instance as parameter, we can use external serializer\r
+        return initializeSceneGraph(ctx, sg, modelURI, RVI, view);\r
+    }\r
+\r
+    /**
+     * @param sg
+     * @param view
+     * @param initialHints
+     * @return
+     */
+    private G2DSceneGraph initializeSceneGraph(ICanvasContext context, G2DSceneGraph sg, String modelURI, String RVI, String view) {\r
+        this.ctx = (CanvasContext) context;\r
+        this.view = view;
+        if(view != null) {
+            //System.out.println("using layer '"+view+"'");
+            initialHints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { view });
+        }
+\r
+        try {\r
+\r
+            IModelingRules modelingRules = Simantics.getSession().syncRequest(DiagramRequests.getModelingRules(resource, null));\r
+            if (modelingRules != null) {\r
+                initialHints.setHint(DiagramModelHints.KEY_MODELING_RULES, modelingRules);\r
+            }\r
+            \r
+            initialHints.setHint(SynchronizationHints.COPY_ADVISOR, getCopyAdvisor());\r
+            
+            final RuntimeDiagramManager runtimeDiagramManager = RuntimeDiagramManager.create(Simantics.getSession(), resource, modelURI, RVI);\r
+            \r
+            synchronizer = Simantics.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {
+                @Override
+                public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {
+                    DiagramResource dr = DiagramResource.getInstance(graph);
+                    Boolean val = graph.getPossibleRelatedValue(resource, dr.NavigationEnabled, Bindings.BOOLEAN);
+                    if(val != null && navigation == null) { // Set only if navigation has not been set manually
+                        navigation = val;
+                    }
+                    GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx,\r
+                            ElementClassProviders.mappedProvider(
+                                    ElementClasses.CONNECTION, DefaultConnectionClassFactory.CLASS.newClassWith(new StaticObjectAdapter(dr.Connection)),
+                                    ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)
+                            )
+                    );
+                    sync.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));
+                    diagram = sync.loadDiagram(new NullProgressMonitor(), graph, null, resource, runtimeDiagramManager.getRuntimeDiagram(), structuralPath, initialHints); // FIXME
+                    return sync;
+                }
+            });\r
+            
+        } catch (DatabaseException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);\r
+\r
+        initContext(ctx);\r
+\r
+        return ctx.getSceneGraph();\r
+    }\r
+
+    @Override\r
+    public void dispose() {
+        if(ctx != null) {\r
+            if (ownsContext)
+                ctx.dispose();
+            ctx = null;
+        }
+        if (synchronizer != null) {\r
+            synchronizer.dispose();
+            synchronizer = null;
+        }
+        if (diagram != null) {\r
+            diagram.dispose();
+            diagram = null;
+        }
+    }
+
+    /**
+     * Hack for returning canvasContext for some special cases
+     * this method brakes the interface, but this is not intended to be used in production context
+     * @return
+     */
+    @Override\r
+    public ICanvasContext getCanvasContext() {
+        return ctx;
+    }
+
+    @Override
+    public AWTEventListener getEventListener() {
+        if(ctx == null) return null;
+        if(listener == null) {
+            listener = new AWTRemoteEventAdapter(ctx, ctx.getEventQueue());
+        }
+        return listener;
+    }
+
+    @Override
+    public void updateDiagram(final ResourceArray structuralPath) {
+        final IHintContext hints = new HintContext();
+        if(view != null) {
+            System.out.println("using layer '"+view+"'");
+            hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { view });
+        }
+
+        try {
+            // FIXME: I have no idea if this works or not..
+            diagram = SimanticsUI.getSession().syncRequest(new Read<IDiagram>() {
+                @Override
+                public IDiagram perform(ReadGraph graph) throws DatabaseException {
+                    IDiagram d = synchronizer.loadDiagram(new NullProgressMonitor(), graph, null, structuralPath.resources[0], null, structuralPath.removeFromBeginning(0), hints);
+                    return d;
+                }
+            });
+            ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);
+        } catch (DatabaseException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+\r
+    public void setExperiment(ReadGraph g, String identifier) {\r
+        if(diagram == null) return;\r
+        diagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, identifier);\r
+        initialHints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, identifier);\r
+\r
+//             try {\r
+//                     DiagramExperiment.setActiveExperiment(g, diagram, (String)identifier);\r
+//             } catch (DatabaseException e) {\r
+//                     // TODO Auto-generated catch block\r
+//                     e.printStackTrace();\r
+//             }\r
+\r
+    }\r
+
+    /**
+     * Supported keys:
+     *     DiagramModelHints.KEY_SESSION_ID
+     *     DiagramHints.KEY_NAVIGATION_ENABLED
+     */
+    @Override
+    public void setHint(Object key, Object value) {\r
+        if(DiagramModelHints.KEY_SESSION_ID.equals(key)) {\r
+            if(diagram != null)\r
+                diagram.setHint(DiagramModelHints.KEY_SESSION_ID, value);\r
+            initialHints.setHint(DiagramModelHints.KEY_SESSION_ID, value);\r
+        } else if(DiagramModelHints.KEY_ACTIVE_EXPERIMENT.equals(key)) {\r
+            if(diagram != null)
+                diagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, value);
+            initialHints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, value);\r
+        } else if(DiagramHints.KEY_NAVIGATION_ENABLED.equals(key)) {
+            navigation = (Boolean)value;
+        }
+    }
+}