1 /*******************************************************************************
2 * Copyright (c) 2007, 2013 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 * Semantum Oy - issue #4384
12 *******************************************************************************/
13 package org.simantics.modeling.ui.diagramEditor.e4;
15 import java.awt.Color;
16 import java.awt.dnd.DnDConstants;
17 import java.util.Collections;
19 import java.util.concurrent.TimeUnit;
20 import java.util.function.Supplier;
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.e4.ui.model.application.ui.basic.MPart;
28 import org.eclipse.e4.ui.services.EContextService;
29 import org.eclipse.jface.action.IStatusLineManager;
30 import org.eclipse.jface.resource.JFaceResources;
31 import org.eclipse.jface.resource.LocalResourceManager;
32 import org.eclipse.swt.widgets.Composite;
33 import org.eclipse.swt.widgets.Display;
34 import org.eclipse.swt.widgets.Shell;
35 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
36 import org.simantics.Simantics;
37 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
38 import org.simantics.db.ReadGraph;
39 import org.simantics.db.Resource;
40 import org.simantics.db.Session;
41 import org.simantics.db.WriteGraph;
42 import org.simantics.db.common.primitiverequest.PossibleAdapter;
43 import org.simantics.db.common.procedure.adapter.ListenerDelegate;
44 import org.simantics.db.common.procedure.adapter.ListenerSupport;
45 import org.simantics.db.common.request.ParametrizedRead;
46 import org.simantics.db.common.request.WriteRequest;
47 import org.simantics.db.common.utils.CommonDBUtils;
48 import org.simantics.db.common.utils.TagUtil;
49 import org.simantics.db.exception.DatabaseException;
50 import org.simantics.db.layer0.request.combinations.Combinators;
51 import org.simantics.db.management.ISessionContext;
52 import org.simantics.db.management.ISessionContextProvider;
53 import org.simantics.db.request.Read;
54 import org.simantics.diagram.DiagramTypeUtils;
55 import org.simantics.diagram.adapter.FlagClassFactory;
56 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
57 import org.simantics.diagram.adapter.IDiagramLoader;
58 import org.simantics.diagram.connection.ModelledConnectionAdvisor;
59 import org.simantics.diagram.handler.ConnectionCommandHandler;
60 import org.simantics.diagram.handler.CopyPasteStrategy;
61 import org.simantics.diagram.handler.DefaultCopyPasteStrategy;
62 import org.simantics.diagram.handler.DeleteHandler;
63 import org.simantics.diagram.handler.ExpandSelectionHandler;
64 import org.simantics.diagram.handler.SimpleElementTransformHandler;
65 import org.simantics.diagram.handler.e4.CopyPasteHandler;
66 import org.simantics.diagram.layer.ILayersViewPage;
67 import org.simantics.diagram.participant.PointerInteractor2;
68 import org.simantics.diagram.participant.SGFocusParticipant;
69 import org.simantics.diagram.participant.e4.ContextUtil;
70 import org.simantics.diagram.query.DiagramRequests;
71 import org.simantics.diagram.runtime.RuntimeDiagramManager;
72 import org.simantics.diagram.stubs.DiagramResource;
73 import org.simantics.diagram.symbolcontribution.SymbolProviderFactory;
74 import org.simantics.diagram.synchronization.CopyAdvisor;
75 import org.simantics.diagram.synchronization.IModifiableSynchronizationContext;
76 import org.simantics.diagram.synchronization.SynchronizationHints;
77 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
78 import org.simantics.diagram.ui.DiagramModelHints;
79 import org.simantics.diagram.ui.SWTPopupMenuParticipant;
80 import org.simantics.diagram.ui.WorkbenchSelectionProvider;
81 import org.simantics.g2d.canvas.Hints;
82 import org.simantics.g2d.canvas.ICanvasContext;
83 import org.simantics.g2d.canvas.ICanvasParticipant;
84 import org.simantics.g2d.canvas.impl.CanvasContext;
85 import org.simantics.g2d.chassis.AWTChassis;
86 import org.simantics.g2d.chassis.ICanvasChassis;
87 import org.simantics.g2d.chassis.IChassisListener;
88 import org.simantics.g2d.chassis.SWTChassis;
89 import org.simantics.g2d.connection.IConnectionAdvisor;
90 import org.simantics.g2d.diagram.DiagramClass;
91 import org.simantics.g2d.diagram.DiagramHints;
92 import org.simantics.g2d.diagram.IDiagram;
93 import org.simantics.g2d.diagram.handler.PickRequest.PickFilter;
94 import org.simantics.g2d.diagram.impl.Diagram;
95 import org.simantics.g2d.diagram.participant.DelayedBatchElementPainter;
96 import org.simantics.g2d.diagram.participant.DiagramParticipant;
97 import org.simantics.g2d.diagram.participant.ElementInteractor;
98 import org.simantics.g2d.diagram.participant.ElementPainter;
99 import org.simantics.g2d.diagram.participant.Selection;
100 import org.simantics.g2d.diagram.participant.TerminalPainter;
101 import org.simantics.g2d.diagram.participant.ZOrderHandler;
102 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
103 import org.simantics.g2d.element.ElementClassProviders;
104 import org.simantics.g2d.element.ElementClasses;
105 import org.simantics.g2d.element.IElement;
106 import org.simantics.g2d.element.IElementClassProvider;
107 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
108 import org.simantics.g2d.elementclass.connection.ConnectionClass;
109 import org.simantics.g2d.page.DiagramDesc;
110 import org.simantics.g2d.participant.BackgroundPainter;
111 import org.simantics.g2d.participant.CanvasBoundsParticipant;
112 import org.simantics.g2d.participant.CanvasGrab;
113 import org.simantics.g2d.participant.GridPainter;
114 import org.simantics.g2d.participant.KeyUtil;
115 import org.simantics.g2d.participant.MouseUtil;
116 import org.simantics.g2d.participant.Notifications;
117 import org.simantics.g2d.participant.PageBorderParticipant;
118 import org.simantics.g2d.participant.PanZoomRotateHandler;
119 import org.simantics.g2d.participant.PointerPainter;
120 import org.simantics.g2d.participant.RenderingQualityInteractor;
121 import org.simantics.g2d.participant.RulerPainter;
122 import org.simantics.g2d.participant.SymbolUtil;
123 import org.simantics.g2d.participant.TimeParticipant;
124 import org.simantics.g2d.participant.TransformUtil;
125 import org.simantics.g2d.participant.WorkbenchStatusLine;
126 import org.simantics.g2d.participant.ZoomToAreaHandler;
127 import org.simantics.g2d.tooltip.TerminalTooltipParticipant;
128 import org.simantics.g2d.utils.CanvasUtils;
129 import org.simantics.layer0.utils.triggers.IActivation;
130 import org.simantics.layer0.utils.triggers.IActivationManager;
131 import org.simantics.modeling.ModelingResources;
132 import org.simantics.modeling.mapping.ComponentCopyAdvisor;
133 import org.simantics.modeling.mapping.ElementCopyAdvisor;
134 import org.simantics.modeling.mapping.MappedElementCopyAdvisor;
135 import org.simantics.modeling.mapping.ModelingSynchronizationHints;
136 import org.simantics.modeling.ui.diagramEditor.DiagramEditorStates;
137 import org.simantics.modeling.ui.diagramEditor.DiagramLayersPage;
138 import org.simantics.modeling.ui.diagramEditor.DiagramOutlinePage;
139 import org.simantics.modeling.ui.diagramEditor.EditorState;
140 import org.simantics.modeling.ui.diagramEditor.PopulateElementMonitorDropParticipant;
141 import org.simantics.modeling.ui.diagramEditor.handlers.e4.LinkBrowsingHandler;
142 import org.simantics.modeling.ui.diagramEditor.handlers.e4.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.structural.stubs.StructuralResource2;
150 import org.simantics.structural2.modelingRules.IModelingRules;
151 import org.simantics.ui.jobs.SessionGarbageCollectorJob;
152 import org.simantics.ui.workbench.IPropertyPage;
153 import org.simantics.ui.workbench.IResourceEditorInput;
154 import org.simantics.ui.workbench.IResourceEditorInput2;
155 import org.simantics.ui.workbench.TitleRequest;
156 import org.simantics.ui.workbench.TitleUpdater;
157 import org.simantics.ui.workbench.ToolTipRequest;
158 import org.simantics.ui.workbench.editor.input.InputValidationCombinators;
159 import org.simantics.utils.DataContainer;
160 import org.simantics.utils.datastructures.hints.HintContext;
161 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
162 import org.simantics.utils.datastructures.hints.IHintContext;
163 import org.simantics.utils.datastructures.hints.IHintContext.Key;
164 import org.simantics.utils.datastructures.hints.IHintListener;
165 import org.simantics.utils.datastructures.hints.IHintObservable;
166 import org.simantics.utils.threads.AWTThread;
167 import org.simantics.utils.threads.IThreadWorkQueue;
168 import org.simantics.utils.threads.SWTThread;
169 import org.simantics.utils.threads.ThreadUtils;
170 import org.simantics.utils.ui.ErrorLogger;
171 import org.simantics.utils.ui.ExceptionUtils;
172 import org.simantics.utils.ui.workbench.WorkbenchUtils;
174 import com.kitfox.svg.SVGCache;
177 * @author Toni Kalajainen
178 * @author Tuukka Lehtonen
180 public class DiagramViewer
181 //extends EditorPart implements IResourceEditorPart2,
182 implements ListenerSupport, IAdaptable {
184 public interface DiagramViewerHost {
185 void doSetPartName(String name);
186 void doSetTitleToolTip(String name);
189 public static final String DIAGRAMMING_CONTEXT = "org.simantics.modeling.ui.diagramming";
190 private static final String PREFERENCE_VIRTUAL_GRAPH = "preferences";
192 private static final boolean PROFILE = false;
194 ParametrizedRead<IResourceEditorInput, Boolean> INPUT_VALIDATOR =
196 InputValidationCombinators.or(
197 // Normal configuration diagrams of a model
199 InputValidationCombinators.hasURI(),
200 InputValidationCombinators.partialFunction(ModelingResources.URIs.DiagramToComposite)
202 // Configuration diagrams of a component type
204 InputValidationCombinators.hasURI(),
206 InputValidationCombinators.partialFunction(StructuralResource2.URIs.Defines),
207 InputValidationCombinators.partialFunction(ModelingResources.URIs.DiagramToComposite)
211 InputValidationCombinators.extractInputResource()
214 protected EditorState editorState;
216 protected boolean disposed = false;
217 protected IThreadWorkQueue swt;
218 protected IStatusLineManager statusLineManager;
219 protected Display display;
220 protected LocalResourceManager resourceManager;
221 protected SWTChassis c;
222 protected IDiagram sourceDiagram;
223 protected DataContainer<IDiagram> sourceDiagramContainer = new DataContainer<IDiagram>();
224 protected CanvasContext canvasContext;
225 protected ISessionContextProvider sessionContextProvider;
226 protected ISessionContext sessionContext;
227 protected Resource diagramResource;
228 protected GraphToDiagramSynchronizer synchronizer;
229 protected IActivation activation;
230 protected ContextUtil contextUtil;
231 protected SWTPopupMenuParticipant popupMenuParticipant;
233 protected DiagramPreferences diagramPreferences;
234 protected DiagramDesc diagramDesc;
235 protected GridSnapAdvisor snapAdvisor;
237 private RuntimeDiagramManager runtimeDiagramManager;
239 protected WorkbenchSelectionProvider selectionProvider;
241 public Resource getRuntime() {
242 RuntimeDiagramManager rtdm = runtimeDiagramManager;
243 return (rtdm == null) ? null : rtdm.getRuntimeDiagram();
246 public ParametrizedRead<IResourceEditorInput, Boolean> getInputValidator() {
247 return INPUT_VALIDATOR;
250 protected void addDropParticipants(ICanvasContext ctx) {
251 ctx.getDefaultHintContext().setHint(Hints.KEY_ALLOWED_DRAG_ACTIONS, DnDConstants.ACTION_COPY);
253 ctx.add(new PopulateElementDropParticipant(synchronizer, getPart()));
254 ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));
257 protected CopyPasteStrategy getCopyPasteStrategy() {
259 CopyPasteStrategy cpStrategy = Simantics.getSession().syncRequest(new PossibleAdapter<CopyPasteStrategy>(getResourceEditorInput().getResource(), CopyPasteStrategy.class));
260 if(cpStrategy != null) return cpStrategy;
261 } catch (DatabaseException e) {
263 return new DefaultCopyPasteStrategy();
266 protected CopyAdvisor getCopyAdvisor() {
268 CopyAdvisor advisor = Simantics.getSession().syncRequest(new PossibleAdapter<CopyAdvisor>(getResourceEditorInput().getResource(), CopyAdvisor.class));
269 if(advisor != null) return advisor;
270 } catch (DatabaseException e) {
272 return new MappedElementCopyAdvisor(new ElementCopyAdvisor(), new ComponentCopyAdvisor());
277 * TODO: change argument from CanvasContext to ICanvasContext
279 protected void addKeyBindingParticipants(CanvasContext ctx) {
280 //ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );
281 ctx.add(new DeleteHandler(statusLineManager));
282 ctx.add(new CopyPasteHandler(getCopyPasteStrategy(), statusLineManager).setWorkbenchSite(getPart()));
283 ctx.add(new ConnectionCommandHandler());
286 protected void addPopupmenu(ICanvasContext ctx) {
287 ctx.add(popupMenuParticipant);
290 protected void addWorkbenchSelectionProvider(ICanvasContext ctx) {
291 ctx.add(selectionProvider);
294 protected void addViewManipulationParticipants(CanvasContext ctx) {
295 ctx.add(new PanZoomRotateHandler());
296 //ctx.add(new MousePanZoomInteractor());
297 //ctx.add(new MultitouchPanZoomRotateInteractor());
298 // ctx.add( new OrientationRestorer() );
299 ctx.add(new ZoomToAreaHandler());
302 protected void addDiagramParticipants(ICanvasContext ctx) {
303 ctx.add(new ZOrderHandler());
304 ctx.add(getPointerInteractor());
305 ctx.add(new ElementInteractor());
306 ctx.add(new Selection());
307 ctx.add(new DiagramParticipant());
308 ctx.add(new ElementPainter());
309 //ctx.add(new ElementHeartbeater());
310 //ctx.add(new ZoomTransitionParticipant(TransitionFunction.SIGMOID));
311 //ctx.add(new TooltipParticipant());
312 ctx.add(new TerminalTooltipParticipant());
315 protected void addPainterParticipants(ICanvasContext ctx) {
316 ctx.add(new RenderingQualityInteractor());
317 ctx.add(new TerminalPainter(true, true, false, true));
318 ctx.add(new DelayedBatchElementPainter(PickFilter.FILTER_MONITORS, 500, TimeUnit.MILLISECONDS));
321 protected void addStructureParticipants(ICanvasContext ctx) {
322 addWorkbenchSelectionProvider(ctx);
323 // Add visual browsing capabilities for structural models
324 ctx.add(new StructuralBrowsingHandler(sessionContext, getPart(), getResourceEditorInput()));
325 ctx.add(new LinkBrowsingHandler(this, sessionContext));
329 * Override to add any diagram/canvas participants to the canvas context
330 * initialized for the editor.
334 protected void addOtherParticipants(CanvasContext ctx) {
337 public static Set<String> defaultPropertyBrowseContexts = Collections.singleton(ProjectResource.URIs.ProjectBrowseContext);
339 protected Set<String> getPropertyPageContexts() {
341 return BrowseContext.getBrowseContextClosure(Simantics.getSession(), defaultPropertyBrowseContexts);
342 } catch (DatabaseException e) {
343 ExceptionUtils.logAndShowError("Failed to load modeled browse contexts for property page, see exception for details.", e);
344 return defaultPropertyBrowseContexts;
348 protected IPropertyPage createPropertyPage(MPart part, Set<String> contexts) {
349 // #TODO Finish this when we are going to use full E4 workbench
350 // return new StandardPropertyPage(part, contexts);
354 protected String getPopupId() {
355 return "#ModelingDiagramPopup";
358 protected void getPreferences() {
359 this.diagramPreferences = DiagramPreferenceUtil.getPreferences();
362 protected void initSession() {
363 sessionContextProvider = Simantics.getSessionContextProvider();
364 sessionContext = sessionContextProvider.getSessionContext();
367 protected void readNames() {
368 String name = getResourceEditorInput().getName();
369 host.doSetPartName(name);
370 host.doSetTitleToolTip(name);
373 class ChassisListener implements IChassisListener {
375 public void chassisClosed(ICanvasChassis sender) {
376 // Prevent deadlock while disposing which using syncExec would result in.
377 final ICanvasContext ctx = canvasContext;
378 ThreadUtils.asyncExec(ctx.getThreadAccess(), new Runnable() {
382 saveEditorState(ctx);
383 ctx.getHintStack().removeKeyHintListener(GridPainter.KEY_GRID_ENABLED, canvasHintListener);
384 ctx.getHintStack().removeKeyHintListener(RulerPainter.KEY_RULER_ENABLED, canvasHintListener);
385 final AWTChassis awtChassis = c.getAWTComponent();
386 if (awtChassis != null)
387 awtChassis.setCanvasContext(null);
391 sourceDiagramContainer.set(null);
392 sourceDiagramContainer = null;
394 if (sourceDiagram != null)
395 sourceDiagram.dispose();
397 if(synchronizer != null) {
398 synchronizer.dispose();
403 if (runtimeDiagramManager != null) {
404 runtimeDiagramManager.dispose();
405 runtimeDiagramManager = null;
409 c.removeChassisListener(ChassisListener.this);
413 protected void createChassis(Composite parent) {
414 resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
415 c = new SWTChassis(parent, 0);
417 Object task = BEGIN("DV.precreateParticipants");
418 createCustomParticipants();
421 c.populate(component -> {
423 c.addChassisListener(new ChassisListener());
429 protected void beforeSetCanvasContext(ICanvasContext canvasContext2) {
433 * Invoke this only from the AWT thread.
436 protected void setCanvasContext(ICanvasContext context) {
437 // Cannot directly invoke SWTChassis.setCanvasContext only because it
438 // needs to be invoked in the SWT thread and AWTChassis.setCanvasContext in the
439 // AWT thread, but directly invoking SWTChassis.setCanvasContext would call both
440 // in the SWT thread which would cause synchronous scheduling of AWT
441 // runnables which is always a potential source of deadlocks.
442 c.getAWTComponent().setCanvasContext(canvasContext);
443 swt.asyncExec(new Runnable() {
447 // For AWT, this is a no-operation.
448 c.setCanvasContext(canvasContext);
453 public void createPartControl(Composite parent) {
454 //ProfileObserver.begin = System.nanoTime();
455 display = parent.getDisplay();
456 swt = SWTThread.getThreadAccess(display);
457 statusLineManager = WorkbenchUtils.getStatusLine(WorkbenchUtils.getActiveWorkbenchPart());
459 Object task = BEGIN("DV.initSession");
463 diagramResource = getResourceEditorInput().getResource();
467 // DiagramViewerSelectionProvider MUST be created and attached to the
470 // 2. here before returning from createPartControl
471 selectionProvider = createSelectionProvider();
474 this.runtimeDiagramManager = RuntimeDiagramManager.track(sessionContext.getSession(), diagramResource, getResourceEditorInput(), this);
476 // Create the canvas context here before finishing createPartControl
477 // to give DiagramViewerActionContributor a chance to work.
478 // The context can be created in SWT thread without scheduling
479 // to the context thread and having potential deadlocks.
480 IThreadWorkQueue thread = AWTThread.getThreadAccess();
481 this.canvasContext = new CanvasContext(thread);
482 this.canvasContext.setLocked(true);
484 task = BEGIN("DV.createChassis");
485 createChassis(parent);
487 } catch (DatabaseException e) {
488 ErrorLogger.defaultLogError(e);
495 protected WorkbenchSelectionProvider createSelectionProvider() {
496 // #TODO Finish this when we are going to use full E4 workbench
497 // return new DiagramViewerSelectionProvider(swt, getPart(), sourceDiagramContainer);
502 * A method invoked before chassis construction for creating such
503 * {@link ICanvasParticipant}s that need to be constructed in the SWT
506 * Use it for creating any such canvas participants during the viewer
507 * construction and add them to the {@link ICanvasContext} later on from
510 protected void createCustomParticipants() {
511 // #TODO Finish this when we are going to use full E4 workbench
512 // popupMenuParticipant = new SWTPopupMenuParticipant(getPart(), c, display, getPopupId());
516 * Invoke this only from the AWT thread.
518 protected void initializeCanvas() {
519 Object canvasInit = BEGIN("DV.canvasInitialization");
521 Object task = BEGIN("DV.createViewerCanvas");
522 initializeCanvasContext(canvasContext);
525 beforeSetCanvasContext(canvasContext);
526 //FullscreenUtils.addFullScreenHandler(canvasContext, s, canvasProvider);
528 // Without this all diagram participants will crash like there's no tomorrow.
529 // Just trying to keep the behavior a bit more sane in case of
530 // errors instead of flooding the console with exceptions.
531 canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, Diagram.spawnNew(DiagramClass.DEFAULT));
533 // Changes in ruler/grid activity shall be written as
534 // workspace-persistent diagram-specific preferences.
535 canvasContext.getHintStack().addKeyHintListener(GridPainter.KEY_GRID_ENABLED, canvasHintListener);
536 canvasContext.getHintStack().addKeyHintListener(RulerPainter.KEY_RULER_ENABLED, canvasHintListener);
538 task = BEGIN("DV.setCanvasContext");
539 setCanvasContext(canvasContext);
542 // Finish loading in a worker thread because it may be a time consuming
543 // process to load a large diagram and we don't want unnecessary AWT
544 // thread contention.
545 Job loadJob = new DiagramViewerLoadJob(this);
551 protected void activateUiContexts(ContextUtil util) {
552 util.activate(DIAGRAMMING_CONTEXT);
556 * @param monitor the progress monitor to use for reporting progress to the
557 * user. It is the caller's responsibility to call done() on the
558 * given monitor. Accepts <code>null</code>, indicating that no
559 * progress should be reported and that the operation cannot be
562 protected void performActivation(IProgressMonitor monitor) {
563 SubMonitor progress = SubMonitor.convert(monitor, "Activate Mapping", 100);
564 IActivationManager activationManager = sessionContext.getSession().peekService(IActivationManager.class);
565 if (activationManager != null) {
566 activation = activationManager.activate(diagramResource);
568 progress.worked(100);
571 protected void onCreated() {
577 protected void scheduleZoomToFit(IDiagram diagram) {
579 throw new IllegalStateException("diagram is null");
581 CanvasUtils.scheduleZoomToFit(swt, () -> disposed, canvasContext, diagram);
585 * Subclasses may override but should always invoke super.
588 * @param initialHints
589 * @throws DatabaseException
591 protected void fillInitialDiagramHints(Resource diagram, IHintContext initialHints) throws DatabaseException {
592 IModelingRules modelingRules = sessionContext.getSession().syncRequest(
593 DiagramRequests.getModelingRules(diagram, null));
594 if (modelingRules != null) {
595 initialHints.setHint(DiagramModelHints.KEY_MODELING_RULES, modelingRules);
596 initialHints.setHint(DiagramHints.CONNECTION_ADVISOR,
597 getConnectionAdvisor(modelingRules, sessionContext.getSession()));
600 initialHints.setHint(SynchronizationHints.COPY_ADVISOR, getCopyAdvisor());
601 initialHints.setHint(DiagramHints.KEY_USE_CONNECTION_FLAGS, Boolean.TRUE);
602 initialHints.setHint(DiagramHints.KEY_ALLOW_CONNECTION_BRANCHING, Boolean.TRUE);
603 initialHints.setHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS, Boolean.TRUE);
607 * @param monitor the progress monitor to use for reporting progress to the
608 * user. It is the caller's responsibility to call done() on the
609 * given monitor. Accepts <code>null</code>, indicating that no
610 * progress should be reported and that the operation cannot be
614 * @throws DatabaseException
616 protected IDiagram loadDiagram(IProgressMonitor monitor, final Resource r) throws DatabaseException {
617 // Pre-load modeling rules and possibly other hints too since they are
618 // needed already while loading the diagram contents.
619 IHintContext initialHints = new HintContext();
620 fillInitialDiagramHints(r, initialHints);
621 IDiagram d = loadDiagram(monitor, r, initialHints);
626 * @param monitor the progress monitor to use for reporting progress to the
627 * user. It is the caller's responsibility to call done() on the
628 * given monitor. Accepts <code>null</code>, indicating that no
629 * progress should be reported and that the operation cannot be
632 * @param initialHints
634 * @throws DatabaseException
636 protected IDiagram loadDiagram(IProgressMonitor monitor, Resource diagram, IHintContext initialHints) throws DatabaseException {
637 RuntimeDiagramManager rtdm = runtimeDiagramManager;
638 Resource runtimeDiagram = rtdm != null ? rtdm.getRuntimeDiagram() : null;
639 IDiagramLoader loader = synchronizer;
640 if (rtdm == null || runtimeDiagram == null || loader == null)
642 IDiagram d = sessionContext.getSession().syncRequest(
643 DiagramRequests.loadDiagram(monitor, getResourceEditorInput().getModel(null), diagram,
644 runtimeDiagram, null, loader, initialHints));
648 protected void beforeSetDiagram(IDiagram diagram) {
651 protected PointerInteractor getPointerInteractor() {
652 return new PointerInteractor2(true, true, true, false, true, false, synchronizer.getElementClassProvider());
655 protected IConnectionAdvisor getConnectionAdvisor(IModelingRules modelingRules, Session session) {
656 return new ModelledConnectionAdvisor(modelingRules, sessionContext.getSession());
659 protected GraphToDiagramSynchronizer createSynchronizer(final ICanvasContext ctx, final ISessionContext sessionContext) {
661 return sessionContext.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {
663 public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {
664 GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx, createElementClassProvider(graph));
665 initializeSynchronizationContext(graph, sync);
669 } catch (DatabaseException e) {
670 throw new UnsupportedOperationException("Failed to initialize data model synchronizer", e);
674 protected void initializeSynchronizationContext(ReadGraph graph, IModifiableSynchronizationContext context) {
675 context.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));
678 protected IElementClassProvider createElementClassProvider(ReadGraph graph) {
679 DiagramResource dr = DiagramResource.getInstance(graph);
680 return ElementClassProviders.mappedProvider(
681 ElementClasses.CONNECTION, ConnectionClass.CLASS.newClassWith(new StaticObjectAdapter(dr.RouteGraphConnection)),
682 ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)
686 protected SimpleElementTransformHandler getTransformHandler() {
687 return new SimpleElementTransformHandler(true, true, true);
690 public void initializeCanvasContext(CanvasContext ctx) {
691 IHintContext h = ctx.getDefaultHintContext();
693 // The canvas context should not be painted until it is ready to avoid
694 // unnecessary visual glitches.
695 h.setHint(Hints.KEY_DISABLE_PAINTING, Boolean.TRUE);
697 Object task = BEGIN("createSynchronizer");
698 this.synchronizer = createSynchronizer(ctx, sessionContext);
701 EContextService contextService = getPart().getContext().get(EContextService.class);
702 contextUtil = new ContextUtil(contextService, swt);
704 // Support & Util Participants
705 ctx.add(new TransformUtil());
706 ctx.add(new MouseUtil());
707 ctx.add(new KeyUtil());
708 ctx.add(contextUtil);
709 ctx.add(new WorkbenchStatusLine(statusLineManager));
710 ctx.add(new CanvasGrab());
711 ctx.add(new SymbolUtil());
712 ctx.add(new TimeParticipant());
713 ctx.add(new CanvasBoundsParticipant());
714 ctx.add(new Notifications());
716 ctx.add(new SGFocusParticipant(c, DIAGRAMMING_CONTEXT));
718 // Debug participant(s)
719 // ctx.add( new PointerPainter() );
720 // ctx.add( new HandPainter() );
721 h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
723 // Pan & Zoom & Rotate
724 addViewManipulationParticipants(ctx);
726 ctx.add(getTransformHandler());
727 ctx.add(new ExpandSelectionHandler(statusLineManager));
730 addKeyBindingParticipants(ctx);
732 // Grid & Ruler & Background
733 ctx.add(new GridPainter());
734 ctx.add(new RulerPainter());
735 ctx.add(new BackgroundPainter());
737 h.setHint(Hints.KEY_DISPLAY_PAGE, diagramPreferences.get(DiagramPreferences.P_DISPLAY_PAGE_SIZE));
738 h.setHint(Hints.KEY_DISPLAY_MARGINS, diagramPreferences.get(DiagramPreferences.P_DISPLAY_MARGINS));
739 ctx.add(new PageBorderParticipant());
741 // h.setHint(Hints.KEY_GRID_COLOR, new Color(0.9f, 0.9f, 0.9f));
742 // h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.LIGHT_GRAY);
743 h.setHint(Hints.KEY_GRID_COLOR, new Color(0.9f, 0.9f, 0.9f));
744 h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.WHITE);
745 h.setHint(RulerPainter.KEY_RULER_BACKGROUND_COLOR, new Color(0.9f, 0.9f, 0.9f, 0.75f));
746 h.setHint(RulerPainter.KEY_RULER_TEXT_COLOR, Color.BLACK);
748 ////// Diagram Participants //////
749 addDiagramParticipants(ctx);
750 addPainterParticipants(ctx);
752 /////// D'n'D ///////
753 addDropParticipants(ctx);
755 h.setHint(ElementPainter.KEY_SELECTION_FRAME_COLOR, Color.MAGENTA);
756 h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
758 h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 100000.0);
759 h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);
761 Double snapResolution = diagramPreferences.get(DiagramPreferences.P_SNAP_GRID_SIZE);
762 this.snapAdvisor = new GridSnapAdvisor(snapResolution);
763 h.setHint(DiagramHints.SNAP_ADVISOR, this.snapAdvisor);
764 h.setHint(GridPainter.KEY_GRID_SIZE, snapResolution);
765 h.setHint(GridPainter.KEY_GRID_ENABLED, Boolean.FALSE);
767 // Workbench selection provider
768 addStructureParticipants(ctx);
773 // Load page frame description settings
774 loadPageSettings(ctx);
776 addOtherParticipants(ctx);
778 ctx.assertParticipantDependencies();
779 ctx.setLocked(false);
782 protected void loadPageSettings(ICanvasContext ctx) {
783 DiagramDesc diagramDesc = null;
785 // load diagram page configuration
786 if (diagramResource != null) {
788 diagramDesc = sessionContext.getSession().syncRequest(DiagramRequests.getDiagramDesc(diagramResource));
789 } catch (DatabaseException e) {
790 ErrorLogger.defaultLogError(e);
794 if (diagramDesc == null) {
795 // Take page description from the preferences if nothing else is available.
796 final DiagramDesc desc = diagramDesc = diagramPreferences.getDiagramDesc();
798 // Write page configuration to graph
799 sessionContext.getSession().asyncRequest(new WriteRequest() {
801 public void perform(WriteGraph graph) throws DatabaseException {
802 CommonDBUtils.selectClusterSet(graph, diagramResource);
803 DiagramGraphUtil.setDiagramDesc(graph, diagramResource, desc);
807 ErrorLogger.defaultLogError("Failed to write default diagram page description to database, see exception for details", e);
811 setDiagramDesc(ctx, diagramDesc);
813 // Create a listener to react to page setting changes.
814 sessionContext.getSession().asyncRequest(DiagramRequests.getDiagramDesc(diagramResource),
815 new ListenerDelegate<DiagramDesc>(this) {
817 public void execute(final DiagramDesc result) {
818 if (result != null && canvasContext != null) {
819 ThreadUtils.asyncExec(canvasContext.getThreadAccess(), new Runnable() {
823 setDiagramDesc(canvasContext, result);
831 protected void setDiagramDesc(ICanvasContext ctx, DiagramDesc diagramDesc) {
832 if (diagramDesc == null)
833 throw new NullPointerException("null diagram desc");
835 if (diagramDesc.equals(this.diagramDesc))
838 this.diagramDesc = diagramDesc;
839 IHintContext hints = ctx.getDefaultHintContext();
840 hints.setHint(Hints.KEY_PAGE_DESC, diagramDesc.getPageDesc());
841 hints.setHint(Hints.KEY_DISPLAY_PAGE, diagramDesc.isPageBordersVisible());
842 hints.setHint(Hints.KEY_DISPLAY_MARGINS, diagramDesc.isMarginsVisible());
843 hints.setHint(GridPainter.KEY_GRID_ENABLED, diagramDesc.isGridVisible());
844 hints.setHint(RulerPainter.KEY_RULER_ENABLED, diagramDesc.isRulerVisible());
845 snapAdvisor.setResolution(diagramDesc.getGridSize());
846 hints.setHint(GridPainter.KEY_GRID_SIZE, diagramDesc.getGridSize());
850 * Must be invoked from the AWT thread only.
855 protected void applyEditorState(final EditorState state, final ICanvasContext ctx) {
856 final IDiagram diagram = ctx.getHintStack().getHint(DiagramHints.KEY_DIAGRAM);
858 if (state.viewTransform != null && state.viewTransform.getDeterminant() != 0) {
859 for (PanZoomRotateHandler h : ctx.getItemsByClass(PanZoomRotateHandler.class)) {
860 h.setTransform(state.viewTransform);
864 if (diagram != null) {
865 if (state.viewTransform != null)
866 diagram.removeHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT);
868 if (state.toolMode != null)
869 ctx.getDefaultHintContext().setHint(Hints.KEY_TOOL, state.toToolMode());
871 ctx.getDefaultHintContext().setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
873 final Set<IElement> selected = DiagramEditorStates.toElements(state.selection, diagram);
874 if (!selected.isEmpty()) {
875 for (Selection s : ctx.getItemsByClass(Selection.class)) {
876 s.setSelection(0, selected);
882 protected EditorState getSavedEditorState(ICanvasContext ctx) {
883 return DiagramEditorStates.toEditorState(ctx, true, true, true);
886 protected void saveEditorState(ICanvasContext ctx) {
887 DiagramEditorStates.saveEditorState(PREFERENCE_VIRTUAL_GRAPH, diagramResource, getSavedEditorState(ctx) , DiagramViewer.this);
890 private boolean firstFocus = true;
892 public void setFocus() {
898 // This is a workaround for using the symbol viewer in multi-page
899 // editors which causes the first zoom-to-fit scheduling to happen
900 // already before the controls have been laid out properly.
909 protected void firstTimeSetFocus() {
910 // [Tuukka@2010-02-11]
911 // Removed since this is actually a workaround for multi-page editors.
912 //scheduleZoomToFit();
915 public void dispose() {
916 // Deactivate all contexts here because after this the context service
917 // in question will not be available.
918 if (contextUtil != null) {
919 contextUtil.deactivateAll();
923 if (activation != null) {
924 activation.deactivate();
928 if (resourceManager != null) {
929 resourceManager.dispose();
930 resourceManager = null;
935 // protected Resource getInputResource() {
936 // return getResourceInput().getResource();
939 // public IResourceEditorInput getResourceInput() {
940 // return (IResourceEditorInput) getEditorInput();
943 // public IResourceEditorInput2 getResourceInput2() {
944 // return (IResourceEditorInput2) getEditorInput();
947 public void init(DiagramViewerHost _host, MPart part, IResourceEditorInput2 input) {
949 if (!(input instanceof IResourceEditorInput))
950 throw new RuntimeException("Invalid input: must be IResourceEditorInput");
954 setResourceEditorInput(input);
956 // Set initial part name according to the name given by IEditorInput
957 host.doSetPartName(getResourceEditorInput().getName());
959 Session session = Simantics.peekSession();
960 if (session != null) {
961 Supplier<Boolean> disposedCallback = () -> disposed;
962 Display display = part.getContext().get(Shell.class).getDisplay();
963 session.asyncRequest(
964 new TitleRequest(part.getElementId(), getResourceEditorInput()),
965 new TitleUpdater(display, host::doSetPartName, disposedCallback));
966 session.asyncRequest(
967 new ToolTipRequest(part.getElementId(), getResourceEditorInput()),
968 new TitleUpdater(display, host::doSetTitleToolTip, disposedCallback));
972 // Read previous editor state from the database
973 editorState = DiagramEditorStates.readEditorState(getResourceEditorInput().getResource());
974 } catch (DatabaseException e) {
979 @SuppressWarnings("rawtypes")
981 public Object getAdapter(Class adapter) {
982 // System.out.println("diagramViewer getAdapter " + adapter);
983 // Property view support
984 if (adapter == IPropertyPage.class)
985 return createPropertyPage(getPart(), getPropertyPageContexts());
986 // Provide symbols for the editor
987 if (adapter == SymbolProviderFactory.class) {
989 return DiagramTypeUtils.readSymbolProviderFactory(sessionContext.getSession(), diagramResource);
990 } catch (DatabaseException e) {
991 ErrorLogger.defaultLogError(getClass() + " failed to adapt to SymbolProviderFactory, see exception for details.", e);
995 // Outline view support
996 if (adapter == IContentOutlinePage.class)
997 return new DiagramOutlinePage(sessionContextProvider, getResourceEditorInput());
999 if (adapter == ILayersViewPage.class)
1000 return new DiagramLayersPage(canvasContext);
1001 // Support external steering of the diagram canvas, zooming etc.
1002 if (adapter == ICanvasContext.class)
1003 return canvasContext;
1004 // Support scene graph debugger view
1005 if (adapter == INode.class) {
1006 if (canvasContext != null) {
1007 INode node = canvasContext.getCanvasNode();
1009 return NodeUtil.getRootNode(node);
1013 // Support retrieval of the current diagram.
1014 if (adapter == IDiagram.class)
1015 return sourceDiagram;
1016 // Why is this here ??
1017 if (adapter == Session.class)
1018 return sessionContext.getSession();
1019 if(adapter == RuntimeDiagramManager.class)
1020 return runtimeDiagramManager;
1021 if (adapter == Resource.class)
1022 return getRuntime();
1023 if (adapter == ICanvasChassis.class)
1029 //-------------------------------------------------------------------------
1032 protected static Object BEGIN(String name) {
1034 //return ThreadLog.BEGIN(name);
1039 protected static void END(Object task) {
1041 //((Task) task).end();
1045 //-------------------------------------------------------------------------
1046 // implement ListenerSupport
1049 public void exception(Throwable t) {
1050 ErrorLogger.defaultLogError(t);
1054 public boolean isDisposed() {
1058 protected void collectGarbage() {
1059 SessionGarbageCollectorJob.getInstance().schedule(0);
1060 AWTThread.getThreadAccess().asyncExec(new Runnable() {
1063 //System.out.println("BEFORE CLEAR: " + SVGCache.getSVGUniverse().report());
1064 SVGCache.getSVGUniverse().clearUnreferenced();
1065 //System.out.println("AFTER CLEAR: " + SVGCache.getSVGUniverse().report());
1070 //-------------------------------------------------------------------------
1071 // Listener for certain canvas context hint changes
1073 IHintListener canvasHintListener = new HintListenerAdapter() {
1075 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
1076 if (key == GridPainter.KEY_GRID_ENABLED) {
1077 boolean v = Boolean.TRUE.equals(newValue);
1078 if (diagramDesc.isGridVisible() != v)
1079 setGlobalPreference(DiagramResource.URIs.DisplayGrid, v);
1080 } else if (key == RulerPainter.KEY_RULER_ENABLED) {
1081 boolean v = Boolean.TRUE.equals(newValue);
1082 if (diagramDesc.isRulerVisible() != v)
1083 setGlobalPreference(DiagramResource.URIs.DisplayRuler, v);
1088 private <T> void setGlobalPreference(final String preferenceURI, boolean value) {
1089 TagUtil.execute(Simantics.getSession(), PREFERENCE_VIRTUAL_GRAPH, preferenceURI, value, Simantics.getProjectResource());
1093 * --------------------------------------------------------------------
1094 * Changes related to removal of EditorPart extension from here on down
1095 * --------------------------------------------------------------------
1099 private DiagramViewerHost host;
1100 private IResourceEditorInput2 resourceEditorInput = null;
1102 public MPart getPart() {
1106 // public IEditorSite getEditorSite() {
1107 // return (IEditorSite) getSite();
1110 // public IEditorInput getEditorInput() {
1111 // return editorInput;
1114 // protected void setPartName(String partName) {
1115 //// if (compatibilityTitleListener != null) {
1116 //// removePropertyListener(compatibilityTitleListener);
1117 //// compatibilityTitleListener = null;
1120 //// super.setPartName(partName);
1123 // protected void setTitleToolTip(String toolTip) {
1124 //// toolTip = Util.safeString(toolTip);
1125 //// //Do not send changes if they are the same
1126 //// if (Util.equals(this.toolTip, toolTip)) {
1129 //// this.toolTip = toolTip;
1130 //// firePropertyChange(IWorkbenchPart.PROP_TITLE);
1133 protected void setHost(DiagramViewerHost host) {
1137 protected void setPart(MPart part) {
1141 protected void setResourceEditorInput(IResourceEditorInput2 input) {
1142 Assert.isLegal(input != null);
1143 resourceEditorInput = input;
1146 public IResourceEditorInput2 getResourceEditorInput() {
1147 return resourceEditorInput;
1150 public Composite getComposite() {