1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling.ui.sg;
14 import java.awt.Color;
\r
15 import java.awt.event.AWTEventListener;
\r
17 import org.eclipse.core.runtime.NullProgressMonitor;
\r
18 import org.simantics.Simantics;
\r
19 import org.simantics.databoard.Bindings;
\r
20 import org.simantics.db.ReadGraph;
\r
21 import org.simantics.db.Resource;
\r
22 import org.simantics.db.common.ResourceArray;
\r
23 import org.simantics.db.common.primitiverequest.PossibleAdapter;
\r
24 import org.simantics.db.exception.DatabaseException;
\r
25 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
\r
26 import org.simantics.db.exception.NoSingleResultException;
\r
27 import org.simantics.db.exception.ServiceException;
\r
28 import org.simantics.db.management.ISessionContext;
\r
29 import org.simantics.db.request.Read;
\r
30 import org.simantics.diagram.adapter.DefaultConnectionClassFactory;
\r
31 import org.simantics.diagram.adapter.FlagClassFactory;
\r
32 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
\r
33 import org.simantics.diagram.handler.CopyPasteHandler;
\r
34 import org.simantics.diagram.handler.CopyPasteStrategy;
\r
35 import org.simantics.diagram.handler.DefaultCopyPasteStrategy;
\r
36 import org.simantics.diagram.handler.DeleteHandler;
\r
37 import org.simantics.diagram.handler.SimpleElementTransformHandler;
\r
38 import org.simantics.diagram.query.DiagramRequests;
\r
39 import org.simantics.diagram.runtime.RuntimeDiagramManager;
\r
40 import org.simantics.diagram.stubs.DiagramResource;
\r
41 import org.simantics.diagram.synchronization.CopyAdvisor;
\r
42 import org.simantics.diagram.synchronization.SynchronizationHints;
\r
43 import org.simantics.diagram.ui.DiagramModelHints;
\r
44 import org.simantics.g2d.canvas.Hints;
\r
45 import org.simantics.g2d.canvas.ICanvasContext;
\r
46 import org.simantics.g2d.canvas.impl.CanvasContext;
\r
47 import org.simantics.g2d.diagram.DiagramHints;
\r
48 import org.simantics.g2d.diagram.IDiagram;
\r
49 import org.simantics.g2d.diagram.participant.DiagramParticipant;
\r
50 import org.simantics.g2d.diagram.participant.ElementInteractor;
\r
51 import org.simantics.g2d.diagram.participant.ElementPainter;
\r
52 import org.simantics.g2d.diagram.participant.Selection;
\r
53 import org.simantics.g2d.diagram.participant.ZOrderHandler;
\r
54 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
\r
55 import org.simantics.g2d.element.ElementClassProviders;
\r
56 import org.simantics.g2d.element.ElementClasses;
\r
57 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
\r
58 import org.simantics.g2d.multileveldiagram.TransitionFunction;
\r
59 import org.simantics.g2d.multileveldiagram.ZoomTransitionParticipant;
\r
60 import org.simantics.g2d.page.DiagramDesc;
\r
61 import org.simantics.g2d.participant.BackgroundPainter;
\r
62 import org.simantics.g2d.participant.CanvasBoundsParticipant;
\r
63 import org.simantics.g2d.participant.CanvasGrab;
\r
64 import org.simantics.g2d.participant.GridPainter;
\r
65 import org.simantics.g2d.participant.KeyToCommand;
\r
66 import org.simantics.g2d.participant.KeyUtil;
\r
67 import org.simantics.g2d.participant.MouseUtil;
\r
68 import org.simantics.g2d.participant.MultitouchPanZoomRotateInteractor;
\r
69 import org.simantics.g2d.participant.Notifications;
\r
70 import org.simantics.g2d.participant.PageBorderParticipant;
\r
71 import org.simantics.g2d.participant.PanZoomRotateHandler;
\r
72 import org.simantics.g2d.participant.PointerPainter;
\r
73 import org.simantics.g2d.participant.RulerPainter;
\r
74 import org.simantics.g2d.participant.SymbolUtil;
\r
75 import org.simantics.g2d.participant.TimeParticipant;
\r
76 import org.simantics.g2d.participant.TransformUtil;
\r
77 import org.simantics.g2d.participant.ZoomToAreaHandler;
\r
78 import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider;
\r
79 import org.simantics.modeling.ModelingResources;
\r
80 import org.simantics.modeling.mapping.ComponentCopyAdvisor;
\r
81 import org.simantics.modeling.mapping.ElementCopyAdvisor;
\r
82 import org.simantics.modeling.mapping.MappedElementCopyAdvisor;
\r
83 import org.simantics.modeling.mapping.ModelingSynchronizationHints;
\r
84 import org.simantics.modeling.ui.diagramEditor.PopulateElementDropParticipant;
\r
85 import org.simantics.modeling.ui.diagramEditor.PopulateElementMonitorDropParticipant;
\r
86 import org.simantics.modeling.ui.diagramEditor.handlers.HeadlessStructuralBrowsingHandler;
\r
87 import org.simantics.modeling.ui.diagramEditor.handlers.HeadlessStructuralBrowsingHandler.IDiagramUpdateSupport;
\r
88 import org.simantics.scenegraph.g2d.G2DSceneGraph;
\r
89 import org.simantics.scenegraph.g2d.events.adapter.AWTRemoteEventAdapter;
\r
90 import org.simantics.scenegraph.g2d.events.command.CommandKeyBinding;
\r
91 import org.simantics.structural.stubs.StructuralResource2;
\r
92 import org.simantics.structural2.modelingRules.IModelingRules;
\r
93 import org.simantics.ui.SimanticsUI;
\r
94 import org.simantics.utils.datastructures.hints.HintContext;
\r
95 import org.simantics.utils.datastructures.hints.IHintContext;
\r
96 import org.simantics.utils.page.PageDesc;
\r
97 import org.simantics.utils.page.PageOrientation;
\r
98 import org.simantics.utils.threads.AWTThread;
\r
99 import org.simantics.utils.threads.IThreadWorkQueue;
\r
100 import org.simantics.utils.ui.ErrorLogger;
\r
104 * ISceneGraphProvider implementation for diagrams.
105 * TODO: decide if this should be stateless or stateful class
110 public class DiagramSceneGraphProvider implements ICanvasSceneGraphProvider, IDiagramUpdateSupport {
112 protected boolean isSymbol = false;
113 protected Resource resource;
114 protected ResourceArray structuralPath = null;
115 protected IDiagram diagram = null;
116 protected CanvasContext ctx = null;
\r
117 protected boolean ownsContext = false;
118 protected GraphToDiagramSynchronizer synchronizer = null;
119 protected String view = null;
120 protected Boolean navigation = null;
122 protected AWTRemoteEventAdapter listener = null;
124 final IHintContext initialHints = new HintContext();
\r
126 public DiagramSceneGraphProvider(ReadGraph g, final Resource diagramOrComposite) {
\r
127 this.structuralPath = new ResourceArray();
130 StructuralResource2 sr = StructuralResource2.getInstance(g);
\r
131 DiagramResource DIA = DiagramResource.getInstance(g);
\r
133 Resource diagram = diagramOrComposite;
\r
134 if(!g.isInstanceOf(diagram, DIA.Composite)) {
\r
136 ModelingResources mr = ModelingResources.getInstance(g);
\r
137 diagram = g.getPossibleObject(diagramOrComposite, mr.CompositeToDiagram);
\r
138 if(diagram == null) {
\r
139 // looks like we have a component without direct relation to composite.. try to solve this
\r
140 // FIXME: use adapter to get composite directly from resource
\r
141 final Resource type = g.getSingleType(diagramOrComposite, sr.Component);
\r
145 final Resource definedBy = g.getPossibleObject(type, sr.IsDefinedBy);
\r
146 if (definedBy == null)
\r
149 this.structuralPath = new ResourceArray(diagramOrComposite);
\r
150 diagram = g.getPossibleObject(definedBy, mr.CompositeToDiagram);
\r
155 Resource possibleSymbol = g.getPossibleObject(diagram, sr.Defines);
\r
156 if(possibleSymbol != null && g.isInstanceOf(possibleSymbol, DIA.ElementClass)) isSymbol = true;
\r
160 this.resource = diagram;
\r
162 } catch (ManyObjectsForFunctionalRelationException e) {
163 // TODO Auto-generated catch block
165 } catch (ServiceException e) {
166 // TODO Auto-generated catch block
168 } catch (NoSingleResultException e) {
169 // TODO Auto-generated catch block
174 protected CopyPasteStrategy getCopyPasteStrategy() {
\r
176 CopyPasteStrategy cpStrategy = Simantics.getSession().syncRequest(new PossibleAdapter<CopyPasteStrategy>(resource, CopyPasteStrategy.class));
\r
177 if(cpStrategy != null) return cpStrategy;
\r
178 } catch (DatabaseException e) {
\r
180 return new DefaultCopyPasteStrategy();
\r
183 protected CopyAdvisor getCopyAdvisor() {
\r
185 CopyAdvisor advisor = Simantics.getSession().syncRequest(new PossibleAdapter<CopyAdvisor>(resource, CopyAdvisor.class));
\r
186 if(advisor != null) return advisor;
\r
187 } catch (DatabaseException e) {
\r
189 return new MappedElementCopyAdvisor(new ElementCopyAdvisor(), new ComponentCopyAdvisor());
\r
192 private void initContext(CanvasContext ctx) {
\r
193 boolean unlock = false;
\r
194 if (!ctx.isLocked()) {
195 ctx.setLocked(true);
\r
199 IHintContext h = ctx.getDefaultHintContext();
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() );
211 // SGFocusParticipant does not work for remote viewer at the moment.
212 //ctx.add( new SGFocusParticipant() );
214 h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
216 ctx.add( new PanZoomRotateHandler(navigation == null || navigation == true) );
217 ctx.add( new MultitouchPanZoomRotateInteractor() );
218 ctx.add( new ZoomToAreaHandler() );
219 ctx.add( new SimpleElementTransformHandler() );
222 if(navigation == null || navigation == true)
223 ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );
225 // Grid & Ruler & Background
226 h.setHint(RulerPainter.KEY_RULER_ENABLED, false);
227 h.setHint(GridPainter.KEY_GRID_ENABLED, false);
229 ctx.add( new GridPainter() );
230 ctx.add( new RulerPainter() );
231 ctx.add( new BackgroundPainter() );
\r
233 h.setHint(Hints.KEY_DISPLAY_PAGE, Boolean.FALSE);
\r
234 h.setHint(Hints.KEY_DISPLAY_MARGINS, Boolean.TRUE);
\r
235 ctx.add( new PageBorderParticipant() );
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);
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) );
249 //ctx.add( new ElementHeartbeater() );
250 ctx.add( new ZOrderHandler() );
251 ctx.add( new ZoomTransitionParticipant(TransitionFunction.SIGMOID) );
253 /////// D'n'D ///////
254 ctx.add(new PopulateElementDropParticipant(synchronizer));
255 ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));
257 h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
259 h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 1000.0);
260 h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);
262 // Add visual browsing capabilities for structural models
263 ISessionContext sessionContext = Simantics.getSessionContext();
264 ctx.add(new HeadlessStructuralBrowsingHandler(this, sessionContext, structuralPath));
267 PageDesc pageDesc = PageDesc.DEFAULT.withOrientation(PageOrientation.Landscape);
268 // TODO: load page desc from graph
269 h.setHint(Hints.KEY_PAGE_DESC, pageDesc);
271 ctx.add(new CopyPasteHandler(getCopyPasteStrategy()));
\r
272 ctx.add(new DeleteHandler(null));
\r
274 if (resource != null)
\r
275 loadPageSettings(ctx, resource);
\r
277 ctx.assertParticipantDependencies();
\r
279 ctx.setLocked(false);
\r
282 protected void loadPageSettings(ICanvasContext ctx, Resource diagramResource) {
\r
284 DiagramDesc diagramDesc = Simantics.getSession().syncRequest(DiagramRequests.getDiagramDesc(diagramResource));
\r
285 if (diagramDesc != null)
\r
286 setDiagramDesc(ctx, diagramDesc);
\r
287 } catch (DatabaseException e) {
\r
288 ErrorLogger.defaultLogError(e);
\r
292 protected void setDiagramDesc(ICanvasContext ctx, DiagramDesc diagramDesc) {
\r
293 IHintContext hints = ctx.getDefaultHintContext();
\r
294 hints.setHint(Hints.KEY_PAGE_DESC, diagramDesc.getPageDesc());
\r
295 //hints.setHint(Hints.KEY_DISPLAY_PAGE, diagramDesc.isPageBordersVisible());
\r
296 hints.setHint(Hints.KEY_DISPLAY_MARGINS, diagramDesc.isMarginsVisible());
\r
300 public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg) {
301 return initializeSceneGraph(sg, null);
305 public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String view) {
\r
306 return initializeSceneGraph(sg, "", "", view);
\r
310 public G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String modelURI, String RVI) {
\r
311 return initializeSceneGraph(sg, modelURI, RVI, "");
\r
315 public G2DSceneGraph initializeSceneGraph(ICanvasContext context, String modelURI, String RVI) {
\r
316 G2DSceneGraph sg = context.getSceneGraph();
\r
317 return initializeSceneGraph(context, sg, modelURI, RVI, "");
\r
323 * @param initialHints
\r
326 private G2DSceneGraph initializeSceneGraph(G2DSceneGraph sg, String modelURI, String RVI, String view) {
\r
327 IThreadWorkQueue thread = AWTThread.getThreadAccess();
\r
328 ctx = new CanvasContext(thread, sg); // By giving the scene graph instance as parameter, we can use external serializer
\r
329 return initializeSceneGraph(ctx, sg, modelURI, RVI, view);
\r
335 * @param initialHints
338 private G2DSceneGraph initializeSceneGraph(ICanvasContext context, G2DSceneGraph sg, String modelURI, String RVI, String view) {
\r
339 this.ctx = (CanvasContext) context;
\r
342 //System.out.println("using layer '"+view+"'");
343 initialHints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { view });
348 IModelingRules modelingRules = Simantics.getSession().syncRequest(DiagramRequests.getModelingRules(resource, null));
\r
349 if (modelingRules != null) {
\r
350 initialHints.setHint(DiagramModelHints.KEY_MODELING_RULES, modelingRules);
\r
353 initialHints.setHint(SynchronizationHints.COPY_ADVISOR, getCopyAdvisor());
\r
355 final RuntimeDiagramManager runtimeDiagramManager = RuntimeDiagramManager.create(Simantics.getSession(), resource, modelURI, RVI);
\r
357 synchronizer = Simantics.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {
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
365 GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx,
\r
366 ElementClassProviders.mappedProvider(
367 ElementClasses.CONNECTION, DefaultConnectionClassFactory.CLASS.newClassWith(new StaticObjectAdapter(dr.Connection)),
368 ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)
371 sync.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));
372 diagram = sync.loadDiagram(new NullProgressMonitor(), graph, null, resource, runtimeDiagramManager.getRuntimeDiagram(), structuralPath, initialHints); // FIXME
377 } catch (DatabaseException e) {
378 // TODO Auto-generated catch block
381 ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);
\r
385 return ctx.getSceneGraph();
\r
389 public void dispose() {
395 if (synchronizer != null) {
\r
396 synchronizer.dispose();
399 if (diagram != null) {
\r
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
411 public ICanvasContext getCanvasContext() {
416 public AWTEventListener getEventListener() {
417 if(ctx == null) return null;
418 if(listener == null) {
419 listener = new AWTRemoteEventAdapter(ctx, ctx.getEventQueue());
425 public void updateDiagram(final ResourceArray structuralPath) {
426 final IHintContext hints = new HintContext();
428 System.out.println("using layer '"+view+"'");
429 hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { view });
433 // FIXME: I have no idea if this works or not..
434 diagram = SimanticsUI.getSession().syncRequest(new Read<IDiagram>() {
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);
441 ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);
442 } catch (DatabaseException e) {
443 // TODO Auto-generated catch block
448 public void setExperiment(ReadGraph g, String identifier) {
\r
449 if(diagram == null) return;
\r
450 diagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, identifier);
\r
451 initialHints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, identifier);
\r
454 // DiagramExperiment.setActiveExperiment(g, diagram, (String)identifier);
\r
455 // } catch (DatabaseException e) {
\r
456 // // TODO Auto-generated catch block
\r
457 // e.printStackTrace();
\r
464 * DiagramModelHints.KEY_SESSION_ID
465 * DiagramHints.KEY_NAVIGATION_ENABLED
468 public void setHint(Object key, Object value) {
\r
469 if(DiagramModelHints.KEY_SESSION_ID.equals(key)) {
\r
470 if(diagram != null)
\r
471 diagram.setHint(DiagramModelHints.KEY_SESSION_ID, value);
\r
472 initialHints.setHint(DiagramModelHints.KEY_SESSION_ID, value);
\r
473 } else if(DiagramModelHints.KEY_ACTIVE_EXPERIMENT.equals(key)) {
\r
475 diagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, value);
476 initialHints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, value);
\r
477 } else if(DiagramHints.KEY_NAVIGATION_ENABLED.equals(key)) {
478 navigation = (Boolean)value;