--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.modeling.ui.diagramEditor;\r
+\r
+import java.awt.Color;\r
+import java.awt.datatransfer.Transferable;\r
+import java.awt.datatransfer.UnsupportedFlavorException;\r
+import java.io.IOException;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.NullProgressMonitor;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.ui.IEditorInput;\r
+import org.eclipse.ui.IEditorSite;\r
+import org.eclipse.ui.PartInitException;\r
+import org.eclipse.ui.contexts.IContextActivation;\r
+import org.eclipse.ui.contexts.IContextService;\r
+import org.eclipse.ui.part.EditorPart;\r
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.common.ResourceArray;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.db.management.ISessionContextProvider;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.diagram.adapter.DefaultConnectionClassFactory;\r
+import org.simantics.diagram.adapter.FlagClassFactory;\r
+import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;\r
+import org.simantics.diagram.handler.SimpleElementTransformHandler;\r
+import org.simantics.diagram.layer.ILayersViewPage;\r
+import org.simantics.diagram.query.DiagramRequests;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.diagram.ui.DiagramModelHints;\r
+import org.simantics.g2d.canvas.Hints;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.canvas.impl.CanvasContext;\r
+import org.simantics.g2d.diagram.DiagramHints;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.participant.DiagramParticipant;\r
+import org.simantics.g2d.diagram.participant.ElementInteractor;\r
+import org.simantics.g2d.diagram.participant.ElementPainter;\r
+import org.simantics.g2d.diagram.participant.Selection;\r
+import org.simantics.g2d.diagram.participant.TerminalPainter;\r
+import org.simantics.g2d.diagram.participant.ZOrderHandler;\r
+import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;\r
+import org.simantics.g2d.element.ElementClassProviders;\r
+import org.simantics.g2d.element.ElementClasses;\r
+import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;\r
+import org.simantics.g2d.multileveldiagram.TransitionFunction;\r
+import org.simantics.g2d.multileveldiagram.ZoomTransitionParticipant;\r
+import org.simantics.g2d.participant.BackgroundPainter;\r
+import org.simantics.g2d.participant.CanvasBoundsParticipant;\r
+import org.simantics.g2d.participant.CanvasGrab;\r
+import org.simantics.g2d.participant.GridPainter;\r
+import org.simantics.g2d.participant.KeyToCommand;\r
+import org.simantics.g2d.participant.KeyUtil;\r
+import org.simantics.g2d.participant.MouseUtil;\r
+import org.simantics.g2d.participant.MultitouchPanZoomRotateInteractor;\r
+import org.simantics.g2d.participant.Notifications;\r
+import org.simantics.g2d.participant.PageBorderParticipant;\r
+import org.simantics.g2d.participant.PanZoomRotateHandler;\r
+import org.simantics.g2d.participant.PointerPainter;\r
+import org.simantics.g2d.participant.RulerPainter;\r
+import org.simantics.g2d.participant.SymbolUtil;\r
+import org.simantics.g2d.participant.TimeParticipant;\r
+import org.simantics.g2d.participant.TransformUtil;\r
+import org.simantics.g2d.participant.ZoomToAreaHandler;\r
+import org.simantics.g2d.utils.CanvasUtils;\r
+import org.simantics.layer0.utils.triggers.IActivation;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.modeling.mapping.ModelingSynchronizationHints;\r
+import org.simantics.scenegraph.g2d.events.command.CommandKeyBinding;\r
+import org.simantics.scenegraph.g2d.events.command.Commands;\r
+import org.simantics.simulation.experiment.IExperiment;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.ui.dnd.ResourceTransferData;\r
+import org.simantics.ui.dnd.ResourceTransferUtils;\r
+import org.simantics.ui.workbench.IResourceEditorInput;\r
+import org.simantics.ui.workbench.IResourceEditorInput2;\r
+import org.simantics.ui.workbench.IResourceEditorPart2;\r
+import org.simantics.ui.workbench.ResourceEditorSupport;\r
+import org.simantics.utils.datastructures.hints.HintContext;\r
+import org.simantics.utils.datastructures.hints.IHintContext;\r
+import org.simantics.utils.page.PageDesc;\r
+import org.simantics.utils.page.PageOrientation;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.IThreadWorkQueue;\r
+\r
+/**\r
+ * @author J-P Laine\r
+ */\r
+public class WikiDiagramViewer extends EditorPart implements IResourceEditorPart2 {\r
+\r
+ protected boolean disposed = false;\r
+ protected IDiagram sourceDiagram;\r
+ protected ICanvasContext canvasContext;\r
+ protected ResourceEditorSupport support;\r
+ protected ISessionContextProvider sessionContextProvider;\r
+ protected ISessionContext sessionContext;\r
+ protected GraphToDiagramSynchronizer synchronizer;\r
+ protected IActivation activation;\r
+ protected ResourceArray structuralPath = new ResourceArray();\r
+ protected IContextActivation contextActivation;\r
+ protected IExperiment experiment;\r
+ protected String layer = null;\r
+\r
+ public WikiDiagramViewer() {\r
+ }\r
+\r
+ protected void addDropParticipants(ICanvasContext ctx) {\r
+ // FIXME This is a workaround so that this participant can be disabled\r
+ // for SymbolViewer\r
+ ctx.add(new PopulateElementDropParticipant(synchronizer));\r
+ ctx.add(new PopulateElementMonitorDropParticipant(synchronizer, 0.5, 0.5));\r
+ }\r
+\r
+ protected void addKeyBindingParticipants(CanvasContext ctx) {\r
+ ctx.add( new KeyToCommand( CommandKeyBinding.DEFAULT_BINDINGS ) );\r
+ }\r
+\r
+ public void setExperiment(IExperiment experiment) {\r
+ sourceDiagram.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);\r
+ }\r
+\r
+ public void init(ResourceArray structuralPath, String layer, IExperiment experiment) {\r
+ this.experiment = experiment;\r
+ this.layer = layer;\r
+ this.structuralPath = structuralPath;\r
+\r
+ sessionContextProvider = SimanticsUI.getSessionContextProvider();\r
+ sessionContext = sessionContextProvider.getSessionContext();\r
+\r
+ canvasContext = createViewerCanvas();\r
+\r
+ try {\r
+ sourceDiagram = loadDiagram(structuralPath, experiment);\r
+ } catch (DatabaseException e) {\r
+ e.printStackTrace();\r
+ }\r
+ onCreated();\r
+ }\r
+\r
+ public void updateDiagram(ResourceArray structuralPath) {\r
+ canvasContext = createViewerCanvas();\r
+ try {\r
+ IHintContext hints = new HintContext();\r
+ hints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);\r
+ if(layer != null) {\r
+ System.out.println("using layer '"+layer+"'");\r
+ hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { layer });\r
+ }\r
+\r
+ sourceDiagram = sessionContext.getSession().syncRequest(DiagramRequests.loadDiagram(new NullProgressMonitor(), getResourceInput2().getModel(null), structuralPath.resources[0], null, structuralPath.removeFromBeginning(0), synchronizer, hints));\r
+ canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, sourceDiagram);\r
+ } catch (DatabaseException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ void scheduleZoomToFit() {\r
+ if (sourceDiagram == null)\r
+ throw new IllegalStateException("source diagram is null");\r
+\r
+ sourceDiagram.setHint(Hints.KEY_DISABLE_PAINTING, Boolean.TRUE);\r
+ sourceDiagram.setHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT, Boolean.TRUE);\r
+\r
+ // zoom-to-fit\r
+ sourceDiagram.removeHint(Hints.KEY_DISABLE_PAINTING);\r
+ Boolean zoomToFit = sourceDiagram.removeHint(DiagramHints.KEY_INITIAL_ZOOM_TO_FIT);\r
+ if (zoomToFit != null && zoomToFit)\r
+ CanvasUtils.sendCommand(canvasContext, Commands.ZOOM_TO_FIT);\r
+ canvasContext.getContentContext().setDirty();\r
+ }\r
+\r
+ protected IDiagram loadDiagram(ResourceArray structuralPath, IExperiment experiment) throws DatabaseException {\r
+ IHintContext hints = new HintContext();\r
+ if(experiment != null)\r
+ hints.setHint(DiagramModelHints.KEY_ACTIVE_EXPERIMENT, experiment);\r
+ if(layer != null) {\r
+ System.out.println("using layer '"+layer+"'");\r
+ hints.setHint(DiagramHints.KEY_FIXED_LAYERS, new String[] { layer });\r
+ }\r
+ IDiagram d = sessionContext.getSession().syncRequest(DiagramRequests.loadDiagram(new NullProgressMonitor(), getResourceInput2().getModel(null), structuralPath.resources[0], null, structuralPath.removeFromBeginning(0), synchronizer, hints));\r
+ canvasContext.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, d);\r
+ return d;\r
+ }\r
+\r
+ protected GraphToDiagramSynchronizer createSynchronizer(final ICanvasContext ctx, final ISessionContext sessionContext) {\r
+ try {\r
+ return sessionContext.getSession().syncRequest(new Read<GraphToDiagramSynchronizer>() {\r
+ @Override\r
+ public GraphToDiagramSynchronizer perform(ReadGraph graph) throws DatabaseException {\r
+ DiagramResource dr = DiagramResource.getInstance(graph);\r
+ GraphToDiagramSynchronizer sync = new GraphToDiagramSynchronizer(graph, ctx,\r
+ ElementClassProviders.mappedProvider(\r
+ ElementClasses.CONNECTION, DefaultConnectionClassFactory.CLASS.newClassWith(new StaticObjectAdapter(dr.Connection)),\r
+ ElementClasses.FLAG, FlagClassFactory.createFlagClass(dr.Flag, dr.Flag_Terminal)\r
+ )\r
+ );\r
+ sync.set(ModelingSynchronizationHints.MODELING_RESOURCE, ModelingResources.getInstance(graph));\r
+ return sync;\r
+ }\r
+ });\r
+ } catch (DatabaseException e) {\r
+ throw new UnsupportedOperationException("Failed to initialize data model synchronizer", e);\r
+ }\r
+ }\r
+\r
+ public ICanvasContext createViewerCanvas()\r
+ {\r
+ IThreadWorkQueue thread = AWTThread.getThreadAccess();\r
+ CanvasContext ctx = new CanvasContext(thread);\r
+ IHintContext h = ctx.getDefaultHintContext();\r
+\r
+ this.synchronizer = createSynchronizer(ctx, sessionContext);\r
+\r
+ canvasContext.add( new PanZoomRotateHandler() ); // Must be before TransformUtil\r
+\r
+ // Support & Util Participants\r
+ ctx.add( new TransformUtil() );\r
+ ctx.add( new MouseUtil() );\r
+ ctx.add( new KeyUtil() );\r
+ ctx.add( new CanvasGrab() );\r
+ ctx.add( new SymbolUtil() );\r
+ ctx.add( new TimeParticipant() );\r
+ ctx.add( new CanvasBoundsParticipant() );\r
+ ctx.add( new Notifications() );\r
+\r
+// ctx.add( new SGFocusParticipant(c) ); // FIXME: Get chassis from somewhere\r
+\r
+ h.setHint(PointerPainter.KEY_PAINT_POINTER, true);\r
+\r
+ ctx.add( new MultitouchPanZoomRotateInteractor() );\r
+ ctx.add( new ZoomToAreaHandler() );\r
+ ctx.add( new SimpleElementTransformHandler() );\r
+\r
+ // Key bindings\r
+ addKeyBindingParticipants(ctx);\r
+\r
+ // Grid & Ruler & Background\r
+\r
+ ctx.add( new GridPainter() );\r
+ ctx.add( new RulerPainter() );\r
+ ctx.add( new BackgroundPainter() );\r
+ ctx.add( new PageBorderParticipant() );\r
+\r
+ h.setHint(Hints.KEY_GRID_COLOR, new Color(0.95f, 0.95f, 0.95f));\r
+ h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.WHITE);\r
+ h.setHint(RulerPainter.KEY_RULER_BACKGROUND_COLOR, new Color(0.9f, 0.9f, 0.9f, 0.75f));\r
+ h.setHint(RulerPainter.KEY_RULER_TEXT_COLOR, Color.BLACK);\r
+\r
+ ////// Diagram Participants //////\r
+ ctx.add(new PointerInteractor(true, true, true, false, true, false, synchronizer.getElementClassProvider(), null));\r
+ ctx.add(new ElementInteractor());\r
+ ctx.add(new Selection());\r
+ ctx.add(new DiagramParticipant());\r
+ ctx.add(new ElementPainter());\r
+ ctx.add(new TerminalPainter(true, true, false, true));\r
+ //ctx.add(new ElementHeartbeater());\r
+ ctx.add(new ZOrderHandler());\r
+ ctx.add(new ZoomTransitionParticipant(TransitionFunction.SIGMOID));\r
+\r
+ /////// D'n'D ///////\r
+ addDropParticipants(ctx);\r
+\r
+ h.setHint(Hints.KEY_TOOL, Hints.POINTERTOOL);\r
+\r
+ h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 1000.0);\r
+ h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 10.0);\r
+\r
+ // Add visual browsing capabilities for structural models\r
+// ctx.add(new HeadlessStructuralBrowsingHandler(this, sessionContext, structuralPath));\r
+\r
+ // Page settings\r
+ PageDesc pageDesc = PageDesc.DEFAULT.withOrientation(PageOrientation.Landscape);\r
+ // TODO: load page desc from graph\r
+ h.setHint(Hints.KEY_PAGE_DESC, pageDesc);\r
+\r
+ ctx.assertParticipantDependencies();\r
+\r
+ return ctx;\r
+ }\r
+\r
+ private boolean firstFocus = true;\r
+\r
+ @Override\r
+ public void setFocus() {\r
+ if (firstFocus) {\r
+ // This is a workaround for using the symbol viewer in multi-page\r
+ // editors which causes the first zoom-to-fit scheduling to happen\r
+ // already before the controls have been laid out properly.\r
+ firstFocus = false;\r
+ firstTimeSetFocus();\r
+ }\r
+ }\r
+\r
+ protected void firstTimeSetFocus() {\r
+ scheduleZoomToFit();\r
+ }\r
+\r
+ @Override\r
+ public void dispose() {\r
+ System.out.println("RemoteDiagramViewer.dispose()");\r
+ if(getSite() != null) {\r
+ IContextService contextService = (IContextService) getSite().getService(IContextService.class);\r
+ contextService.deactivateContext(contextActivation);\r
+ }\r
+\r
+ disposed = true;\r
+ if (activation != null) {\r
+ activation.deactivate();\r
+ activation = null;\r
+ }\r
+\r
+ if(synchronizer != null) {\r
+ synchronizer.dispose();\r
+ synchronizer = null;\r
+ }\r
+\r
+ if(sourceDiagram != null) {\r
+ sourceDiagram.dispose();\r
+ sourceDiagram = null;\r
+ }\r
+\r
+ if(support != null) {\r
+ support.dispose();\r
+ support = null;\r
+ }\r
+ super.dispose();\r
+ }\r
+\r
+ @Override\r
+ public void doSave(IProgressMonitor monitor) {\r
+ }\r
+\r
+ @Override\r
+ public void doSaveAs() {\r
+ }\r
+\r
+ @Override\r
+ public void init(IEditorSite site, IEditorInput input)\r
+ throws PartInitException {\r
+ if (!(input instanceof IResourceEditorInput))\r
+ throw new PartInitException("Invalid input: must be IResourceEditorInput");\r
+ setSite(site);\r
+ setInput(input);\r
+ support = new ResourceEditorSupport(this);\r
+\r
+ // Set initial part name according to the name given by IEditorInput\r
+ setPartName(getEditorInput().getName());\r
+ }\r
+\r
+ @Override\r
+ public boolean isDirty() {\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public boolean isSaveAsAllowed() {\r
+ return false;\r
+ }\r
+\r
+ public static ResourceArray[] decodeToResources(Session session, Transferable tr)\r
+ {\r
+ try {\r
+ SerialisationSupport support = session.getService(SerialisationSupport.class);\r
+ ResourceTransferData data = ResourceTransferUtils.readAwtTransferable(support, tr);\r
+ if ("property".equals(data.getPurpose()))\r
+ return data.toResourceArrayArray();\r
+ } catch (UnsupportedFlavorException e) {\r
+ throw new RuntimeException(e);\r
+ } catch (IOException e) {\r
+ throw new RuntimeException(e);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new RuntimeException(e);\r
+ } catch (DatabaseException e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+ return null;\r
+ }\r
+\r
+ @SuppressWarnings("rawtypes")\r
+ @Override\r
+ public Object getAdapter(Class adapter) {\r
+ if (adapter == IContentOutlinePage.class)\r
+ return new DiagramOutlinePage(sessionContextProvider, getResourceInput2());\r
+ if (adapter == ILayersViewPage.class)\r
+ return new DiagramLayersPage(sourceDiagram, canvasContext);\r
+ if (adapter == ICanvasContext.class)\r
+ return canvasContext;\r
+ if (adapter == IDiagram.class)\r
+ return sourceDiagram;\r
+ if (adapter == Session.class)\r
+ return sessionContext.getSession();\r
+ return super.getAdapter(adapter);\r
+ }\r
+\r
+ public ICanvasContext getCanvasContext() {\r
+ return canvasContext;\r
+ }\r
+\r
+ protected void onCreated() {\r
+ }\r
+\r
+ @Override\r
+ public void createPartControl(Composite parent) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public IResourceEditorInput2 getResourceInput2() {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public IResourceEditorInput getResourceInput() {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+}\r