]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/WikiDiagramViewer.java
Configurable connection crossing styles
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / WikiDiagramViewer.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.diagramEditor;
13
14 import java.awt.Color;
15 import java.awt.datatransfer.Transferable;
16 import java.awt.datatransfer.UnsupportedFlavorException;
17 import java.io.IOException;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.NullProgressMonitor;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.ui.IEditorInput;
23 import org.eclipse.ui.IEditorSite;
24 import org.eclipse.ui.PartInitException;
25 import org.eclipse.ui.contexts.IContextActivation;
26 import org.eclipse.ui.contexts.IContextService;
27 import org.eclipse.ui.part.EditorPart;
28 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
29 import org.simantics.Simantics;
30 import org.simantics.db.ReadGraph;
31 import org.simantics.db.Session;
32 import org.simantics.db.common.ResourceArray;
33 import org.simantics.db.exception.DatabaseException;
34 import org.simantics.db.management.ISessionContext;
35 import org.simantics.db.management.ISessionContextProvider;
36 import org.simantics.db.request.Read;
37 import org.simantics.db.service.SerialisationSupport;
38 import org.simantics.diagram.adapter.DefaultConnectionClassFactory;
39 import org.simantics.diagram.adapter.FlagClassFactory;
40 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
41 import org.simantics.diagram.handler.SimpleElementTransformHandler;
42 import org.simantics.diagram.layer.ILayersViewPage;
43 import org.simantics.diagram.query.DiagramRequests;
44 import org.simantics.diagram.stubs.DiagramResource;
45 import org.simantics.diagram.ui.DiagramModelHints;
46 import org.simantics.g2d.canvas.Hints;
47 import org.simantics.g2d.canvas.ICanvasContext;
48 import org.simantics.g2d.canvas.impl.CanvasContext;
49 import org.simantics.g2d.diagram.DiagramHints;
50 import org.simantics.g2d.diagram.IDiagram;
51 import org.simantics.g2d.diagram.participant.DiagramParticipant;
52 import org.simantics.g2d.diagram.participant.ElementInteractor;
53 import org.simantics.g2d.diagram.participant.ElementPainter;
54 import org.simantics.g2d.diagram.participant.Selection;
55 import org.simantics.g2d.diagram.participant.TerminalPainter;
56 import org.simantics.g2d.diagram.participant.ZOrderHandler;
57 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
58 import org.simantics.g2d.element.ElementClassProviders;
59 import org.simantics.g2d.element.ElementClasses;
60 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
61 import org.simantics.g2d.multileveldiagram.TransitionFunction;
62 import org.simantics.g2d.multileveldiagram.ZoomTransitionParticipant;
63 import org.simantics.g2d.participant.BackgroundPainter;
64 import org.simantics.g2d.participant.CanvasBoundsParticipant;
65 import org.simantics.g2d.participant.CanvasGrab;
66 import org.simantics.g2d.participant.GridPainter;
67 import org.simantics.g2d.participant.KeyToCommand;
68 import org.simantics.g2d.participant.KeyUtil;
69 import org.simantics.g2d.participant.MouseUtil;
70 import org.simantics.g2d.participant.MultitouchPanZoomRotateInteractor;
71 import org.simantics.g2d.participant.Notifications;
72 import org.simantics.g2d.participant.PageBorderParticipant;
73 import org.simantics.g2d.participant.PanZoomRotateHandler;
74 import org.simantics.g2d.participant.PointerPainter;
75 import org.simantics.g2d.participant.RulerPainter;
76 import org.simantics.g2d.participant.SymbolUtil;
77 import org.simantics.g2d.participant.TimeParticipant;
78 import org.simantics.g2d.participant.TransformUtil;
79 import org.simantics.g2d.participant.ZoomToAreaHandler;
80 import org.simantics.g2d.utils.CanvasUtils;
81 import org.simantics.layer0.utils.triggers.IActivation;
82 import org.simantics.modeling.ModelingResources;
83 import org.simantics.modeling.mapping.ModelingSynchronizationHints;
84 import org.simantics.scenegraph.g2d.events.command.CommandKeyBinding;
85 import org.simantics.scenegraph.g2d.events.command.Commands;
86 import org.simantics.simulation.experiment.IExperiment;
87 import org.simantics.ui.dnd.ResourceTransferData;
88 import org.simantics.ui.dnd.ResourceTransferUtils;
89 import org.simantics.ui.workbench.IResourceEditorInput;
90 import org.simantics.ui.workbench.IResourceEditorInput2;
91 import org.simantics.ui.workbench.IResourceEditorPart2;
92 import org.simantics.ui.workbench.ResourceEditorSupport;
93 import org.simantics.utils.datastructures.hints.HintContext;
94 import org.simantics.utils.datastructures.hints.IHintContext;
95 import org.simantics.utils.page.PageDesc;
96 import org.simantics.utils.page.PageOrientation;
97 import org.simantics.utils.threads.AWTThread;
98 import org.simantics.utils.threads.IThreadWorkQueue;
99
100 /**
101  * @author J-P Laine
102  */
103 public class WikiDiagramViewer extends EditorPart implements IResourceEditorPart2 {
104
105     protected boolean                  disposed = false;
106     protected IDiagram                 sourceDiagram;
107     protected ICanvasContext           canvasContext;
108     protected ResourceEditorSupport    support;
109     protected ISessionContextProvider  sessionContextProvider;
110     protected ISessionContext          sessionContext;
111     protected GraphToDiagramSynchronizer synchronizer;
112     protected IActivation              activation;
113     protected ResourceArray            structuralPath = new ResourceArray();
114     protected IContextActivation       contextActivation;
115     protected IExperiment              experiment;
116     protected String                               layer = null;
117
118     public WikiDiagramViewer() {
119     }
120
121     protected void addDropParticipants(ICanvasContext ctx) {
122         // FIXME This is a workaround so that this participant can be disabled
123         // for SymbolViewer
124         ctx.add(new PopulateElementDropParticipant(synchronizer));
125         ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));
126     }
127
128     protected void addKeyBindingParticipants(CanvasContext ctx) {
129         ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );
130     }
131
132     public void setExperiment(IExperiment experiment) {
133         sourceDiagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);
134     }
135
136     public void init(ResourceArray structuralPath, String layer, IExperiment experiment) {
137         this.experiment = experiment;
138         this.layer = layer;
139         this.structuralPath = structuralPath;
140
141         sessionContextProvider = Simantics.getSessionContextProvider();
142         sessionContext = sessionContextProvider.getSessionContext();
143
144         canvasContext = createViewerCanvas();
145
146         try {
147             sourceDiagram = loadDiagram(structuralPath, experiment);
148         } catch (DatabaseException e) {
149             e.printStackTrace();
150         }
151         onCreated();
152     }
153
154     public void updateDiagram(ResourceArray structuralPath) {
155         canvasContext = createViewerCanvas();
156         try {
157             IHintContext hints = new HintContext();
158             hints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);
159             if(layer != null) {
160                 System.out.println("using layer '"+layer+"'"); //$NON-NLS-1$ //$NON-NLS-2$
161                 hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { layer });
162             }
163
164             sourceDiagram = sessionContext.getSession().syncRequest(DiagramRequests.loadDiagram(new NullProgressMonitor(), getResourceInput2().getModel(null), structuralPath.resources[0], null, structuralPath.removeFromBeginning(0), synchronizer, hints));
165             canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, sourceDiagram);
166         } catch (DatabaseException e) {
167             e.printStackTrace();
168         }
169     }
170
171     void scheduleZoomToFit() {
172         if (sourceDiagram == null)
173             throw new IllegalStateException("source diagram is null"); //$NON-NLS-1$
174
175         sourceDiagram.setHint(Hints.KEY_DISABLE_PAINTING, Boolean.TRUE);
176         sourceDiagram.setHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT, Boolean.TRUE);
177
178         // zoom-to-fit
179         sourceDiagram.removeHint(Hints.KEY_DISABLE_PAINTING);
180         Boolean zoomToFit = sourceDiagram.removeHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT);
181         if (zoomToFit != null && zoomToFit)
182             CanvasUtils.sendCommand(canvasContext, Commands.ZOOM_TO_FIT);
183         canvasContext.getContentContext().setDirty();
184     }
185
186     protected IDiagram loadDiagram(ResourceArray structuralPath, IExperiment experiment) throws DatabaseException {
187         IHintContext hints = new HintContext();
188         if(experiment != null)
189             hints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);
190         if(layer != null) {
191             System.out.println("using layer '"+layer+"'"); //$NON-NLS-1$ //$NON-NLS-2$
192             hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { layer });
193         }
194         IDiagram d = sessionContext.getSession().syncRequest(DiagramRequests.loadDiagram(new NullProgressMonitor(), getResourceInput2().getModel(null), structuralPath.resources[0], null, structuralPath.removeFromBeginning(0), synchronizer, hints));
195         canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, d);
196         return d;
197     }
198
199     protected GraphToDiagramSynchronizer createSynchronizer(final ICanvasContext ctx, final ISessionContext sessionContext) {
200         try {
201             return sessionContext.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {
202                 @Override
203                 public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {
204                     DiagramResource dr = DiagramResource.getInstance(graph);
205                     GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx,
206                             ElementClassProviders.mappedProvider(
207                                     ElementClasses.CONNECTION, DefaultConnectionClassFactory.CLASS.newClassWith(new StaticObjectAdapter(dr.Connection)),
208                                     ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)
209                             )
210                     );
211                     sync.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));
212                     return sync;
213                 }
214             });
215         } catch (DatabaseException e) {
216             throw new UnsupportedOperationException("Failed to initialize data model synchronizer", e); //$NON-NLS-1$
217         }
218     }
219
220     public ICanvasContext createViewerCanvas()
221     {
222         IThreadWorkQueue thread = AWTThread.getThreadAccess();
223         CanvasContext ctx = new CanvasContext(thread);
224         IHintContext h = ctx.getDefaultHintContext();
225
226         this.synchronizer = createSynchronizer(ctx, sessionContext);
227
228         canvasContext.add( new PanZoomRotateHandler() ); // Must be before TransformUtil
229
230         // Support & Util Participants
231         ctx.add( new TransformUtil() );
232         ctx.add( new MouseUtil() );
233         ctx.add( new KeyUtil() );
234         ctx.add( new CanvasGrab() );
235         ctx.add( new SymbolUtil() );
236         ctx.add( new TimeParticipant() );
237         ctx.add( new CanvasBoundsParticipant() );
238         ctx.add( new Notifications() );
239
240 //        ctx.add( new SGFocusParticipant(c) ); // FIXME: Get chassis from somewhere
241
242         h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
243
244         ctx.add( new MultitouchPanZoomRotateInteractor() );
245         ctx.add( new ZoomToAreaHandler() );
246         ctx.add( new SimpleElementTransformHandler() );
247
248         // Key bindings
249         addKeyBindingParticipants(ctx);
250
251         // Grid & Ruler & Background
252
253         ctx.add( new GridPainter() );
254         ctx.add( new RulerPainter() );
255         ctx.add( new BackgroundPainter() );
256         ctx.add( new PageBorderParticipant() );
257
258         h.setHint(Hints.KEY_GRID_COLOR, new Color(0.95f, 0.95f, 0.95f));
259         h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.WHITE);
260         h.setHint(RulerPainter.KEY_RULER_BACKGROUND_COLOR, new Color(0.9f, 0.9f, 0.9f, 0.75f));
261         h.setHint(RulerPainter.KEY_RULER_TEXT_COLOR, Color.BLACK);
262
263         ////// Diagram Participants //////
264         ctx.add(new PointerInteractor(true, true, true, false, true, false, synchronizer.getElementClassProvider(), null));
265         ctx.add(new ElementInteractor());
266         ctx.add(new Selection());
267         ctx.add(new DiagramParticipant());
268         ctx.add(new ElementPainter());
269         ctx.add(new TerminalPainter(true, true, false, true));
270         //ctx.add(new ElementHeartbeater());
271         ctx.add(new ZOrderHandler());
272         ctx.add(new ZoomTransitionParticipant(TransitionFunction.SIGMOID));
273
274         /////// D'n'D ///////
275         addDropParticipants(ctx);
276
277         h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
278
279         h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 1000.0);
280         h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);
281
282         // Add visual browsing capabilities for structural models
283 //        ctx.add(new HeadlessStructuralBrowsingHandler(this, sessionContext, structuralPath));
284
285         // Page settings
286         PageDesc pageDesc = PageDesc.DEFAULT.withOrientation(PageOrientation.Landscape);
287         // TODO: load page desc from graph
288         h.setHint(Hints.KEY_PAGE_DESC, pageDesc);
289
290         ctx.assertParticipantDependencies();
291
292         return ctx;
293     }
294
295     private boolean firstFocus = true;
296
297     @Override
298     public void setFocus() {
299         if (firstFocus) {
300             // This is a workaround for using the symbol viewer in multi-page
301             // editors which causes the first zoom-to-fit scheduling to happen
302             // already before the controls have been laid out properly.
303             firstFocus = false;
304             firstTimeSetFocus();
305         }
306     }
307
308     protected void firstTimeSetFocus() {
309         scheduleZoomToFit();
310     }
311
312     @Override
313     public void dispose() {
314         System.out.println("RemoteDiagramViewer.dispose()"); //$NON-NLS-1$
315         if(getSite() != null) {
316             IContextService contextService = (IContextService) getSite().getService(IContextService.class);
317             contextService.deactivateContext(contextActivation);
318         }
319
320         disposed = true;
321         if (activation != null) {
322             activation.deactivate();
323             activation = null;
324         }
325
326         if(synchronizer != null) {
327             synchronizer.dispose();
328             synchronizer = null;
329         }
330
331         if(sourceDiagram != null) {
332             sourceDiagram.dispose();
333             sourceDiagram = null;
334         }
335
336         if(support != null) {
337             support.dispose();
338             support = null;
339         }
340         super.dispose();
341     }
342
343     @Override
344     public void doSave(IProgressMonitor monitor) {
345     }
346
347     @Override
348     public void doSaveAs() {
349     }
350
351     @Override
352     public void init(IEditorSite site, IEditorInput input)
353     throws PartInitException {
354         if (!(input instanceof IResourceEditorInput))
355             throw new PartInitException("Invalid input: must be IResourceEditorInput"); //$NON-NLS-1$
356         setSite(site);
357         setInput(input);
358         support = new ResourceEditorSupport(this);
359
360         // Set initial part name according to the name given by IEditorInput
361         setPartName(getEditorInput().getName());
362     }
363
364     @Override
365     public boolean isDirty() {
366         return false;
367     }
368
369     @Override
370     public boolean isSaveAsAllowed() {
371         return false;
372     }
373
374     public static ResourceArray[] decodeToResources(Session session, Transferable tr)
375     {
376         try {
377             SerialisationSupport support = session.getService(SerialisationSupport.class);
378             ResourceTransferData data = ResourceTransferUtils.readAwtTransferable(support, tr);
379             if ("property".equals(data.getPurpose())) //$NON-NLS-1$
380                 return data.toResourceArrayArray();
381         } catch (UnsupportedFlavorException e) {
382             throw new RuntimeException(e);
383         } catch (IOException e) {
384             throw new RuntimeException(e);
385         } catch (IllegalArgumentException e) {
386             throw new RuntimeException(e);
387         } catch (DatabaseException e) {
388             throw new RuntimeException(e);
389         }
390         return null;
391     }
392
393     @SuppressWarnings("rawtypes")
394     @Override
395     public Object getAdapter(Class adapter) {
396         if (adapter == IContentOutlinePage.class)
397             return new DiagramOutlinePage(sessionContextProvider, getResourceInput2());
398         if (adapter == ILayersViewPage.class)
399             return new DiagramLayersPage(sourceDiagram, canvasContext);
400         if (adapter == ICanvasContext.class)
401             return canvasContext;
402         if (adapter == IDiagram.class)
403             return sourceDiagram;
404         if (adapter == Session.class)
405             return sessionContext.getSession();
406         return super.getAdapter(adapter);
407     }
408
409     public ICanvasContext getCanvasContext() {
410         return canvasContext;
411     }
412
413     protected void onCreated() {
414     }
415
416     @Override
417     public void createPartControl(Composite parent) {
418         // TODO Auto-generated method stub
419
420     }
421
422     @Override
423     public IResourceEditorInput2 getResourceInput2() {
424         // TODO Auto-generated method stub
425         return null;
426     }
427
428     @Override
429     public IResourceEditorInput getResourceInput() {
430         // TODO Auto-generated method stub
431         return null;
432     }
433
434 }