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