]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/DiagramViewer.java
Introduce new DiagramViewer.getRuntimeFromManager()
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / DiagramViewer.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2019 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, gitlab #399
12  *******************************************************************************/
13 package org.simantics.modeling.ui.diagramEditor;
14
15 import java.awt.Color;
16 import java.awt.dnd.DnDConstants;
17 import java.util.Collections;
18 import java.util.Set;
19 import java.util.concurrent.TimeUnit;
20 import java.util.function.Supplier;
21
22 import org.eclipse.core.runtime.Assert;
23 import org.eclipse.core.runtime.IAdaptable;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.SubMonitor;
26 import org.eclipse.core.runtime.jobs.Job;
27 import org.eclipse.jface.action.IStatusLineManager;
28 import org.eclipse.jface.resource.JFaceResources;
29 import org.eclipse.jface.resource.LocalResourceManager;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.swt.widgets.Display;
32 import org.eclipse.ui.IEditorInput;
33 import org.eclipse.ui.IEditorSite;
34 import org.eclipse.ui.IWorkbenchPartSite;
35 import org.eclipse.ui.contexts.IContextService;
36 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
37 import org.simantics.Simantics;
38 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
39 import org.simantics.db.ReadGraph;
40 import org.simantics.db.Resource;
41 import org.simantics.db.Session;
42 import org.simantics.db.WriteGraph;
43 import org.simantics.db.common.primitiverequest.PossibleAdapter;
44 import org.simantics.db.common.primitiverequest.PossibleObject;
45 import org.simantics.db.common.procedure.adapter.ListenerDelegate;
46 import org.simantics.db.common.procedure.adapter.ListenerSupport;
47 import org.simantics.db.common.request.ParametrizedRead;
48 import org.simantics.db.common.request.TypeURIs;
49 import org.simantics.db.common.request.WriteRequest;
50 import org.simantics.db.common.utils.CommonDBUtils;
51 import org.simantics.db.common.utils.TagUtil;
52 import org.simantics.db.exception.DatabaseException;
53 import org.simantics.db.layer0.request.combinations.Combinators;
54 import org.simantics.db.management.ISessionContext;
55 import org.simantics.db.management.ISessionContextProvider;
56 import org.simantics.db.request.Read;
57 import org.simantics.diagram.DiagramTypeUtils;
58 import org.simantics.diagram.adapter.FlagClassFactory;
59 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
60 import org.simantics.diagram.adapter.IDiagramLoader;
61 import org.simantics.diagram.connection.ModelledConnectionAdvisor;
62 import org.simantics.diagram.handler.ConnectionCommandHandler;
63 import org.simantics.diagram.handler.CopyPasteHandler;
64 import org.simantics.diagram.handler.CopyPasteStrategy;
65 import org.simantics.diagram.handler.DefaultCopyPasteStrategy;
66 import org.simantics.diagram.handler.DeleteHandler;
67 import org.simantics.diagram.handler.ExpandSelectionHandler;
68 import org.simantics.diagram.handler.SimpleElementTransformHandler;
69 import org.simantics.diagram.layer.ILayersViewPage;
70 import org.simantics.diagram.participant.ContextUtil;
71 import org.simantics.diagram.participant.PointerInteractor2;
72 import org.simantics.diagram.participant.SGFocusParticipant;
73 import org.simantics.diagram.query.DiagramRequests;
74 import org.simantics.diagram.runtime.RuntimeDiagramManager;
75 import org.simantics.diagram.stubs.DiagramResource;
76 import org.simantics.diagram.symbolcontribution.SymbolProviderFactory;
77 import org.simantics.diagram.synchronization.CopyAdvisor;
78 import org.simantics.diagram.synchronization.IModifiableSynchronizationContext;
79 import org.simantics.diagram.synchronization.SynchronizationHints;
80 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
81 import org.simantics.diagram.ui.DiagramModelHints;
82 import org.simantics.diagram.ui.SWTPopupMenuParticipant;
83 import org.simantics.diagram.ui.SWTPopupMenuParticipantAwt;
84 import org.simantics.diagram.ui.WorkbenchSelectionProvider;
85 import org.simantics.g2d.canvas.Hints;
86 import org.simantics.g2d.canvas.ICanvasContext;
87 import org.simantics.g2d.canvas.ICanvasParticipant;
88 import org.simantics.g2d.canvas.impl.CanvasContext;
89 import org.simantics.g2d.chassis.AWTChassis;
90 import org.simantics.g2d.chassis.ICanvasChassis;
91 import org.simantics.g2d.chassis.IChassisListener;
92 import org.simantics.g2d.chassis.SWTChassis;
93 import org.simantics.g2d.connection.IConnectionAdvisor;
94 import org.simantics.g2d.diagram.DiagramClass;
95 import org.simantics.g2d.diagram.DiagramHints;
96 import org.simantics.g2d.diagram.IDiagram;
97 import org.simantics.g2d.diagram.handler.PickRequest.PickFilter;
98 import org.simantics.g2d.diagram.impl.Diagram;
99 import org.simantics.g2d.diagram.participant.DelayedBatchElementPainter;
100 import org.simantics.g2d.diagram.participant.DiagramParticipant;
101 import org.simantics.g2d.diagram.participant.ElementInteractor;
102 import org.simantics.g2d.diagram.participant.ElementPainter;
103 import org.simantics.g2d.diagram.participant.Selection;
104 import org.simantics.g2d.diagram.participant.TerminalPainter;
105 import org.simantics.g2d.diagram.participant.ZOrderHandler;
106 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
107 import org.simantics.g2d.element.ElementClassProviders;
108 import org.simantics.g2d.element.ElementClasses;
109 import org.simantics.g2d.element.ElementUtils;
110 import org.simantics.g2d.element.IElement;
111 import org.simantics.g2d.element.IElementClassProvider;
112 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
113 import org.simantics.g2d.elementclass.connection.ConnectionClass;
114 import org.simantics.g2d.page.DiagramDesc;
115 import org.simantics.g2d.participant.BackgroundPainter;
116 import org.simantics.g2d.participant.CanvasBoundsParticipant;
117 import org.simantics.g2d.participant.CanvasGrab;
118 import org.simantics.g2d.participant.GridPainter;
119 import org.simantics.g2d.participant.KeyUtil;
120 import org.simantics.g2d.participant.MouseUtil;
121 import org.simantics.g2d.participant.Notifications;
122 import org.simantics.g2d.participant.PageBorderParticipant;
123 import org.simantics.g2d.participant.PanZoomRotateHandler;
124 import org.simantics.g2d.participant.PointerPainter;
125 import org.simantics.g2d.participant.RenderingQualityInteractor;
126 import org.simantics.g2d.participant.RulerPainter;
127 import org.simantics.g2d.participant.SymbolUtil;
128 import org.simantics.g2d.participant.TimeParticipant;
129 import org.simantics.g2d.participant.TransformUtil;
130 import org.simantics.g2d.participant.WorkbenchStatusLine;
131 import org.simantics.g2d.participant.ZoomToAreaHandler;
132 import org.simantics.g2d.tooltip.TerminalTooltipParticipant;
133 import org.simantics.g2d.utils.CanvasUtils;
134 import org.simantics.layer0.utils.triggers.IActivation;
135 import org.simantics.layer0.utils.triggers.IActivationManager;
136 import org.simantics.modeling.ModelingResources;
137 import org.simantics.modeling.mapping.ComponentCopyAdvisor;
138 import org.simantics.modeling.mapping.ElementCopyAdvisor;
139 import org.simantics.modeling.mapping.MappedElementCopyAdvisor;
140 import org.simantics.modeling.mapping.ModelingSynchronizationHints;
141 import org.simantics.modeling.ui.diagramEditor.handlers.LinkBrowsingHandler;
142 import org.simantics.modeling.ui.diagramEditor.handlers.StructuralBrowsingHandler;
143 import org.simantics.modeling.ui.preferences.DiagramPreferenceUtil;
144 import org.simantics.modeling.ui.preferences.DiagramPreferences;
145 import org.simantics.project.ontology.ProjectResource;
146 import org.simantics.scenegraph.INode;
147 import org.simantics.scenegraph.g2d.snap.GridSnapAdvisor;
148 import org.simantics.scenegraph.utils.NodeUtil;
149 import org.simantics.selectionview.StandardPropertyPage;
150 import org.simantics.structural.stubs.StructuralResource2;
151 import org.simantics.structural2.modelingRules.IModelingRules;
152 import org.simantics.ui.SimanticsUI;
153 import org.simantics.ui.jobs.SessionGarbageCollectorJob;
154 import org.simantics.ui.workbench.IPropertyPage;
155 import org.simantics.ui.workbench.IResourceEditorInput;
156 import org.simantics.ui.workbench.IResourceEditorInput2;
157 import org.simantics.ui.workbench.TitleRequest;
158 import org.simantics.ui.workbench.TitleUpdater;
159 import org.simantics.ui.workbench.ToolTipRequest;
160 import org.simantics.ui.workbench.editor.input.InputValidationCombinators;
161 import org.simantics.utils.DataContainer;
162 import org.simantics.utils.datastructures.hints.HintContext;
163 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
164 import org.simantics.utils.datastructures.hints.IHintContext;
165 import org.simantics.utils.datastructures.hints.IHintContext.Key;
166 import org.simantics.utils.datastructures.hints.IHintListener;
167 import org.simantics.utils.datastructures.hints.IHintObservable;
168 import org.simantics.utils.threads.AWTThread;
169 import org.simantics.utils.threads.IThreadWorkQueue;
170 import org.simantics.utils.threads.SWTThread;
171 import org.simantics.utils.threads.ThreadUtils;
172 import org.simantics.utils.ui.ErrorLogger;
173 import org.simantics.utils.ui.ExceptionUtils;
174
175 import com.kitfox.svg.SVGCache;
176
177 /**
178  * @author Toni Kalajainen
179  * @author Tuukka Lehtonen
180  */
181 public class DiagramViewer 
182   //extends EditorPart implements IResourceEditorPart2, 
183     implements ListenerSupport, IAdaptable {
184
185     public interface DiagramViewerHost {
186         void doSetPartName(String name);
187         void doSetTitleToolTip(String name);
188     }
189
190     public static final String                      DIAGRAMMING_CONTEXT      = "org.simantics.modeling.ui.diagramming"; //$NON-NLS-1$
191     private static final String                     PREFERENCE_VIRTUAL_GRAPH = "preferences"; //$NON-NLS-1$
192
193     private static final boolean                    PROFILE                  = false;
194
195     ParametrizedRead<IResourceEditorInput, Boolean> INPUT_VALIDATOR =
196         Combinators.compose(
197                 InputValidationCombinators.or(
198                         // Normal configuration diagrams of a model
199                         Combinators.compose(
200                                 InputValidationCombinators.hasURI(),
201                                 InputValidationCombinators.partialFunction(ModelingResources.URIs.DiagramToComposite)
202                         ),
203                         // Configuration diagrams of a component type
204                         Combinators.compose(
205                                 InputValidationCombinators.hasURI(),
206                                 Combinators.compose(
207                                         InputValidationCombinators.partialFunction(StructuralResource2.URIs.Defines),
208                                         InputValidationCombinators.partialFunction(ModelingResources.URIs.DiagramToComposite)
209                                 )
210                         )
211                 ),
212                 InputValidationCombinators.extractInputResource()
213         );
214
215     protected EditorState                editorState;
216
217     protected boolean                    disposed           = false;
218     protected IThreadWorkQueue           swt;
219     protected IStatusLineManager         statusLineManager;
220     protected Display                    display;
221     protected LocalResourceManager       resourceManager;
222     protected SWTChassis                 c;
223     protected IDiagram                   sourceDiagram;
224     protected DataContainer<IDiagram>    sourceDiagramContainer;
225     protected CanvasContext              canvasContext;
226     protected ISessionContextProvider    sessionContextProvider;
227     protected ISessionContext            sessionContext;
228     protected Resource                   diagramResource;
229     protected GraphToDiagramSynchronizer synchronizer;
230     protected IActivation                activation;
231     protected ContextUtil                contextUtil;
232     protected SWTPopupMenuParticipant    popupMenuParticipant;
233     
234     protected DiagramPreferences         diagramPreferences;
235     protected DiagramDesc                diagramDesc;
236     protected GridSnapAdvisor            snapAdvisor;
237
238     private RuntimeDiagramManager        runtimeDiagramManager;
239     private Resource                     runtimeDiagramResourceCache;
240     private HasDiagramSourceListener     hasDiagramSourceListener;
241
242     /**
243      * Set externally in
244      * {@link #init(DiagramViewerHost, IEditorSite, IEditorInput, DataContainer, WorkbenchSelectionProvider)}
245      * .
246      */
247     protected WorkbenchSelectionProvider selectionProvider;
248
249     protected Resource getRuntimeFromManager() {
250         RuntimeDiagramManager rtdm = runtimeDiagramManager;
251         return (rtdm == null) ? null : rtdm.getRuntimeDiagram();
252     }
253
254     public Resource getRuntime() {
255         if (runtimeDiagramResourceCache != null)
256             return runtimeDiagramResourceCache;
257         runtimeDiagramResourceCache = getRuntimeFromManager();
258         return runtimeDiagramResourceCache;
259     }
260
261     public ParametrizedRead<IResourceEditorInput, Boolean> getInputValidator() {
262         return INPUT_VALIDATOR;
263     }
264
265     protected void addDropParticipants(ICanvasContext ctx) {
266         ctx.getDefaultHintContext().setHint(Hints.KEY_ALLOWED_DRAG_ACTIONS, DnDConstants.ACTION_COPY);
267
268         ctx.add(new PopulateElementDropParticipant(synchronizer, getSite()));
269         ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));
270     }
271
272     protected CopyPasteStrategy getCopyPasteStrategy() {
273                 try {
274                         CopyPasteStrategy cpStrategy = Simantics.getSession().syncRequest(new PossibleAdapter<CopyPasteStrategy>(getInputResource(), CopyPasteStrategy.class));
275                         if(cpStrategy != null) return cpStrategy;
276                 } catch (DatabaseException e) {
277                 }
278                 return getDefaultCopyPasteStrategy();
279     }
280     
281     protected CopyPasteStrategy getDefaultCopyPasteStrategy() {
282         return new DefaultCopyPasteStrategy();
283     }
284
285     protected CopyAdvisor getCopyAdvisor() {
286                 try {
287                         CopyAdvisor advisor = Simantics.getSession().syncRequest(new PossibleAdapter<CopyAdvisor>(getInputResource(), CopyAdvisor.class));
288                         if(advisor != null) return advisor;
289                 } catch (DatabaseException e) {
290                 }
291                 return new MappedElementCopyAdvisor(new ElementCopyAdvisor(), new ComponentCopyAdvisor());
292     }
293     
294     /**
295      * @param ctx
296      * TODO: change argument from CanvasContext to ICanvasContext
297      */
298     protected void addKeyBindingParticipants(CanvasContext ctx) {
299         //ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );
300         ctx.add(new DeleteHandler(statusLineManager));
301         ctx.add(new CopyPasteHandler(getCopyPasteStrategy(), statusLineManager).setWorkbenchSite(getEditorSite()));
302         ctx.add(new ConnectionCommandHandler());
303     }
304
305     protected void addPopupmenu(ICanvasContext ctx) {
306         ctx.add(popupMenuParticipant);
307     }
308
309     protected void addWorkbenchSelectionProvider(ICanvasContext ctx) {
310         if (selectionProvider != null)
311             ctx.add(selectionProvider);
312     }
313
314     protected void addViewManipulationParticipants(CanvasContext ctx) {
315         ctx.add(new PanZoomRotateHandler());
316         //ctx.add(new MousePanZoomInteractor());
317         //ctx.add(new MultitouchPanZoomRotateInteractor());
318         // ctx.add( new OrientationRestorer() );
319         ctx.add(new ZoomToAreaHandler());
320     }
321
322     protected void addDiagramParticipants(ICanvasContext ctx) {
323         ctx.add(new ZOrderHandler());
324         ctx.add(getPointerInteractor());
325         ctx.add(new ElementInteractor());
326         ctx.add(new Selection());
327         ctx.add(new DiagramParticipant());
328         ctx.add(new ElementPainter());
329         //ctx.add(new ElementHeartbeater());
330         //ctx.add(new ZoomTransitionParticipant(TransitionFunction.SIGMOID));
331         //ctx.add(new TooltipParticipant());
332         ctx.add(new TerminalTooltipParticipant());
333     }
334
335     protected void addPainterParticipants(ICanvasContext ctx) {
336         ctx.add(new RenderingQualityInteractor());
337         ctx.add(new TerminalPainter(true, true, false, true));
338         ctx.add(new DelayedBatchElementPainter(PickFilter.FILTER_MONITORS, 500, TimeUnit.MILLISECONDS));
339     }
340
341     protected void addStructureParticipants(ICanvasContext ctx) {
342         addWorkbenchSelectionProvider(ctx);
343         // Add visual browsing capabilities for structural models
344         ctx.add(new StructuralBrowsingHandler(getSite(), sessionContext, getResourceInput2()));
345         ctx.add(new LinkBrowsingHandler(getSite(), this, sessionContext));
346     }
347
348     /**
349      * Override to add any diagram/canvas participants to the canvas context
350      * initialized for the editor.
351      * 
352      * @param ctx
353      */
354     protected void addOtherParticipants(CanvasContext ctx) {
355     }
356
357     public static Set<String> defaultPropertyBrowseContexts = Collections.singleton(ProjectResource.URIs.ProjectBrowseContext);
358
359     protected Set<String> getPropertyPageContexts() {
360         try {
361             return BrowseContext.getBrowseContextClosure(Simantics.getSession(), defaultPropertyBrowseContexts);
362         } catch (DatabaseException e) {
363             ExceptionUtils.logAndShowError(Messages.DiagramViewer_FailedtoLoadModeled, e);
364             return defaultPropertyBrowseContexts;
365         }
366     }
367
368     protected IPropertyPage createPropertyPage(IWorkbenchPartSite site, Set<String> contexts) {
369         return new StandardPropertyPage(site, contexts);
370     }
371
372     protected String getPopupId() {
373         return "#ModelingDiagramPopup"; //$NON-NLS-1$
374     }
375
376     protected void getPreferences() {
377         this.diagramPreferences = DiagramPreferenceUtil.getPreferences();
378     }
379
380     protected void initSession() {
381         sessionContextProvider = Simantics.getSessionContextProvider();
382         sessionContext = sessionContextProvider.getSessionContext();
383     }
384
385     protected void readNames() {
386         String name = getEditorInput().getName();
387         host.doSetPartName(name);
388         host.doSetTitleToolTip(name);
389     }
390
391     class ChassisListener implements IChassisListener {
392         @Override
393         public void chassisClosed(ICanvasChassis sender) {
394             // Prevent deadlock while disposing which using syncExec would result in.
395             final ICanvasContext ctx = canvasContext;
396             ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() {
397                 @Override
398                 public void run() {
399                     if (ctx != null) {
400                         saveEditorState(ctx);
401                         ctx.getHintStack().removeKeyHintListener(GridPainter.KEY_GRID_ENABLED, canvasHintListener);
402                         ctx.getHintStack().removeKeyHintListener(RulerPainter.KEY_RULER_ENABLED, canvasHintListener);
403                         final AWTChassis awtChassis = c.getAWTComponent();
404                         if (awtChassis != null)
405                             awtChassis.setCanvasContext(null);
406                         ctx.dispose();
407                     }
408
409                     if (sourceDiagramContainer != null) {
410                         sourceDiagramContainer.set(null);
411                         sourceDiagramContainer = null;
412                     }
413
414                     if (sourceDiagram != null)
415                         sourceDiagram.dispose();
416
417                     if(synchronizer != null) {
418                         synchronizer.dispose();
419                         // Let GC work.
420                         synchronizer = null;
421                     }
422
423                     if (runtimeDiagramManager != null) {
424                         runtimeDiagramManager.dispose();
425                         runtimeDiagramManager = null;
426                     }
427                 }
428             });
429             c.removeChassisListener(ChassisListener.this);
430         }
431     }
432
433     protected void createChassis(Composite parent) {
434         resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
435         c = new SWTChassis(parent, 0);
436
437         Object task = BEGIN("DV.precreateParticipants"); //$NON-NLS-1$
438         createCustomParticipants();
439         END(task);
440
441         c.populate(component -> {
442             if (!disposed) {
443                 c.addChassisListener(new ChassisListener());
444                 initializeCanvas();
445             }
446         });
447     }
448
449     protected void beforeSetCanvasContext(ICanvasContext canvasContext2) {
450     }
451
452     /**
453      * Invoke this only from the AWT thread.
454      * @param context
455      */
456     protected void setCanvasContext(ICanvasContext context) {
457         // Cannot directly invoke SWTChassis.setCanvasContext only because it
458         // needs to be invoked in the SWT thread and AWTChassis.setCanvasContext in the
459         // AWT thread, but directly invoking SWTChassis.setCanvasContext would call both
460         // in the SWT thread which would cause synchronous scheduling of AWT
461         // runnables which is always a potential source of deadlocks.
462         c.getAWTComponent().setCanvasContext(canvasContext);
463         swt.asyncExec(new Runnable() {
464             @Override
465             public void run() {
466                 if (!c.isDisposed())
467                     // For AWT, this is a no-operation.
468                     c.setCanvasContext(canvasContext);
469             }
470         });
471     }
472
473     public void createPartControl(Composite parent) {
474         //ProfileObserver.begin = System.nanoTime();
475         display = parent.getDisplay(); 
476         swt = SWTThread.getThreadAccess(display);
477         statusLineManager = getEditorSite().getActionBars().getStatusLineManager();
478
479         Object task = BEGIN("DV.initSession"); //$NON-NLS-1$
480         initSession();
481         END(task);
482
483         diagramResource = getInputResource();
484         readNames();
485         getPreferences();
486
487         try {
488             this.runtimeDiagramManager = RuntimeDiagramManager.track(sessionContext.getSession(), diagramResource, getEditorInput(), this);
489
490             // Create the canvas context here before finishing createPartControl
491             // to give DiagramViewerActionContributor a chance to work.
492             // The context can be created in SWT thread without scheduling
493             // to the context thread and having potential deadlocks.
494             IThreadWorkQueue thread = AWTThread.getThreadAccess();
495             this.canvasContext = new CanvasContext(thread);
496             this.canvasContext.setLocked(true);
497
498             task = BEGIN("DV.createChassis"); //$NON-NLS-1$
499             createChassis(parent);
500             END(task);
501         } catch (DatabaseException e) {
502             ErrorLogger.defaultLogError(e);
503         }
504     }
505
506
507         /**
508      * A method invoked before chassis construction for creating such
509      * {@link ICanvasParticipant}s that need to be constructed in the SWT
510      * thread.
511      * 
512      * Use it for creating any such canvas participants during the viewer 
513      * construction and add them to the {@link ICanvasContext} later on from
514      * the AWT thread.
515      */
516     protected void createCustomParticipants() {
517         if (SimanticsUI.isLinuxGTK()) {
518                 popupMenuParticipant = new SWTPopupMenuParticipantAwt(getSite(), c, display, getPopupId());
519         } else {
520                 popupMenuParticipant = new SWTPopupMenuParticipant(getSite(), c, display, getPopupId());
521         }
522     }
523
524     /**
525      * Invoke this only from the AWT thread.
526      */
527     protected void initializeCanvas() {
528         Object canvasInit = BEGIN("DV.canvasInitialization"); //$NON-NLS-1$
529
530         Object task = BEGIN("DV.createViewerCanvas"); //$NON-NLS-1$
531         initializeCanvasContext(canvasContext);
532         END(task);
533
534         beforeSetCanvasContext(canvasContext);
535         //FullscreenUtils.addFullScreenHandler(canvasContext, s, canvasProvider);
536
537         // Without this all diagram participants will crash like there's no tomorrow.
538         // Just trying to keep the behavior a bit more sane in case of
539         // errors instead of flooding the console with exceptions.
540         canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, Diagram.spawnNew(DiagramClass.DEFAULT));
541
542         // Changes in ruler/grid activity shall be written as
543         // workspace-persistent diagram-specific preferences.
544         canvasContext.getHintStack().addKeyHintListener(GridPainter.KEY_GRID_ENABLED, canvasHintListener);
545         canvasContext.getHintStack().addKeyHintListener(RulerPainter.KEY_RULER_ENABLED, canvasHintListener);
546
547         task = BEGIN("DV.setCanvasContext"); //$NON-NLS-1$
548         setCanvasContext(canvasContext);
549         END(task);
550
551         // Finish loading in a worker thread because it may be a time consuming
552         // process to load a large diagram and we don't want unnecessary AWT
553         // thread contention.
554         Job loadJob = new DiagramViewerLoadJob(this);
555         loadJob.schedule();
556
557         END(canvasInit);
558     }
559
560     protected void activateUiContexts(ContextUtil util) {
561         util.activate(DIAGRAMMING_CONTEXT);
562     }
563
564     /**
565      * @param monitor the progress monitor to use for reporting progress to the
566      *        user. It is the caller's responsibility to call done() on the
567      *        given monitor. Accepts <code>null</code>, indicating that no
568      *        progress should be reported and that the operation cannot be
569      *        cancelled.
570      */
571     protected void performActivation(IProgressMonitor monitor) {
572         SubMonitor progress = SubMonitor.convert(monitor, Messages.DiagramViewer_MonitorActivateMapping, 100);
573         IActivationManager activationManager = sessionContext.getSession().peekService(IActivationManager.class);
574         if (activationManager != null) {
575             activation = activationManager.activate(diagramResource);
576         }
577         progress.worked(100);
578     }
579
580     protected void onCreated() {
581     }
582
583     /**
584      * @param diagram
585      */
586     protected void scheduleZoomToFit(IDiagram diagram) {
587         if (diagram == null)
588             throw new IllegalStateException("diagram is null"); //$NON-NLS-1$
589
590         CanvasUtils.scheduleZoomToFit(swt, () -> disposed, canvasContext, diagram);
591     }
592
593     /**
594      * Subclasses may override but should always invoke super.
595      * 
596      * @param diagram
597      * @param initialHints
598      * @throws DatabaseException
599      */
600     protected void fillInitialDiagramHints(Resource diagram, IHintContext initialHints) throws DatabaseException {
601         IModelingRules modelingRules = sessionContext.getSession().syncRequest(
602                 DiagramRequests.getModelingRules(diagram, null));
603         if (modelingRules != null) {
604             initialHints.setHint(DiagramModelHints.KEY_MODELING_RULES, modelingRules);
605             initialHints.setHint(DiagramHints.CONNECTION_ADVISOR,
606                     getConnectionAdvisor(modelingRules, sessionContext.getSession()));
607         }
608
609         initialHints.setHint(SynchronizationHints.COPY_ADVISOR, getCopyAdvisor());
610         initialHints.setHint(DiagramHints.KEY_USE_CONNECTION_FLAGS, Boolean.TRUE);
611         initialHints.setHint(DiagramHints.KEY_ALLOW_CONNECTION_BRANCHING, Boolean.TRUE);
612         initialHints.setHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS, Boolean.TRUE);
613     }
614
615     /**
616      * @param monitor the progress monitor to use for reporting progress to the
617      *        user. It is the caller's responsibility to call done() on the
618      *        given monitor. Accepts <code>null</code>, indicating that no
619      *        progress should be reported and that the operation cannot be
620      *        cancelled.
621      * @param r
622      * @return
623      * @throws DatabaseException
624      */
625     protected IDiagram loadDiagram(IProgressMonitor monitor, final Resource r) throws DatabaseException {
626         // Pre-load modeling rules and possibly other hints too since they are
627         // needed already while loading the diagram contents.
628         IHintContext initialHints = new HintContext();
629         fillInitialDiagramHints(r, initialHints);
630         IDiagram d = loadDiagram(monitor, r, initialHints);
631         return d;
632     }
633
634     /**
635      * @param monitor the progress monitor to use for reporting progress to the
636      *        user. It is the caller's responsibility to call done() on the
637      *        given monitor. Accepts <code>null</code>, indicating that no
638      *        progress should be reported and that the operation cannot be
639      *        cancelled.
640      * @param diagram
641      * @param initialHints
642      * @return
643      * @throws DatabaseException
644      */
645     protected IDiagram loadDiagram(IProgressMonitor monitor, Resource diagram, IHintContext initialHints) throws DatabaseException {
646         RuntimeDiagramManager rtdm = runtimeDiagramManager;
647         Resource runtimeDiagram = rtdm != null ? rtdm.getRuntimeDiagram() : null;
648         IDiagramLoader loader = synchronizer;
649         if (rtdm == null || runtimeDiagram == null || loader == null)
650             return null;
651         IDiagram d = sessionContext.getSession().syncRequest((Read<IDiagram>) graph -> {
652             IDiagram result = DiagramRequests.loadDiagram(monitor, getResourceInput2().getModel(null), diagram,
653                     runtimeDiagram, null, loader, initialHints).perform(graph);
654
655             // #399: Enable certain PropertyTester implementation without database transactions
656             ModelingResources MOD = ModelingResources.getInstance(graph);
657             Resource composite = graph.getPossibleObject(diagram, MOD.DiagramToComposite);
658             result.setHint(
659                     DiagramModelHints.KEY_DIAGRAM_RESOURCE_TYPE_URIS,
660                     graph.syncRequest(new TypeURIs(diagram)));
661             result.setHint(
662                     DiagramModelHints.KEY_MAPPED_COMPOSITE_RESOURCE_TYPE_URIS,
663                     composite != null ? graph.syncRequest(new TypeURIs(composite)) : Collections.emptySet());
664
665             Resource diagramSource = graph.syncRequest(
666                     new PossibleObject(diagram, MOD.HasDiagramSource),
667                     hasDiagramSourceListener = new HasDiagramSourceListener(sourceDiagramContainer));
668             ElementUtils.setOrRemoveHint(
669                     result, 
670                     DiagramModelHints.KEY_HAS_DIAGRAM_SOURCE,
671                     diagramSource);
672
673             return result;
674         });
675         return d;
676     }
677
678     protected void beforeSetDiagram(IDiagram diagram) {
679     }
680
681     protected PointerInteractor getPointerInteractor() {
682         return new PointerInteractor2(true, true, true, false, true, false, synchronizer.getElementClassProvider());
683     }
684
685     protected IConnectionAdvisor getConnectionAdvisor(IModelingRules modelingRules, Session session) {
686         return new ModelledConnectionAdvisor(modelingRules, sessionContext.getSession());
687     }
688
689     protected GraphToDiagramSynchronizer createSynchronizer(final ICanvasContext ctx, final ISessionContext sessionContext) {
690         try {
691             return sessionContext.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {
692                 @Override
693                 public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {
694                     GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx, createElementClassProvider(graph));
695                     initializeSynchronizationContext(graph, sync);
696                     return sync;
697                 }
698             });
699         } catch (DatabaseException e) {
700             throw new UnsupportedOperationException("Failed to initialize data model synchronizer", e); //$NON-NLS-1$
701         }
702     }
703
704     protected void initializeSynchronizationContext(ReadGraph graph, IModifiableSynchronizationContext context) {
705         context.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));
706     }
707
708     protected IElementClassProvider createElementClassProvider(ReadGraph graph) {
709         DiagramResource dr = DiagramResource.getInstance(graph);
710         return ElementClassProviders.mappedProvider(
711                 ElementClasses.CONNECTION, ConnectionClass.CLASS.newClassWith(new StaticObjectAdapter(dr.RouteGraphConnection)),
712                 ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)
713         );
714     }
715     
716     protected SimpleElementTransformHandler getTransformHandler() {
717         return new SimpleElementTransformHandler(true, true, true);
718     }
719
720     public void initializeCanvasContext(CanvasContext ctx) {
721         IHintContext h = ctx.getDefaultHintContext();
722
723         // The canvas context should not be painted until it is ready to avoid
724         // unnecessary visual glitches.
725         h.setHint(Hints.KEY_DISABLE_PAINTING, Boolean.TRUE);
726
727         Object task = BEGIN("createSynchronizer"); //$NON-NLS-1$
728         this.synchronizer = createSynchronizer(ctx, sessionContext);
729         END(task);
730
731         IContextService contextService = (IContextService) getSite().getService(IContextService.class);
732         contextUtil = new ContextUtil(contextService, swt);
733
734         // Support & Util Participants
735         ctx.add(new TransformUtil());
736         ctx.add(new MouseUtil());
737         ctx.add(new KeyUtil());
738         ctx.add(contextUtil);
739         ctx.add(new WorkbenchStatusLine(statusLineManager));
740         ctx.add(new CanvasGrab());
741         ctx.add(new SymbolUtil());
742         ctx.add(new TimeParticipant());
743         ctx.add(new CanvasBoundsParticipant());
744         ctx.add(new Notifications());
745
746         ctx.add(new SGFocusParticipant(c, DIAGRAMMING_CONTEXT));
747
748         // Debug participant(s)
749         // ctx.add( new PointerPainter() );
750         // ctx.add( new HandPainter() );
751         h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
752
753         // Pan & Zoom & Rotate
754         addViewManipulationParticipants(ctx);
755
756         ctx.add(getTransformHandler());
757         ctx.add(new ExpandSelectionHandler(getEditorSite().getActionBars().getStatusLineManager()));
758
759         // Key bindings
760         addKeyBindingParticipants(ctx);
761
762         // Grid & Ruler & Background
763         addGridRulerBackgroundParticipants(ctx);
764
765         h.setHint(Hints.KEY_DISPLAY_PAGE, diagramPreferences.get(DiagramPreferences.P_DISPLAY_PAGE_SIZE));
766         h.setHint(Hints.KEY_DISPLAY_MARGINS, diagramPreferences.get(DiagramPreferences.P_DISPLAY_MARGINS));
767         ctx.add(new PageBorderParticipant());
768
769         // h.setHint(Hints.KEY_GRID_COLOR, new Color(0.9f, 0.9f, 0.9f));
770         // h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.LIGHT_GRAY);
771         h.setHint(Hints.KEY_GRID_COLOR, new Color(0.9f, 0.9f, 0.9f));
772         h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.WHITE);
773         h.setHint(RulerPainter.KEY_RULER_BACKGROUND_COLOR, new Color(0.9f, 0.9f, 0.9f, 0.75f));
774         h.setHint(RulerPainter.KEY_RULER_TEXT_COLOR, Color.BLACK);
775
776         ////// Diagram Participants //////
777         addDiagramParticipants(ctx);
778         addPainterParticipants(ctx);
779
780         /////// D'n'D ///////
781         addDropParticipants(ctx);
782
783         h.setHint(ElementPainter.KEY_SELECTION_FRAME_COLOR, Color.MAGENTA);
784         h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
785
786         h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 100000.0);
787         h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);
788
789         Double snapResolution = diagramPreferences.get(DiagramPreferences.P_SNAP_GRID_SIZE);
790         this.snapAdvisor = new GridSnapAdvisor(snapResolution);
791         h.setHint(DiagramHints.SNAP_ADVISOR, this.snapAdvisor);
792         h.setHint(GridPainter.KEY_GRID_SIZE, snapResolution);
793         h.setHint(GridPainter.KEY_GRID_ENABLED, Boolean.FALSE);
794
795         // Workbench selection provider
796         addStructureParticipants(ctx);
797
798         // Pop-up menu
799         addPopupmenu(ctx);
800
801         // Load page frame description settings
802         loadPageSettings(ctx);
803
804         addOtherParticipants(ctx);
805
806         ctx.assertParticipantDependencies();
807         ctx.setLocked(false);
808     }
809
810     protected void addGridRulerBackgroundParticipants(CanvasContext ctx) {
811         ctx.add(new GridPainter());
812         ctx.add(new RulerPainter());
813         ctx.add(new BackgroundPainter());
814     }
815
816     protected void loadPageSettings(ICanvasContext ctx) {
817         DiagramDesc diagramDesc = null;
818
819         // load diagram page configuration
820         if (diagramResource != null) {
821             try {
822                 diagramDesc = sessionContext.getSession().syncRequest(DiagramRequests.getDiagramDesc(diagramResource));
823             } catch (DatabaseException e) {
824                 ErrorLogger.defaultLogError(e);
825             }
826         }
827
828         if (diagramDesc == null) {
829             // Take page description from the preferences if nothing else is available.
830             final DiagramDesc desc = diagramDesc = diagramPreferences.getDiagramDesc();
831
832             // Write page configuration to graph
833             sessionContext.getSession().asyncRequest(new WriteRequest() {
834                 @Override
835                 public void perform(WriteGraph graph) throws DatabaseException {
836                     if (graph.isImmutable(diagramResource))
837                         return;
838                     CommonDBUtils.selectClusterSet(graph, diagramResource);
839                     DiagramGraphUtil.setDiagramDesc(graph, diagramResource, desc);
840                 }
841             }, parameter -> {
842                 if (parameter != null)
843                     ErrorLogger.defaultLogError("Failed to write default diagram page description to database, see exception for details", parameter); //$NON-NLS-1$
844             });
845         }
846
847         setDiagramDesc(ctx, diagramDesc);
848
849         // Create a listener to react to page setting changes.
850         sessionContext.getSession().asyncRequest(DiagramRequests.getDiagramDesc(diagramResource),
851                 new ListenerDelegate<DiagramDesc>(this) {
852             @Override
853             public void execute(final DiagramDesc result) {
854                 if (result != null && canvasContext != null) {
855                     ThreadUtils.asyncExec(canvasContext.getThreadAccess(), new Runnable() {
856                         @Override
857                         public void run() {
858                             if (!disposed)
859                                 setDiagramDesc(canvasContext, result);
860                         }
861                     });
862                 }
863             }
864         });
865     }
866
867     protected void setDiagramDesc(ICanvasContext ctx, DiagramDesc diagramDesc) {
868         if (diagramDesc == null)
869             throw new NullPointerException("null diagram desc"); //$NON-NLS-1$
870
871         if (diagramDesc.equals(this.diagramDesc))
872             return;
873
874         this.diagramDesc = diagramDesc;
875         IHintContext hints = ctx.getDefaultHintContext();
876         hints.setHint(Hints.KEY_PAGE_DESC, diagramDesc.getPageDesc());
877         hints.setHint(Hints.KEY_DISPLAY_PAGE, diagramDesc.isPageBordersVisible());
878         hints.setHint(Hints.KEY_DISPLAY_MARGINS, diagramDesc.isMarginsVisible());
879         hints.setHint(GridPainter.KEY_GRID_ENABLED, diagramDesc.isGridVisible());
880         hints.setHint(RulerPainter.KEY_RULER_ENABLED, diagramDesc.isRulerVisible());
881         snapAdvisor.setResolution(diagramDesc.getGridSize());
882         hints.setHint(GridPainter.KEY_GRID_SIZE, diagramDesc.getGridSize());
883     }
884
885     /**
886      * Must be invoked from the AWT thread only.
887      * 
888      * @param state
889      * @param ctx
890      */
891     protected void applyEditorState(final EditorState state, final ICanvasContext ctx) {
892         final IDiagram diagram = ctx.getHintStack().getHint(DiagramHints.KEY_DIAGRAM);
893
894         if (state.viewTransform != null && state.viewTransform.getDeterminant() != 0) {
895             for (PanZoomRotateHandler h : ctx.getItemsByClass(PanZoomRotateHandler.class)) {
896                 h.setTransform(state.viewTransform);
897             }
898         }
899
900         if (diagram != null) {
901             if (state.viewTransform != null)
902                 diagram.removeHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT);
903
904             if (state.toolMode != null)
905                 ctx.getDefaultHintContext().setHint(Hints.KEY_TOOL, state.toToolMode());
906             else
907                 ctx.getDefaultHintContext().setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
908
909             final Set<IElement> selected = DiagramEditorStates.toElements(state.selection, diagram);
910             if (!selected.isEmpty()) {
911                 for (Selection s : ctx.getItemsByClass(Selection.class)) {
912                     s.setSelection(0, selected);
913                 }
914             }
915         }
916     }
917
918     protected EditorState getSavedEditorState(ICanvasContext ctx) {
919         return DiagramEditorStates.toEditorState(ctx, true, true, true);
920     }
921
922     protected void saveEditorState(ICanvasContext ctx) {
923         DiagramEditorStates.saveEditorState(PREFERENCE_VIRTUAL_GRAPH, diagramResource, getSavedEditorState(ctx) , DiagramViewer.this);
924     }
925
926     private boolean firstFocus = true;
927
928     public void setFocus() {
929         
930         if(c != null) {
931                 c.setFocus();
932
933                 if (firstFocus) {
934                     // This is a workaround for using the symbol viewer in multi-page
935                     // editors which causes the first zoom-to-fit scheduling to happen
936                     // already before the controls have been laid out properly.
937                     firstFocus = false;
938                     firstTimeSetFocus();
939                 }
940                 
941         }
942         
943     }
944
945     protected void firstTimeSetFocus() {
946         // [Tuukka@2010-02-11]
947         // Removed since this is actually a workaround for multi-page editors.
948         //scheduleZoomToFit();
949     }
950
951     public void dispose() {
952         // Deactivate all contexts here because after this the context service
953         // in question will not be available.
954         if (contextUtil != null) {
955             contextUtil.deactivateAll();
956         }
957
958         disposed = true;
959
960         if (hasDiagramSourceListener != null) {
961             hasDiagramSourceListener.dispose();
962             hasDiagramSourceListener = null;
963         }
964
965         if (activation != null) {
966             activation.deactivate();
967             activation = null;
968         }
969
970         if (resourceManager != null) {
971                 resourceManager.dispose();
972                 resourceManager = null;
973         }
974         //super.dispose();
975     }
976
977     protected Resource getInputResource() {
978         return getResourceInput().getResource();
979     }
980
981     public IResourceEditorInput getResourceInput() {
982         return (IResourceEditorInput) getEditorInput();
983     }
984
985     public IResourceEditorInput2 getResourceInput2() {
986         return (IResourceEditorInput2) getEditorInput();
987     }
988
989     public void init(DiagramViewerHost _host, IEditorSite site, IEditorInput input, DataContainer<IDiagram> diagramContainer, WorkbenchSelectionProvider selectionProvider) {
990         if (!(input instanceof IResourceEditorInput))
991             throw new RuntimeException("Invalid input: must be IResourceEditorInput"); //$NON-NLS-1$
992
993         setHost(_host);
994         setSite(site);
995         setInput(input);
996         this.sourceDiagramContainer = diagramContainer;
997         this.selectionProvider = selectionProvider;
998
999         // Set initial part name according to the name given by IEditorInput
1000         host.doSetPartName(getEditorInput().getName());
1001
1002         Session session = Simantics.peekSession();
1003         if (session != null) {
1004             Supplier<Boolean> disposedCallback = () -> disposed;
1005             session.asyncRequest(
1006                     new TitleRequest(site.getId(), getResourceInput()),
1007                     new TitleUpdater(site.getShell().getDisplay(), host::doSetPartName, disposedCallback));
1008             session.asyncRequest(
1009                     new ToolTipRequest(site.getId(), getResourceInput()),
1010                     new TitleUpdater(site.getShell().getDisplay(), host::doSetTitleToolTip, disposedCallback));
1011         }
1012
1013         try {
1014             // Read previous editor state from the database
1015             editorState = DiagramEditorStates.readEditorState(getInputResource());
1016         } catch (DatabaseException e) {
1017             exception(e);
1018         }
1019     }
1020
1021     @SuppressWarnings("unchecked")
1022     @Override
1023     public <T> T getAdapter(Class<T> adapter) {
1024 //        System.out.println("diagramViewer getAdapter " + adapter);
1025         // Property view support
1026         if (adapter == IPropertyPage.class)
1027             return (T) createPropertyPage(getSite(), getPropertyPageContexts());
1028         // Provide symbols for the editor
1029         if (adapter == SymbolProviderFactory.class) {
1030             try {
1031                 return (T) DiagramTypeUtils.readSymbolProviderFactory(sessionContext.getSession(), diagramResource);
1032             } catch (DatabaseException e) {
1033                 ErrorLogger.defaultLogError(getClass() + " failed to adapt to SymbolProviderFactory, see exception for details.", e); //$NON-NLS-1$
1034                 return null;
1035             }
1036         }
1037         // Outline view support
1038         if (adapter == IContentOutlinePage.class)
1039             return (T) new DiagramOutlinePage(sessionContextProvider, getResourceInput2());
1040         // Role view support
1041         if (adapter == ILayersViewPage.class)
1042             return (T) new DiagramLayersPage(sourceDiagram, canvasContext);
1043         // Support external steering of the diagram canvas, zooming etc.
1044         if (adapter == ICanvasContext.class)
1045             return (T) canvasContext;
1046         // Support scene graph debugger view
1047         if (adapter == INode.class) {
1048             if (canvasContext != null) {
1049                 INode node = canvasContext.getCanvasNode();
1050                 if (node != null)
1051                     return (T) NodeUtil.getRootNode(node);
1052             }
1053             return null;
1054         }
1055         // Support retrieval of the current diagram.
1056         if (adapter == IDiagram.class)
1057             return (T) sourceDiagram;
1058         // Why is this here ??
1059         if (adapter == Session.class)
1060             return (T) sessionContext.getSession();
1061         if(adapter == RuntimeDiagramManager.class)
1062             return (T) runtimeDiagramManager;
1063         if (adapter == Resource.class)
1064             return (T) getRuntime();
1065         if (adapter == ICanvasChassis.class)
1066             return (T) c;
1067
1068         return null;
1069     }
1070
1071     //-------------------------------------------------------------------------
1072     // Profiling aid
1073
1074     protected static Object BEGIN(String name) {
1075         if (PROFILE) {
1076             //return ThreadLog.BEGIN(name);
1077         }
1078         return null;
1079     }
1080
1081     protected static void END(Object task) {
1082         if (PROFILE) {
1083             //((Task) task).end();
1084         }
1085     }
1086
1087     //-------------------------------------------------------------------------
1088     // implement ListenerSupport
1089
1090     @Override
1091     public void exception(Throwable t) {
1092         ErrorLogger.defaultLogError(t);
1093     }
1094
1095     @Override
1096     public boolean isDisposed() {
1097         return disposed;
1098     }
1099
1100     protected void collectGarbage() {
1101         SessionGarbageCollectorJob.getInstance().schedule(0);
1102         AWTThread.getThreadAccess().asyncExec(new Runnable() {
1103             @Override
1104             public void run() {
1105                 //System.out.println("BEFORE CLEAR: " + SVGCache.getSVGUniverse().report());
1106                 SVGCache.getSVGUniverse().clearUnreferenced();
1107                 //System.out.println("AFTER CLEAR: " + SVGCache.getSVGUniverse().report());
1108             }
1109         });
1110     }
1111
1112     //-------------------------------------------------------------------------
1113     // Listener for certain canvas context hint changes
1114
1115     IHintListener canvasHintListener = new HintListenerAdapter() {
1116         @Override
1117         public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
1118             if (key == GridPainter.KEY_GRID_ENABLED) {
1119                 boolean v = Boolean.TRUE.equals(newValue);
1120                 if (diagramDesc.isGridVisible() != v)
1121                     setGlobalPreference(DiagramResource.URIs.DisplayGrid, v);
1122             } else if (key == RulerPainter.KEY_RULER_ENABLED) {
1123                 boolean v = Boolean.TRUE.equals(newValue);
1124                 if (diagramDesc.isRulerVisible() != v)
1125                     setGlobalPreference(DiagramResource.URIs.DisplayRuler, v);
1126             }
1127         }
1128     };
1129
1130     private <T> void setGlobalPreference(final String preferenceURI, boolean value) {
1131         TagUtil.execute(Simantics.getSession(), PREFERENCE_VIRTUAL_GRAPH, preferenceURI, value, Simantics.getProjectResource());
1132     }
1133
1134     /*
1135      * --------------------------------------------------------------------
1136      * Changes related to removal of EditorPart extension from here on down
1137      * --------------------------------------------------------------------
1138      */
1139
1140     private IWorkbenchPartSite partSite;
1141     private DiagramViewerHost host;
1142     private IEditorInput editorInput = null;
1143
1144     /* (non-Javadoc)
1145      * Method declared on IWorkbenchPart.
1146      */
1147     public IWorkbenchPartSite getSite() {
1148         return partSite;
1149     }
1150
1151     public IEditorSite getEditorSite() {
1152         return (IEditorSite) getSite();
1153     }
1154
1155     public IEditorInput getEditorInput() {
1156         return editorInput;
1157     }
1158
1159 //    protected void setPartName(String partName) {
1160 ////        if (compatibilityTitleListener != null) {
1161 ////            removePropertyListener(compatibilityTitleListener);
1162 ////            compatibilityTitleListener = null;
1163 ////        }
1164 ////
1165 ////        super.setPartName(partName);
1166 //    }
1167  
1168 //    protected void setTitleToolTip(String toolTip) {
1169 ////        toolTip = Util.safeString(toolTip);
1170 ////        //Do not send changes if they are the same
1171 ////        if (Util.equals(this.toolTip, toolTip)) {
1172 ////                    return;
1173 ////            }
1174 ////        this.toolTip = toolTip;
1175 ////        firePropertyChange(IWorkbenchPart.PROP_TITLE);
1176 //    }
1177
1178     protected void setHost(DiagramViewerHost host) {
1179         this.host = host;
1180     }
1181
1182     protected void setSite(IWorkbenchPartSite site) {
1183         this.partSite = site;
1184     }
1185
1186     protected void setInput(IEditorInput input) {
1187         Assert.isLegal(input != null);
1188         editorInput = input;
1189     }
1190
1191     public Composite getComposite() {
1192         return c;
1193     }
1194
1195 }