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