1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling.ui.diagramEditor;
\r
14 import java.awt.Color;
\r
15 import java.awt.datatransfer.Transferable;
\r
16 import java.awt.datatransfer.UnsupportedFlavorException;
\r
17 import java.io.IOException;
\r
19 import org.eclipse.core.runtime.IProgressMonitor;
\r
20 import org.eclipse.core.runtime.NullProgressMonitor;
\r
21 import org.eclipse.swt.widgets.Composite;
\r
22 import org.eclipse.ui.IEditorInput;
\r
23 import org.eclipse.ui.IEditorSite;
\r
24 import org.eclipse.ui.PartInitException;
\r
25 import org.eclipse.ui.contexts.IContextActivation;
\r
26 import org.eclipse.ui.contexts.IContextService;
\r
27 import org.eclipse.ui.part.EditorPart;
\r
28 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
\r
29 import org.simantics.db.ReadGraph;
\r
30 import org.simantics.db.Session;
\r
31 import org.simantics.db.common.ResourceArray;
\r
32 import org.simantics.db.exception.DatabaseException;
\r
33 import org.simantics.db.management.ISessionContext;
\r
34 import org.simantics.db.management.ISessionContextProvider;
\r
35 import org.simantics.db.request.Read;
\r
36 import org.simantics.db.service.SerialisationSupport;
\r
37 import org.simantics.diagram.adapter.DefaultConnectionClassFactory;
\r
38 import org.simantics.diagram.adapter.FlagClassFactory;
\r
39 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
\r
40 import org.simantics.diagram.handler.SimpleElementTransformHandler;
\r
41 import org.simantics.diagram.layer.ILayersViewPage;
\r
42 import org.simantics.diagram.query.DiagramRequests;
\r
43 import org.simantics.diagram.stubs.DiagramResource;
\r
44 import org.simantics.diagram.ui.DiagramModelHints;
\r
45 import org.simantics.g2d.canvas.Hints;
\r
46 import org.simantics.g2d.canvas.ICanvasContext;
\r
47 import org.simantics.g2d.canvas.impl.CanvasContext;
\r
48 import org.simantics.g2d.diagram.DiagramHints;
\r
49 import org.simantics.g2d.diagram.IDiagram;
\r
50 import org.simantics.g2d.diagram.participant.DiagramParticipant;
\r
51 import org.simantics.g2d.diagram.participant.ElementInteractor;
\r
52 import org.simantics.g2d.diagram.participant.ElementPainter;
\r
53 import org.simantics.g2d.diagram.participant.Selection;
\r
54 import org.simantics.g2d.diagram.participant.TerminalPainter;
\r
55 import org.simantics.g2d.diagram.participant.ZOrderHandler;
\r
56 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
\r
57 import org.simantics.g2d.element.ElementClassProviders;
\r
58 import org.simantics.g2d.element.ElementClasses;
\r
59 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
\r
60 import org.simantics.g2d.multileveldiagram.TransitionFunction;
\r
61 import org.simantics.g2d.multileveldiagram.ZoomTransitionParticipant;
\r
62 import org.simantics.g2d.participant.BackgroundPainter;
\r
63 import org.simantics.g2d.participant.CanvasBoundsParticipant;
\r
64 import org.simantics.g2d.participant.CanvasGrab;
\r
65 import org.simantics.g2d.participant.GridPainter;
\r
66 import org.simantics.g2d.participant.KeyToCommand;
\r
67 import org.simantics.g2d.participant.KeyUtil;
\r
68 import org.simantics.g2d.participant.MouseUtil;
\r
69 import org.simantics.g2d.participant.MultitouchPanZoomRotateInteractor;
\r
70 import org.simantics.g2d.participant.Notifications;
\r
71 import org.simantics.g2d.participant.PageBorderParticipant;
\r
72 import org.simantics.g2d.participant.PanZoomRotateHandler;
\r
73 import org.simantics.g2d.participant.PointerPainter;
\r
74 import org.simantics.g2d.participant.RulerPainter;
\r
75 import org.simantics.g2d.participant.SymbolUtil;
\r
76 import org.simantics.g2d.participant.TimeParticipant;
\r
77 import org.simantics.g2d.participant.TransformUtil;
\r
78 import org.simantics.g2d.participant.ZoomToAreaHandler;
\r
79 import org.simantics.g2d.utils.CanvasUtils;
\r
80 import org.simantics.layer0.utils.triggers.IActivation;
\r
81 import org.simantics.modeling.ModelingResources;
\r
82 import org.simantics.modeling.mapping.ModelingSynchronizationHints;
\r
83 import org.simantics.scenegraph.g2d.events.command.CommandKeyBinding;
\r
84 import org.simantics.scenegraph.g2d.events.command.Commands;
\r
85 import org.simantics.simulation.experiment.IExperiment;
\r
86 import org.simantics.ui.SimanticsUI;
\r
87 import org.simantics.ui.dnd.ResourceTransferData;
\r
88 import org.simantics.ui.dnd.ResourceTransferUtils;
\r
89 import org.simantics.ui.workbench.IResourceEditorInput;
\r
90 import org.simantics.ui.workbench.IResourceEditorInput2;
\r
91 import org.simantics.ui.workbench.IResourceEditorPart2;
\r
92 import org.simantics.ui.workbench.ResourceEditorSupport;
\r
93 import org.simantics.utils.datastructures.hints.HintContext;
\r
94 import org.simantics.utils.datastructures.hints.IHintContext;
\r
95 import org.simantics.utils.page.PageDesc;
\r
96 import org.simantics.utils.page.PageOrientation;
\r
97 import org.simantics.utils.threads.AWTThread;
\r
98 import org.simantics.utils.threads.IThreadWorkQueue;
\r
101 * @author J-P Laine
\r
103 public class WikiDiagramViewer extends EditorPart implements IResourceEditorPart2 {
\r
105 protected boolean disposed = false;
\r
106 protected IDiagram sourceDiagram;
\r
107 protected ICanvasContext canvasContext;
\r
108 protected ResourceEditorSupport support;
\r
109 protected ISessionContextProvider sessionContextProvider;
\r
110 protected ISessionContext sessionContext;
\r
111 protected GraphToDiagramSynchronizer synchronizer;
\r
112 protected IActivation activation;
\r
113 protected ResourceArray structuralPath = new ResourceArray();
\r
114 protected IContextActivation contextActivation;
\r
115 protected IExperiment experiment;
\r
116 protected String layer = null;
\r
118 public WikiDiagramViewer() {
\r
121 protected void addDropParticipants(ICanvasContext ctx) {
\r
122 // FIXME This is a workaround so that this participant can be disabled
\r
123 // for SymbolViewer
\r
124 ctx.add(new PopulateElementDropParticipant(synchronizer));
\r
125 ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));
\r
128 protected void addKeyBindingParticipants(CanvasContext ctx) {
\r
129 ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );
\r
132 public void setExperiment(IExperiment experiment) {
\r
133 sourceDiagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);
\r
136 public void init(ResourceArray structuralPath, String layer, IExperiment experiment) {
\r
137 this.experiment = experiment;
\r
138 this.layer = layer;
\r
139 this.structuralPath = structuralPath;
\r
141 sessionContextProvider = SimanticsUI.getSessionContextProvider();
\r
142 sessionContext = sessionContextProvider.getSessionContext();
\r
144 canvasContext = createViewerCanvas();
\r
147 sourceDiagram = loadDiagram(structuralPath, experiment);
\r
148 } catch (DatabaseException e) {
\r
149 e.printStackTrace();
\r
154 public void updateDiagram(ResourceArray structuralPath) {
\r
155 canvasContext = createViewerCanvas();
\r
157 IHintContext hints = new HintContext();
\r
158 hints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);
\r
159 if(layer != null) {
\r
160 System.out.println("using layer '"+layer+"'");
\r
161 hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { layer });
\r
164 sourceDiagram = sessionContext.getSession().syncRequest(DiagramRequests.loadDiagram(new NullProgressMonitor(), getResourceInput2().getModel(null), structuralPath.resources[0], null, structuralPath.removeFromBeginning(0), synchronizer, hints));
\r
165 canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, sourceDiagram);
\r
166 } catch (DatabaseException e) {
\r
167 e.printStackTrace();
\r
171 void scheduleZoomToFit() {
\r
172 if (sourceDiagram == null)
\r
173 throw new IllegalStateException("source diagram is null");
\r
175 sourceDiagram.setHint(Hints.KEY_DISABLE_PAINTING, Boolean.TRUE);
\r
176 sourceDiagram.setHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT, Boolean.TRUE);
\r
179 sourceDiagram.removeHint(Hints.KEY_DISABLE_PAINTING);
\r
180 Boolean zoomToFit = sourceDiagram.removeHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT);
\r
181 if (zoomToFit != null && zoomToFit)
\r
182 CanvasUtils.sendCommand(canvasContext, Commands.ZOOM_TO_FIT);
\r
183 canvasContext.getContentContext().setDirty();
\r
186 protected IDiagram loadDiagram(ResourceArray structuralPath, IExperiment experiment) throws DatabaseException {
\r
187 IHintContext hints = new HintContext();
\r
188 if(experiment != null)
\r
189 hints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);
\r
190 if(layer != null) {
\r
191 System.out.println("using layer '"+layer+"'");
\r
192 hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { layer });
\r
194 IDiagram d = sessionContext.getSession().syncRequest(DiagramRequests.loadDiagram(new NullProgressMonitor(), getResourceInput2().getModel(null), structuralPath.resources[0], null, structuralPath.removeFromBeginning(0), synchronizer, hints));
\r
195 canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, d);
\r
199 protected GraphToDiagramSynchronizer createSynchronizer(final ICanvasContext ctx, final ISessionContext sessionContext) {
\r
201 return sessionContext.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {
\r
203 public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {
\r
204 DiagramResource dr = DiagramResource.getInstance(graph);
\r
205 GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx,
\r
206 ElementClassProviders.mappedProvider(
\r
207 ElementClasses.CONNECTION, DefaultConnectionClassFactory.CLASS.newClassWith(new StaticObjectAdapter(dr.Connection)),
\r
208 ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)
\r
211 sync.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));
\r
215 } catch (DatabaseException e) {
\r
216 throw new UnsupportedOperationException("Failed to initialize data model synchronizer", e);
\r
220 public ICanvasContext createViewerCanvas()
\r
222 IThreadWorkQueue thread = AWTThread.getThreadAccess();
\r
223 CanvasContext ctx = new CanvasContext(thread);
\r
224 IHintContext h = ctx.getDefaultHintContext();
\r
226 this.synchronizer = createSynchronizer(ctx, sessionContext);
\r
228 canvasContext.add( new PanZoomRotateHandler() ); // Must be before TransformUtil
\r
230 // Support & Util Participants
\r
231 ctx.add( new TransformUtil() );
\r
232 ctx.add( new MouseUtil() );
\r
233 ctx.add( new KeyUtil() );
\r
234 ctx.add( new CanvasGrab() );
\r
235 ctx.add( new SymbolUtil() );
\r
236 ctx.add( new TimeParticipant() );
\r
237 ctx.add( new CanvasBoundsParticipant() );
\r
238 ctx.add( new Notifications() );
\r
240 // ctx.add( new SGFocusParticipant(c) ); // FIXME: Get chassis from somewhere
\r
242 h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
\r
244 ctx.add( new MultitouchPanZoomRotateInteractor() );
\r
245 ctx.add( new ZoomToAreaHandler() );
\r
246 ctx.add( new SimpleElementTransformHandler() );
\r
249 addKeyBindingParticipants(ctx);
\r
251 // Grid & Ruler & Background
\r
253 ctx.add( new GridPainter() );
\r
254 ctx.add( new RulerPainter() );
\r
255 ctx.add( new BackgroundPainter() );
\r
256 ctx.add( new PageBorderParticipant() );
\r
258 h.setHint(Hints.KEY_GRID_COLOR, new Color(0.95f, 0.95f, 0.95f));
\r
259 h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.WHITE);
\r
260 h.setHint(RulerPainter.KEY_RULER_BACKGROUND_COLOR, new Color(0.9f, 0.9f, 0.9f, 0.75f));
\r
261 h.setHint(RulerPainter.KEY_RULER_TEXT_COLOR, Color.BLACK);
\r
263 ////// Diagram Participants //////
\r
264 ctx.add(new PointerInteractor(true, true, true, false, true, false, synchronizer.getElementClassProvider(), null));
\r
265 ctx.add(new ElementInteractor());
\r
266 ctx.add(new Selection());
\r
267 ctx.add(new DiagramParticipant());
\r
268 ctx.add(new ElementPainter());
\r
269 ctx.add(new TerminalPainter(true, true, false, true));
\r
270 //ctx.add(new ElementHeartbeater());
\r
271 ctx.add(new ZOrderHandler());
\r
272 ctx.add(new ZoomTransitionParticipant(TransitionFunction.SIGMOID));
\r
274 /////// D'n'D ///////
\r
275 addDropParticipants(ctx);
\r
277 h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);
\r
279 h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 1000.0);
\r
280 h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);
\r
282 // Add visual browsing capabilities for structural models
\r
283 // ctx.add(new HeadlessStructuralBrowsingHandler(this, sessionContext, structuralPath));
\r
286 PageDesc pageDesc = PageDesc.DEFAULT.withOrientation(PageOrientation.Landscape);
\r
287 // TODO: load page desc from graph
\r
288 h.setHint(Hints.KEY_PAGE_DESC, pageDesc);
\r
290 ctx.assertParticipantDependencies();
\r
295 private boolean firstFocus = true;
\r
298 public void setFocus() {
\r
300 // This is a workaround for using the symbol viewer in multi-page
\r
301 // editors which causes the first zoom-to-fit scheduling to happen
\r
302 // already before the controls have been laid out properly.
\r
303 firstFocus = false;
\r
304 firstTimeSetFocus();
\r
308 protected void firstTimeSetFocus() {
\r
309 scheduleZoomToFit();
\r
313 public void dispose() {
\r
314 System.out.println("RemoteDiagramViewer.dispose()");
\r
315 if(getSite() != null) {
\r
316 IContextService contextService = (IContextService) getSite().getService(IContextService.class);
\r
317 contextService.deactivateContext(contextActivation);
\r
321 if (activation != null) {
\r
322 activation.deactivate();
\r
326 if(synchronizer != null) {
\r
327 synchronizer.dispose();
\r
328 synchronizer = null;
\r
331 if(sourceDiagram != null) {
\r
332 sourceDiagram.dispose();
\r
333 sourceDiagram = null;
\r
336 if(support != null) {
\r
344 public void doSave(IProgressMonitor monitor) {
\r
348 public void doSaveAs() {
\r
352 public void init(IEditorSite site, IEditorInput input)
\r
353 throws PartInitException {
\r
354 if (!(input instanceof IResourceEditorInput))
\r
355 throw new PartInitException("Invalid input: must be IResourceEditorInput");
\r
358 support = new ResourceEditorSupport(this);
\r
360 // Set initial part name according to the name given by IEditorInput
\r
361 setPartName(getEditorInput().getName());
\r
365 public boolean isDirty() {
\r
370 public boolean isSaveAsAllowed() {
\r
374 public static ResourceArray[] decodeToResources(Session session, Transferable tr)
\r
377 SerialisationSupport support = session.getService(SerialisationSupport.class);
\r
378 ResourceTransferData data = ResourceTransferUtils.readAwtTransferable(support, tr);
\r
379 if ("property".equals(data.getPurpose()))
\r
380 return data.toResourceArrayArray();
\r
381 } catch (UnsupportedFlavorException e) {
\r
382 throw new RuntimeException(e);
\r
383 } catch (IOException e) {
\r
384 throw new RuntimeException(e);
\r
385 } catch (IllegalArgumentException e) {
\r
386 throw new RuntimeException(e);
\r
387 } catch (DatabaseException e) {
\r
388 throw new RuntimeException(e);
\r
393 @SuppressWarnings("rawtypes")
\r
395 public Object getAdapter(Class adapter) {
\r
396 if (adapter == IContentOutlinePage.class)
\r
397 return new DiagramOutlinePage(sessionContextProvider, getResourceInput2());
\r
398 if (adapter == ILayersViewPage.class)
\r
399 return new DiagramLayersPage(sourceDiagram, canvasContext);
\r
400 if (adapter == ICanvasContext.class)
\r
401 return canvasContext;
\r
402 if (adapter == IDiagram.class)
\r
403 return sourceDiagram;
\r
404 if (adapter == Session.class)
\r
405 return sessionContext.getSession();
\r
406 return super.getAdapter(adapter);
\r
409 public ICanvasContext getCanvasContext() {
\r
410 return canvasContext;
\r
413 protected void onCreated() {
\r
417 public void createPartControl(Composite parent) {
\r
418 // TODO Auto-generated method stub
\r
423 public IResourceEditorInput2 getResourceInput2() {
\r
424 // TODO Auto-generated method stub
\r
429 public IResourceEditorInput getResourceInput() {
\r
430 // TODO Auto-generated method stub
\r