]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sg/DiagramSceneGraphProvider.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / sg / DiagramSceneGraphProvider.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.modeling.ui.sg;
13
14 import java.awt.Color;
15 import java.awt.event.AWTEventListener;
16
17 import org.eclipse.core.runtime.NullProgressMonitor;
18 import org.simantics.Simantics;
19 import org.simantics.databoard.Bindings;
20 import org.simantics.db.ReadGraph;
21 import org.simantics.db.Resource;
22 import org.simantics.db.common.ResourceArray;
23 import org.simantics.db.common.primitiverequest.PossibleAdapter;
24 import org.simantics.db.exception.DatabaseException;
25 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
26 import org.simantics.db.exception.NoSingleResultException;
27 import org.simantics.db.exception.ServiceException;
28 import org.simantics.db.management.ISessionContext;
29 import org.simantics.db.request.Read;
30 import org.simantics.diagram.adapter.DefaultConnectionClassFactory;
31 import org.simantics.diagram.adapter.FlagClassFactory;
32 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
33 import org.simantics.diagram.handler.CopyPasteHandler;
34 import org.simantics.diagram.handler.CopyPasteStrategy;
35 import org.simantics.diagram.handler.DefaultCopyPasteStrategy;
36 import org.simantics.diagram.handler.DeleteHandler;
37 import org.simantics.diagram.handler.SimpleElementTransformHandler;
38 import org.simantics.diagram.query.DiagramRequests;
39 import org.simantics.diagram.runtime.RuntimeDiagramManager;
40 import org.simantics.diagram.stubs.DiagramResource;
41 import org.simantics.diagram.synchronization.CopyAdvisor;
42 import org.simantics.diagram.synchronization.SynchronizationHints;
43 import org.simantics.diagram.ui.DiagramModelHints;
44 import org.simantics.g2d.canvas.Hints;
45 import org.simantics.g2d.canvas.ICanvasContext;
46 import org.simantics.g2d.canvas.impl.CanvasContext;
47 import org.simantics.g2d.diagram.DiagramHints;
48 import org.simantics.g2d.diagram.IDiagram;
49 import org.simantics.g2d.diagram.participant.DiagramParticipant;
50 import org.simantics.g2d.diagram.participant.ElementInteractor;
51 import org.simantics.g2d.diagram.participant.ElementPainter;
52 import org.simantics.g2d.diagram.participant.Selection;
53 import org.simantics.g2d.diagram.participant.ZOrderHandler;
54 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
55 import org.simantics.g2d.element.ElementClassProviders;
56 import org.simantics.g2d.element.ElementClasses;
57 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
58 import org.simantics.g2d.multileveldiagram.TransitionFunction;
59 import org.simantics.g2d.multileveldiagram.ZoomTransitionParticipant;
60 import org.simantics.g2d.page.DiagramDesc;
61 import org.simantics.g2d.participant.BackgroundPainter;
62 import org.simantics.g2d.participant.CanvasBoundsParticipant;
63 import org.simantics.g2d.participant.CanvasGrab;
64 import org.simantics.g2d.participant.GridPainter;
65 import org.simantics.g2d.participant.KeyToCommand;
66 import org.simantics.g2d.participant.KeyUtil;
67 import org.simantics.g2d.participant.MouseUtil;
68 import org.simantics.g2d.participant.MultitouchPanZoomRotateInteractor;
69 import org.simantics.g2d.participant.Notifications;
70 import org.simantics.g2d.participant.PageBorderParticipant;
71 import org.simantics.g2d.participant.PanZoomRotateHandler;
72 import org.simantics.g2d.participant.PointerPainter;
73 import org.simantics.g2d.participant.RulerPainter;
74 import org.simantics.g2d.participant.SymbolUtil;
75 import org.simantics.g2d.participant.TimeParticipant;
76 import org.simantics.g2d.participant.TransformUtil;
77 import org.simantics.g2d.participant.ZoomToAreaHandler;
78 import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider;
79 import org.simantics.modeling.ModelingResources;
80 import org.simantics.modeling.mapping.ComponentCopyAdvisor;
81 import org.simantics.modeling.mapping.ElementCopyAdvisor;
82 import org.simantics.modeling.mapping.MappedElementCopyAdvisor;
83 import org.simantics.modeling.mapping.ModelingSynchronizationHints;
84 import org.simantics.modeling.ui.diagramEditor.PopulateElementDropParticipant;
85 import org.simantics.modeling.ui.diagramEditor.PopulateElementMonitorDropParticipant;
86 import org.simantics.modeling.ui.diagramEditor.handlers.HeadlessStructuralBrowsingHandler;
87 import org.simantics.modeling.ui.diagramEditor.handlers.HeadlessStructuralBrowsingHandler.IDiagramUpdateSupport;
88 import org.simantics.scenegraph.g2d.G2DSceneGraph;
89 import org.simantics.scenegraph.g2d.events.adapter.AWTRemoteEventAdapter;
90 import org.simantics.scenegraph.g2d.events.command.CommandKeyBinding;
91 import org.simantics.structural.stubs.StructuralResource2;
92 import org.simantics.structural2.modelingRules.IModelingRules;
93 import org.simantics.ui.SimanticsUI;
94 import org.simantics.utils.datastructures.hints.HintContext;
95 import org.simantics.utils.datastructures.hints.IHintContext;
96 import org.simantics.utils.page.PageDesc;
97 import org.simantics.utils.page.PageOrientation;
98 import org.simantics.utils.threads.AWTThread;
99 import org.simantics.utils.threads.IThreadWorkQueue;
100 import org.simantics.utils.ui.ErrorLogger;
101
102
103 /**
104  * ISceneGraphProvider implementation for diagrams.
105  * TODO: decide if this should be stateless or stateful class
106  * 
107  * @author J-P Laine
108  *
109  */
110 public class DiagramSceneGraphProvider implements ICanvasSceneGraphProvider, IDiagramUpdateSupport {
111
112         protected boolean isSymbol = false;
113     protected Resource resource;
114     protected ResourceArray structuralPath = null;
115     protected IDiagram diagram = null;
116     protected CanvasContext ctx = null;
117     protected boolean ownsContext = false;
118     protected GraphToDiagramSynchronizer synchronizer = null;
119     protected String view = null;
120     protected Boolean navigation = null;
121
122     protected AWTRemoteEventAdapter listener = null;
123
124     final IHintContext initialHints = new HintContext();
125
126     public DiagramSceneGraphProvider(ReadGraph g, final Resource diagramOrComposite) {
127         this.structuralPath = new ResourceArray();
128         try {
129
130             StructuralResource2 sr = StructuralResource2.getInstance(g);
131                 DiagramResource DIA = DiagramResource.getInstance(g);
132                 
133                 Resource diagram = diagramOrComposite;
134                 if(!g.isInstanceOf(diagram, DIA.Composite)) {
135                         
136                 ModelingResources mr = ModelingResources.getInstance(g);
137                         diagram = g.getPossibleObject(diagramOrComposite, mr.CompositeToDiagram);
138                         if(diagram == null) {
139                     // looks like we have a component without direct relation to composite.. try to solve this
140                     // FIXME: use adapter to get composite directly from resource
141                     final Resource type = g.getSingleType(diagramOrComposite, sr.Component);
142                     if (type == null)
143                         return;
144
145                     final Resource definedBy = g.getPossibleObject(type, sr.IsDefinedBy);
146                     if (definedBy == null)
147                         return;
148
149                     this.structuralPath = new ResourceArray(diagramOrComposite);
150                     diagram =  g.getPossibleObject(definedBy, mr.CompositeToDiagram);
151                         }
152                         
153                 } else {
154                         
155                         Resource possibleSymbol = g.getPossibleObject(diagram, sr.Defines);
156                         if(possibleSymbol != null && g.isInstanceOf(possibleSymbol, DIA.ElementClass)) isSymbol = true;
157                         
158                 }
159                 
160                         this.resource = diagram;
161                 
162         } catch (ManyObjectsForFunctionalRelationException e) {
163             // TODO Auto-generated catch block
164             e.printStackTrace();
165         } catch (ServiceException e) {
166             // TODO Auto-generated catch block
167             e.printStackTrace();
168         } catch (NoSingleResultException e) {
169             // TODO Auto-generated catch block
170             e.printStackTrace();
171         }
172     }
173
174     protected CopyPasteStrategy getCopyPasteStrategy() {
175                 try {
176                         CopyPasteStrategy cpStrategy = Simantics.getSession().syncRequest(new PossibleAdapter<CopyPasteStrategy>(resource, CopyPasteStrategy.class));
177                         if(cpStrategy != null) return cpStrategy;
178                 } catch (DatabaseException e) {
179                 }
180                 return new DefaultCopyPasteStrategy();
181     }
182     
183     protected CopyAdvisor getCopyAdvisor() {
184                 try {
185                         CopyAdvisor advisor = Simantics.getSession().syncRequest(new PossibleAdapter<CopyAdvisor>(resource, CopyAdvisor.class));
186                         if(advisor != null) return advisor;
187                 } catch (DatabaseException e) {
188                 }
189                 return new MappedElementCopyAdvisor(new ElementCopyAdvisor(), new ComponentCopyAdvisor());
190     }
191     
192     private void initContext(CanvasContext ctx) {
193         boolean unlock = false;
194         if (!ctx.isLocked()) {
195             ctx.setLocked(true);
196             unlock = true;
197         }
198
199         IHintContext h = ctx.getDefaultHintContext();
200
201         // Support & Util Participants
202         ctx.add( new TransformUtil() );
203         ctx.add( new MouseUtil() );
204         ctx.add( new KeyUtil() );
205         ctx.add( new CanvasGrab() );
206         ctx.add( new SymbolUtil() );
207         ctx.add( new TimeParticipant() );
208         ctx.add( new CanvasBoundsParticipant() );
209         ctx.add( new Notifications() );
210
211         // SGFocusParticipant does not work for remote viewer at the moment.
212         //ctx.add( new SGFocusParticipant() );
213
214         h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
215
216         ctx.add( new PanZoomRotateHandler(navigation == null || navigation == true) );
217         ctx.add( new MultitouchPanZoomRotateInteractor() );
218         ctx.add( new ZoomToAreaHandler() );
219         ctx.add( new SimpleElementTransformHandler() );
220         
221         // Key bindings
222         if(navigation == null || navigation == true)
223             ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );
224
225         // Grid & Ruler & Background
226         h.setHint(RulerPainter.KEY_RULER_ENABLED, false);
227         h.setHint(GridPainter.KEY_GRID_ENABLED, false);
228
229         ctx.add( new GridPainter() );
230         ctx.add( new RulerPainter() );
231         ctx.add( new BackgroundPainter() );
232         
233         h.setHint(Hints.KEY_DISPLAY_PAGE, Boolean.FALSE);
234         h.setHint(Hints.KEY_DISPLAY_MARGINS, Boolean.TRUE);
235         ctx.add( new PageBorderParticipant() );
236
237         h.setHint(Hints.KEY_GRID_COLOR, new Color(0.95f, 0.95f, 0.95f));
238         h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.WHITE);
239         h.setHint(RulerPainter.KEY_RULER_BACKGROUND_COLOR, new Color(0.9f, 0.9f, 0.9f, 0.75f));
240         h.setHint(RulerPainter.KEY_RULER_TEXT_COLOR, Color.BLACK);
241
242         ////// Diagram Participants //////
243         ctx.add( new PointerInteractor(false, false, false, false, true, true, synchronizer.getElementClassProvider(), null) );
244         ctx.add( new ElementInteractor() );
245         ctx.add( new Selection() );
246         ctx.add( new DiagramParticipant() );
247         ctx.add( new ElementPainter(false) );
248
249         //ctx.add( new ElementHeartbeater() );
250         ctx.add( new ZOrderHandler() );
251         ctx.add( new ZoomTransitionParticipant(TransitionFunction.SIGMOID) );
252
253         /////// D'n'D ///////
254         ctx.add(new PopulateElementDropParticipant(synchronizer));
255         ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));
256
257         h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
258
259         h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 1000.0);
260         h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);
261
262         // Add visual browsing capabilities for structural models
263         ISessionContext sessionContext = Simantics.getSessionContext();
264         ctx.add(new HeadlessStructuralBrowsingHandler(this, sessionContext, structuralPath));
265
266         // Page settings
267         PageDesc pageDesc = PageDesc.DEFAULT.withOrientation(PageOrientation.Landscape);
268         // TODO: load page desc from graph
269         h.setHint(Hints.KEY_PAGE_DESC, pageDesc);
270
271         ctx.add(new CopyPasteHandler(getCopyPasteStrategy()));
272         ctx.add(new DeleteHandler(null));
273
274         if (resource != null)
275             loadPageSettings(ctx, resource);
276
277         ctx.assertParticipantDependencies();
278         if (unlock)
279             ctx.setLocked(false);
280     }
281
282     protected void loadPageSettings(ICanvasContext ctx, Resource diagramResource) {
283         try {
284             DiagramDesc diagramDesc = Simantics.getSession().syncRequest(DiagramRequests.getDiagramDesc(diagramResource));
285             if (diagramDesc != null)
286                 setDiagramDesc(ctx, diagramDesc);
287         } catch (DatabaseException e) {
288             ErrorLogger.defaultLogError(e);
289         }
290     }
291
292     protected void setDiagramDesc(ICanvasContext ctx, DiagramDesc diagramDesc) {
293         IHintContext hints = ctx.getDefaultHintContext();
294         hints.setHint(Hints.KEY_PAGE_DESC, diagramDesc.getPageDesc());
295         //hints.setHint(Hints.KEY_DISPLAY_PAGE, diagramDesc.isPageBordersVisible());
296         hints.setHint(Hints.KEY_DISPLAY_MARGINS, diagramDesc.isMarginsVisible());
297     }
298
299     @Override
300     public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg) {
301         return initializeSceneGraph(sg, null);
302     }
303
304     @Override
305     public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String view) {
306         return initializeSceneGraph(sg, "", "", view);
307     }
308
309     @Override
310     public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String modelURI, String RVI) {
311         return initializeSceneGraph(sg, modelURI, RVI, "");
312     }
313
314     @Override
315     public G2DSceneGraph initializeSceneGraph(ICanvasContext context, String modelURI, String RVI) {
316         G2DSceneGraph sg = context.getSceneGraph();
317         return initializeSceneGraph(context, sg, modelURI, RVI, "");
318     }
319
320     /**
321      * @param sg
322      * @param view
323      * @param initialHints
324      * @return
325      */
326     private G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String modelURI, String RVI, String view) {
327         IThreadWorkQueue thread = AWTThread.getThreadAccess();
328         ctx = new CanvasContext(thread, sg); // By giving the scene graph instance as parameter, we can use external serializer
329         return initializeSceneGraph(ctx, sg, modelURI, RVI, view);
330     }
331
332     /**
333      * @param sg
334      * @param view
335      * @param initialHints
336      * @return
337      */
338     private G2DSceneGraph initializeSceneGraph(ICanvasContext context, G2DSceneGraph sg, String modelURI, String RVI, String view) {
339         this.ctx = (CanvasContext) context;
340         this.view = view;
341         if(view != null) {
342             //System.out.println("using layer '"+view+"'");
343             initialHints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { view });
344         }
345
346         try {
347
348             IModelingRules modelingRules = Simantics.getSession().syncRequest(DiagramRequests.getModelingRules(resource, null));
349             if (modelingRules != null) {
350                 initialHints.setHint(DiagramModelHints.KEY_MODELING_RULES, modelingRules);
351             }
352             
353             initialHints.setHint(SynchronizationHints.COPY_ADVISOR, getCopyAdvisor());
354             
355             final RuntimeDiagramManager runtimeDiagramManager = RuntimeDiagramManager.create(Simantics.getSession(), resource, modelURI, RVI);
356             
357             synchronizer = Simantics.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {
358                 @Override
359                 public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {
360                     DiagramResource dr = DiagramResource.getInstance(graph);
361                     Boolean val = graph.getPossibleRelatedValue(resource, dr.NavigationEnabled, Bindings.BOOLEAN);
362                     if(val != null && navigation == null) { // Set only if navigation has not been set manually
363                         navigation = val;
364                     }
365                     GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx,
366                             ElementClassProviders.mappedProvider(
367                                     ElementClasses.CONNECTION, DefaultConnectionClassFactory.CLASS.newClassWith(new StaticObjectAdapter(dr.Connection)),
368                                     ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)
369                             )
370                     );
371                     sync.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));
372                     diagram = sync.loadDiagram(new NullProgressMonitor(), graph, null, resource, runtimeDiagramManager.getRuntimeDiagram(), structuralPath, initialHints); // FIXME
373                     return sync;
374                 }
375             });
376             
377         } catch (DatabaseException e) {
378             // TODO Auto-generated catch block
379             e.printStackTrace();
380         }
381         ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);
382
383         initContext(ctx);
384
385         return ctx.getSceneGraph();
386     }
387
388     @Override
389     public void dispose() {
390         if(ctx != null) {
391             if (ownsContext)
392                 ctx.dispose();
393             ctx = null;
394         }
395         if (synchronizer != null) {
396             synchronizer.dispose();
397             synchronizer = null;
398         }
399         if (diagram != null) {
400             diagram.dispose();
401             diagram = null;
402         }
403     }
404
405     /**
406      * Hack for returning canvasContext for some special cases
407      * this method brakes the interface, but this is not intended to be used in production context
408      * @return
409      */
410     @Override
411     public ICanvasContext getCanvasContext() {
412         return ctx;
413     }
414
415     @Override
416     public AWTEventListener getEventListener() {
417         if(ctx == null) return null;
418         if(listener == null) {
419             listener = new AWTRemoteEventAdapter(ctx, ctx.getEventQueue());
420         }
421         return listener;
422     }
423
424     @Override
425     public void updateDiagram(final ResourceArray structuralPath) {
426         final IHintContext hints = new HintContext();
427         if(view != null) {
428             System.out.println("using layer '"+view+"'");
429             hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { view });
430         }
431
432         try {
433             // FIXME: I have no idea if this works or not..
434             diagram = SimanticsUI.getSession().syncRequest(new Read<IDiagram>() {
435                 @Override
436                 public IDiagram perform(ReadGraph graph) throws DatabaseException {
437                     IDiagram d = synchronizer.loadDiagram(new NullProgressMonitor(), graph, null, structuralPath.resources[0], null, structuralPath.removeFromBeginning(0), hints);
438                     return d;
439                 }
440             });
441             ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);
442         } catch (DatabaseException e) {
443             // TODO Auto-generated catch block
444             e.printStackTrace();
445         }
446     }
447
448     public void setExperiment(ReadGraph g, String identifier) {
449         if(diagram == null) return;
450         diagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, identifier);
451         initialHints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, identifier);
452
453 //              try {
454 //                      DiagramExperiment.setActiveExperiment(g, diagram, (String)identifier);
455 //              } catch (DatabaseException e) {
456 //                      // TODO Auto-generated catch block
457 //                      e.printStackTrace();
458 //              }
459
460     }
461
462     /**
463      * Supported keys:
464      *     DiagramModelHints.KEY_SESSION_ID
465      *     DiagramHints.KEY_NAVIGATION_ENABLED
466      */
467     @Override
468     public void setHint(Object key, Object value) {
469         if(DiagramModelHints.KEY_SESSION_ID.equals(key)) {
470             if(diagram != null)
471                 diagram.setHint(DiagramModelHints.KEY_SESSION_ID, value);
472             initialHints.setHint(DiagramModelHints.KEY_SESSION_ID, value);
473         } else if(DiagramModelHints.KEY_ACTIVE_EXPERIMENT.equals(key)) {
474             if(diagram != null)
475                 diagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, value);
476             initialHints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, value);
477         } else if(DiagramHints.KEY_NAVIGATION_ENABLED.equals(key)) {
478             navigation = (Boolean)value;
479         }
480     }
481 }