]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/SheetViewer.java
Combination of Simantics-platform related changes and fixes for district
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / SheetViewer.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2013 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  *     Semantum Oy - issue #4384
12  *******************************************************************************/
13 package org.simantics.modeling.ui.diagramEditor;
14
15 import java.awt.Color;
16 import java.lang.reflect.InvocationTargetException;
17 import java.util.function.Supplier;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.SubMonitor;
21 import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
22 import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
23 import org.eclipse.jface.action.IStatusLineManager;
24 import org.eclipse.jface.operation.IRunnableWithProgress;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.ui.IEditorInput;
27 import org.eclipse.ui.IEditorSite;
28 import org.eclipse.ui.PartInitException;
29 import org.eclipse.ui.PlatformUI;
30 import org.eclipse.ui.contexts.IContextService;
31 import org.eclipse.ui.part.EditorPart;
32 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
33 import org.simantics.db.ReadGraph;
34 import org.simantics.db.Resource;
35 import org.simantics.db.Session;
36 import org.simantics.db.common.ResourceArray;
37 import org.simantics.db.exception.DatabaseException;
38 import org.simantics.db.management.ISessionContext;
39 import org.simantics.db.management.ISessionContextProvider;
40 import org.simantics.db.request.Read;
41 import org.simantics.diagram.adapter.DefaultConnectionClassFactory;
42 import org.simantics.diagram.adapter.FlagClassFactory;
43 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
44 import org.simantics.diagram.handler.ConnectionCommandHandler;
45 import org.simantics.diagram.handler.CopyPasteHandler;
46 import org.simantics.diagram.handler.DeleteHandler;
47 import org.simantics.diagram.handler.ExpandSelectionHandler;
48 import org.simantics.diagram.handler.SimpleElementTransformHandler;
49 import org.simantics.diagram.layer.ILayersViewPage;
50 import org.simantics.diagram.participant.ContextUtil;
51 import org.simantics.diagram.participant.SGFocusParticipant;
52 import org.simantics.diagram.query.DiagramRequests;
53 import org.simantics.diagram.stubs.DiagramResource;
54 import org.simantics.diagram.synchronization.IModifiableSynchronizationContext;
55 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
56 import org.simantics.diagram.ui.SWTPopupMenuParticipant;
57 import org.simantics.g2d.canvas.Hints;
58 import org.simantics.g2d.canvas.ICanvasContext;
59 import org.simantics.g2d.canvas.impl.CanvasContext;
60 import org.simantics.g2d.chassis.SWTChassis;
61 import org.simantics.g2d.diagram.DiagramClass;
62 import org.simantics.g2d.diagram.DiagramHints;
63 import org.simantics.g2d.diagram.IDiagram;
64 import org.simantics.g2d.diagram.impl.Diagram;
65 import org.simantics.g2d.diagram.participant.DiagramParticipant;
66 import org.simantics.g2d.diagram.participant.ElementInteractor;
67 import org.simantics.g2d.diagram.participant.ElementPainter;
68 import org.simantics.g2d.diagram.participant.Selection;
69 import org.simantics.g2d.diagram.participant.TerminalPainter;
70 import org.simantics.g2d.diagram.participant.ZOrderHandler;
71 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
72 import org.simantics.g2d.element.ElementClassProviders;
73 import org.simantics.g2d.element.ElementClasses;
74 import org.simantics.g2d.element.IElementClassProvider;
75 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
76 import org.simantics.g2d.participant.CanvasBoundsParticipant;
77 import org.simantics.g2d.participant.CanvasGrab;
78 import org.simantics.g2d.participant.KeyUtil;
79 import org.simantics.g2d.participant.MouseUtil;
80 import org.simantics.g2d.participant.MultitouchPanZoomRotateInteractor;
81 import org.simantics.g2d.participant.Notifications;
82 import org.simantics.g2d.participant.PageBorderParticipant;
83 import org.simantics.g2d.participant.PanZoomRotateHandler;
84 import org.simantics.g2d.participant.PointerPainter;
85 import org.simantics.g2d.participant.RulerPainter;
86 import org.simantics.g2d.participant.SymbolUtil;
87 import org.simantics.g2d.participant.TimeParticipant;
88 import org.simantics.g2d.participant.TransformUtil;
89 import org.simantics.g2d.participant.ZoomToAreaHandler;
90 import org.simantics.layer0.utils.triggers.IActivation;
91 import org.simantics.layer0.utils.triggers.IActivationManager;
92 import org.simantics.modeling.ModelingResources;
93 import org.simantics.modeling.mapping.ModelingSynchronizationHints;
94 import org.simantics.modeling.ui.diagramEditor.handlers.WorkbenchStructuralSelectionProvider;
95 import org.simantics.modeling.ui.preferences.DiagramPreferenceUtil;
96 import org.simantics.modeling.ui.preferences.DiagramPreferences;
97 import org.simantics.scenegraph.INode;
98 import org.simantics.scenegraph.g2d.snap.GridSnapAdvisor;
99 import org.simantics.scenegraph.utils.NodeUtil;
100 import org.simantics.selectionview.StandardPropertyPage;
101 import org.simantics.ui.SimanticsUI;
102 import org.simantics.ui.workbench.IPropertyPage;
103 import org.simantics.ui.workbench.IResourceEditorInput;
104 import org.simantics.ui.workbench.IResourceEditorInput2;
105 import org.simantics.ui.workbench.IResourceEditorPart2;
106 import org.simantics.ui.workbench.ResourceEditorSupport;
107 import org.simantics.ui.workbench.TitleRequest;
108 import org.simantics.ui.workbench.TitleUpdater;
109 import org.simantics.ui.workbench.ToolTipRequest;
110 import org.simantics.utils.DataContainer;
111 import org.simantics.utils.datastructures.hints.IHintContext;
112 import org.simantics.utils.page.PageDesc;
113 import org.simantics.utils.threads.AWTThread;
114 import org.simantics.utils.threads.IThreadWorkQueue;
115 import org.simantics.utils.threads.SWTThread;
116 import org.simantics.utils.threads.ThreadUtils;
117 import org.simantics.utils.ui.ErrorLogger;
118
119 /**
120  * @author Toni Kalajainen
121  * @author Tuukka Lehtonen
122  */
123 public class SheetViewer extends EditorPart implements IResourceEditorPart2 {
124
125     private static final boolean         PROFILE            = false;
126
127     protected boolean                    disposed           = false;
128     protected IThreadWorkQueue           swt;
129     protected IStatusLineManager         statusLineManager;
130     protected SWTChassis                 c;
131     protected IDiagram                   sourceDiagram;
132     protected ICanvasContext             canvasContext;
133     protected ResourceEditorSupport      support;
134     protected ISessionContextProvider    sessionContextProvider;
135     protected ISessionContext            sessionContext;
136     protected Resource                   diagramResource;
137     protected GraphToDiagramSynchronizer synchronizer;
138     protected IActivation                activation;
139     protected ContextUtil                contextUtil;
140
141     protected DiagramPreferences         diagramPreferences;
142     protected GridSnapAdvisor            snapAdvisor;
143
144     public ResourceArray                 structuralPath;
145
146     IPreferenceChangeListener preferenceListener = new IPreferenceChangeListener() {
147         @Override
148         public void preferenceChange(PreferenceChangeEvent event) {
149             String value = (String) event.getNewValue();
150             if (DiagramPreferences.P_SNAP_GRID_SIZE.equals(event.getKey())) {
151                 double grid = DiagramPreferences.DEFAULT_SNAP_GRID_SIZE;
152                 if (value != null)
153                     grid = Double.parseDouble(value);
154                 snapAdvisor.setResolution(grid);
155             } else if (DiagramPreferences.P_DEFAULT_PAGE_SIZE.equals(event.getKey())) {
156                 PageDesc pageDesc = PageDesc.deserialize(value, DiagramPreferences.DEFAULT_PAGE_SIZE);
157                 //System.out.println("new page desc: " + pageDesc);
158                 canvasContext.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, pageDesc);
159             } else if (DiagramPreferences.P_DISPLAY_PAGE_SIZE.equals(event.getKey())) {
160                 Boolean display = value != null ? Boolean.parseBoolean(value) : DiagramPreferences.DEFAULT_DISPLAY_PAGE_SIZE;
161                 canvasContext.getDefaultHintContext().setHint(Hints.KEY_DISPLAY_PAGE, display);
162             } else if (DiagramPreferences.P_DISPLAY_MARGINS.equals(event.getKey())) {
163                 Boolean display = value != null ? Boolean.parseBoolean(value) : DiagramPreferences.DEFAULT_DISPLAY_MARGINS;
164                 canvasContext.getDefaultHintContext().setHint(Hints.KEY_DISPLAY_MARGINS, display);
165             }
166         }
167     };
168
169     protected void addDropParticipants(ICanvasContext ctx) {
170         // FIXME This is a workaround so that this participant can be disabled
171         // for SymbolViewer
172         ctx.add(new PopulateElementDropParticipant(synchronizer));
173         ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));
174     }
175
176     protected void addKeyBindingParticipants(CanvasContext ctx) {
177         //ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );
178         ctx.add(new DeleteHandler(statusLineManager));
179         ctx.add(new CopyPasteHandler(statusLineManager));
180         ctx.add(new ConnectionCommandHandler());
181     }
182
183     protected void addPopupmenu(ICanvasContext ctx) {
184         ctx.add(new SWTPopupMenuParticipant(getSite(), c, getPopupId()));
185     }
186
187     protected void addStructureParticipants(ICanvasContext ctx) {
188         structuralPath = getResourceInput().getResourceArray().removeFromBeginning(1);
189
190         ctx.add(new WorkbenchStructuralSelectionProvider(swt, getSite(), structuralPath));
191         // Add visual browsing capabilities for structural models
192 //        ctx.add(new StructuralBrowsingHandler(getSite(), sessionContext, structuralPath));
193 //        ctx.add(new LinkBrowsingHandler(getSite(), this, sessionContext));
194     }
195
196     protected String getPopupId() {
197         return "#ModelingDiagramPopup";
198     }
199
200     protected void getPreferences() {
201         this.diagramPreferences = DiagramPreferenceUtil.getPreferences();
202     }
203
204     protected void initSession() {
205         sessionContextProvider = SimanticsUI.getSessionContextProvider();
206         sessionContext = sessionContextProvider.getSessionContext();
207     }
208
209     protected void readNames() {
210         String name = getEditorInput().getName();
211         setPartName(name);
212         setTitleToolTip(name);
213     }
214
215     protected void createChassis(Composite parent) {
216         c = new SWTChassis(parent, 0);
217         c.syncPopulate();
218     }
219
220     protected void setCanvasContext(ICanvasContext context) {
221         c.setCanvasContext(canvasContext);
222     }
223
224     @Override
225     public void createPartControl(Composite parent) {
226         swt = SWTThread.getThreadAccess(parent.getDisplay());
227         statusLineManager = getEditorSite().getActionBars().getStatusLineManager();
228
229         Object task = BEGIN("DV.initSession");
230         initSession();
231         END(task);
232
233         diagramResource = getInputResource();
234         readNames();
235         getPreferences();
236
237         task = BEGIN("DV.createChassis");
238         createChassis(parent);
239         END(task);
240
241         initializeCanvas();
242
243         // Start tracking changes in diagram preferences.
244         diagramPreferences.preferences.addPreferenceChangeListener(preferenceListener);
245     }
246
247     protected void initializeCanvas() {
248         Object canvasInit = BEGIN("DV.canvasInitialization");
249
250         Object task = BEGIN("DV.createViewerCanvas");
251 //        ThreadUtils.syncExec(AWTThread.getThreadAccess(), new Runnable() {
252 //            @Override
253 //            public void run() {
254         canvasContext = createViewerCanvas();
255 //            }
256 //        });
257         END(task);
258
259         //FullscreenUtils.addFullScreenHandler(canvasContext, s, canvasProvider);
260
261         task = BEGIN("DV.setCanvasContext");
262         setCanvasContext(canvasContext);
263         END(task);
264
265         try {
266             task = BEGIN("DV.loadDiagram");
267             sourceDiagram = loadDiagram(diagramResource);
268             END(task);
269
270             // Zoom to fit
271             task = BEGIN("DV.scheduleZoomToFit");
272
273 //            canvasContext.getDefaultHintContext().setHint(Hints.KEY_CANVAS_TRANSFORM, new AffineTransform());
274 //            canvasContext.getContentContext().setDirty();
275             scheduleZoomToFit();
276
277             END(task);
278
279             // Start an activation for the input resource.
280             // This will activate mapping if necessary.
281             task = BEGIN("DV.performActivation");
282             performActivation();
283             END(task);
284
285             task = BEGIN("DV.activate context");
286             contextUtil.activate(DiagramViewer.DIAGRAMMING_CONTEXT);
287             END(task);
288
289             task = BEGIN("DV.onCreated");
290             onCreated();
291             END(task);
292
293         } catch (DatabaseException e) {
294             ErrorLogger.defaultLogError(e);
295
296             // Without this all diagram participants will crash like there's no tomorrow.
297             // Just trying to keep the behavior a bit more sane in case of
298             // errors instead of flooding the console with exceptions.
299             canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, Diagram.spawnNew(DiagramClass.DEFAULT));
300         }
301         END(canvasInit);
302     }
303
304     protected void performActivation() {
305
306         IActivationManager activationManager = sessionContext.getSession().peekService(IActivationManager.class);
307         if (activationManager != null) {
308             activation = activationManager.activate(diagramResource);
309         }
310
311     }
312
313     protected void scheduleZoomToFit() {
314         if (sourceDiagram == null)
315             throw new IllegalStateException("source diagram is null");
316
317         sourceDiagram.setHint(Hints.KEY_DISABLE_PAINTING, Boolean.TRUE);
318         sourceDiagram.setHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT, Boolean.TRUE);
319         ThreadUtils.asyncExec(swt, new Runnable() {
320             @Override
321             public void run() {
322                 if (disposed)
323                     return;
324
325                 // System.out.println("size: " + c.getSize());
326                 ThreadUtils.asyncExec(canvasContext.getThreadAccess(), new Runnable() {
327                     @Override
328                     public void run() {
329                         if (disposed)
330                             return;
331                         // System.out.println("fit diagram to view");
332                         sourceDiagram.removeHint(Hints.KEY_DISABLE_PAINTING);
333                         /*Boolean zoomToFit =*/ sourceDiagram.removeHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT);
334                         canvasContext.getDefaultHintContext().removeHint(Hints.KEY_DISABLE_PAINTING);
335
336 //                        if (Boolean.TRUE.equals(zoomToFit))
337 //                            CanvasUtils.sendCommand(canvasContext, Commands.ZOOM_TO_FIT);
338
339                         canvasContext.getContentContext().setDirty();
340                     }
341                 });
342             }
343         });
344     }
345
346
347
348     protected IDiagram loadDiagram(final Resource r) throws DatabaseException {
349         final DataContainer<IDiagram> dc = new DataContainer<IDiagram>();
350         //dc.set( loadDiagram(new NullProgressMonitor(), r) );
351         try {
352             PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
353                 @Override
354                 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
355                     SubMonitor mon = SubMonitor.convert(monitor, "Loading Diagram", 100);
356                     try {
357                         dc.set( loadDiagram(mon.newChild(100), r) );
358                     } catch (DatabaseException e) {
359                         throw new InvocationTargetException(e);
360                     } finally {
361                         monitor.done();
362                     }
363                 }
364             });
365         } catch (InvocationTargetException e) {
366             Throwable t = e.getTargetException();
367             if (t instanceof DatabaseException)
368                 throw (DatabaseException) t;
369             throw new DatabaseException(t);
370         } catch (InterruptedException e) {
371             throw new DatabaseException(e);
372         }
373         return dc.get();
374     }
375
376     protected IDiagram loadDiagram(IProgressMonitor monitor, Resource r) throws DatabaseException {
377         SubMonitor mon = SubMonitor.convert(monitor, "Loading Diagram", 100);
378
379         Object task = BEGIN("DV.DiagramLoadQuery");
380         IDiagram d = sessionContext.getSession().syncRequest(DiagramRequests.loadDiagram(mon.newChild(100), getResourceInput2().getModel(null), r, null, structuralPath, synchronizer, null));
381         END(task);
382
383         task = BEGIN("DV.setDiagramHint");
384         canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, d);
385         END(task);
386
387         task = BEGIN("DV.set other hints");
388         // Setup a copy advisor for the synchronizer
389         //d.setHint(SynchronizationHints.COPY_ADVISOR, new MappedElementCopyAdvisor(new ComponentCopyAdvisor()));
390         d.setHint(DiagramHints.KEY_USE_CONNECTION_FLAGS, Boolean.FALSE);
391         d.setHint(DiagramHints.KEY_ALLOW_CONNECTION_BRANCHING, Boolean.FALSE);
392         d.setHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS, Boolean.FALSE);
393         END(task);
394
395         return d;
396     }
397
398     protected GraphToDiagramSynchronizer createSynchronizer(final ICanvasContext ctx, final ISessionContext sessionContext) {
399         try {
400             return sessionContext.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {
401                 @Override
402                 public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {
403                     GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx, createElementClassProvider(graph));
404                     initializeSynchronizationContext(graph, sync);
405                     return sync;
406                 }
407             });
408         } catch (DatabaseException e) {
409             throw new UnsupportedOperationException("Failed to initialize data model synchronizer", e);
410         }
411     }
412
413     protected void initializeSynchronizationContext(ReadGraph graph, IModifiableSynchronizationContext context) {
414         context.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));
415     }
416
417     protected IElementClassProvider createElementClassProvider(ReadGraph graph) {
418         DiagramResource dr = DiagramResource.getInstance(graph);
419         return ElementClassProviders.mappedProvider(
420                 ElementClasses.CONNECTION, DefaultConnectionClassFactory.CLASS.newClassWith(new StaticObjectAdapter(dr.Connection)),
421                 ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)
422         );
423     }
424
425     public ICanvasContext createViewerCanvas() {
426         IThreadWorkQueue thread = AWTThread.getThreadAccess();
427         CanvasContext ctx = new CanvasContext(thread);
428         IHintContext h = ctx.getDefaultHintContext();
429
430         Object task = BEGIN("createSynchronizer");
431         this.synchronizer = createSynchronizer(ctx, sessionContext);
432         END(task);
433
434         IContextService contextService = (IContextService) getSite().getService(IContextService.class);
435         contextUtil = new ContextUtil(contextService, swt);
436
437         ctx.add(new PanZoomRotateHandler()); // Must be before TransformUtil
438
439         // Support & Util Participants
440         ctx.add(new TransformUtil());
441         ctx.add(new MouseUtil());
442         ctx.add(new KeyUtil());
443         ctx.add(contextUtil);
444         ctx.add(new CanvasGrab());
445         ctx.add(new SymbolUtil());
446         ctx.add(new TimeParticipant());
447         ctx.add(new CanvasBoundsParticipant());
448         ctx.add(new Notifications());
449
450         ctx.add( new SGFocusParticipant(c, DiagramViewer.DIAGRAMMING_CONTEXT) );
451
452         // Debug participant(s)
453         // ctx.add( new PointerPainter() );
454         // ctx.add( new HandPainter() );
455         h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
456
457         // Pan & Zoom & Rotate
458         ctx.add(new MultitouchPanZoomRotateInteractor());
459         // ctx.add( new OrientationRestorer() );
460         ctx.add(new ZoomToAreaHandler());
461         ctx.add(new SimpleElementTransformHandler(true, true, true));
462         ctx.add(new ExpandSelectionHandler(getEditorSite().getActionBars().getStatusLineManager()));
463
464         // Key bindings
465         addKeyBindingParticipants(ctx);
466
467         // Grid & Ruler & Background
468 //        ctx.add(new GridPainter());
469 //        ctx.add(new RulerPainter());
470 //        ctx.add(new BackgroundPainter());
471
472
473         h.setHint(PanZoomRotateHandler.KEY_ADAPT_VIEWPORT_TO_RESIZED_CONTROL, Boolean.FALSE);
474         h.setHint(Hints.KEY_DISPLAY_PAGE, diagramPreferences.get(DiagramPreferences.P_DISPLAY_PAGE_SIZE));
475         h.setHint(Hints.KEY_DISPLAY_MARGINS, diagramPreferences.get(DiagramPreferences.P_DISPLAY_MARGINS));
476         ctx.add(new PageBorderParticipant());
477
478         // h.setHint(Hints.KEY_GRID_COLOR, new Color(0.9f, 0.9f, 0.9f));
479         // h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.LIGHT_GRAY);
480         h.setHint(Hints.KEY_GRID_COLOR, new Color(0.95f, 0.95f, 0.95f));
481         h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.WHITE);
482         h.setHint(RulerPainter.KEY_RULER_BACKGROUND_COLOR, new Color(0.9f, 0.9f, 0.9f, 0.75f));
483         h.setHint(RulerPainter.KEY_RULER_TEXT_COLOR, Color.BLACK);
484
485         ////// Diagram Participants //////
486         ctx.add(new ZOrderHandler());
487         ctx.add(new PointerInteractor(true, true, true, false, true, false, synchronizer.getElementClassProvider(), null));
488         ctx.add(new ElementInteractor());
489         ctx.add(new Selection());
490         ctx.add(new DiagramParticipant());
491         ctx.add(new ElementPainter());
492         ctx.add(new TerminalPainter(true, true, false, true));
493         //ctx.add(new ElementHeartbeater());
494 //        ctx.add(new ZoomTransitionParticipant(TransitionFunction.SIGMOID));
495
496         /////// D'n'D ///////
497         addDropParticipants(ctx);
498
499         h.setHint(ElementPainter.KEY_SELECTION_FRAME_COLOR, Color.MAGENTA);
500         h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
501
502         h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 100000.0);
503         h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);
504
505         Double snapResolution = diagramPreferences.get(DiagramPreferences.P_SNAP_GRID_SIZE);
506         this.snapAdvisor = new GridSnapAdvisor(snapResolution);
507         h.setHint(DiagramHints.SNAP_ADVISOR, this.snapAdvisor);
508
509         // Workbench selection provider
510         addStructureParticipants(ctx);
511
512         // Pop-up menu
513         addPopupmenu(ctx);
514
515         // Load page frame description settings
516         loadPageSettings(ctx);
517
518         // The canvas context should not be painted until it is ready to avoid
519         // unnecessary visual glitches.
520         h.setHint(Hints.KEY_DISABLE_PAINTING, Boolean.TRUE);
521
522         ctx.assertParticipantDependencies();
523
524         return ctx;
525     }
526
527     protected void loadPageSettings(ICanvasContext ctx) {
528         PageDesc pageDesc = null;
529
530         if (diagramResource != null) {
531             try {
532                 pageDesc = sessionContext.getSession().syncRequest(new Read<PageDesc>() {
533                     @Override
534                     public PageDesc perform(ReadGraph graph) throws DatabaseException {
535                         return DiagramGraphUtil.getPageDesc(graph, diagramResource, null);
536                     }
537                 });
538             } catch (DatabaseException e) {
539                 ErrorLogger.defaultLogError(e);
540             }
541         }
542
543         if (pageDesc == null) {
544             // Take page description from the preferences if nothing else is available.
545             PageDesc pd = diagramPreferences.getCompletePageDesc();
546             pageDesc = pd;
547         }
548         ctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, pageDesc);
549     }
550
551     private boolean firstFocus = true;
552
553     @Override
554     public void setFocus() {
555         c.setFocus();
556
557         if (firstFocus) {
558             // This is a workaround for using the symbol viewer in multi-page
559             // editors which causes the first zoom-to-fit scheduling to happen
560             // already before the controls have been laid out properly.
561             firstFocus = false;
562             firstTimeSetFocus();
563         }
564     }
565
566     protected void firstTimeSetFocus() {
567         //scheduleZoomToFit();
568     }
569
570     @Override
571     public void dispose() {
572         // Remember to remove the added preference change listener
573         diagramPreferences.preferences.removePreferenceChangeListener(preferenceListener);
574
575         // Deactivate all contexts here because after this the context service
576         // in question will not be available.
577         contextUtil.deactivateAll();
578
579         disposed = true;
580         if (activation != null) {
581             activation.deactivate();
582             activation = null;
583         }
584         synchronizer.dispose();
585         ThreadUtils.asyncExec(c.getCanvasContext().getThreadAccess(), new Runnable() {
586             @Override
587             public void run() {
588                 c.getCanvasContext().dispose();
589             }
590         });
591         sourceDiagram.dispose();
592         support.dispose();
593         super.dispose();
594     }
595
596     protected Resource getInputResource() {
597         return getResourceInput().getResource();
598     }
599
600     @Override
601     public IResourceEditorInput2 getResourceInput2() {
602         return (IResourceEditorInput2) getEditorInput();
603     }
604
605     @Override
606     public IResourceEditorInput getResourceInput() {
607         return (IResourceEditorInput) getEditorInput();
608     }
609
610     @Override
611     public void doSave(IProgressMonitor monitor) {
612     }
613
614     @Override
615     public void doSaveAs() {
616     }
617
618     @Override
619     public void init(IEditorSite site, IEditorInput input) throws PartInitException {
620         if (!(input instanceof IResourceEditorInput))
621             throw new PartInitException("Invalid input: must be IResourceEditorInput");
622         setSite(site);
623         setInput(input);
624         support = new ResourceEditorSupport(this);
625
626         // Set initial part name according to the name given by IEditorInput
627         setPartName(getEditorInput().getName());
628
629         Session session = SimanticsUI.peekSession();
630         if (session != null) {
631             Supplier<Boolean> disposedCallback = () -> disposed;
632             session.asyncRequest(
633                     new TitleRequest(site.getId(), getResourceInput2()),
634                     new TitleUpdater(site.getShell().getDisplay(), this::setPartName, disposedCallback));
635             session.asyncRequest(
636                     new ToolTipRequest(site.getId(), getResourceInput2()),
637                     new TitleUpdater(site.getShell().getDisplay(), this::setTitleToolTip, disposedCallback));
638         }
639
640     }
641
642     @Override
643     public boolean isDirty() {
644         return false;
645     }
646
647     @Override
648     public boolean isSaveAsAllowed() {
649         return false;
650     }
651
652     @SuppressWarnings("unchecked")
653     @Override
654     public <T> T getAdapter(Class<T> adapter) {
655         if (adapter == IPropertyPage.class)
656             return (T) new StandardPropertyPage(getSite());
657         if (adapter == IContentOutlinePage.class)
658             return (T) new DiagramOutlinePage(sessionContextProvider, getResourceInput2());
659         if (adapter == ILayersViewPage.class)
660             return (T) new DiagramLayersPage(sourceDiagram, canvasContext);
661         if (adapter == ICanvasContext.class)
662             return (T) canvasContext;
663         if (adapter == INode.class) {
664             if (canvasContext != null) {
665                 INode node = canvasContext.getCanvasNode();
666                 if (node != null)
667                     return (T) NodeUtil.getRootNode(node);
668             }
669             return null;
670         }
671         if (adapter == IDiagram.class)
672             return (T) sourceDiagram;
673         if (adapter == Session.class)
674             return (T) sessionContext.getSession();
675         return super.getAdapter(adapter);
676     }
677
678     protected void onCreated() {
679     }
680
681
682     private static Object BEGIN(String name) {
683         if (PROFILE) {
684             //return ThreadLog.BEGIN(name);
685         }
686         return null;
687     }
688
689     private static void END(Object task) {
690         if (PROFILE) {
691             //((Task) task).end();
692         }
693     }
694
695 }