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