]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.views.swt/src/org/simantics/views/swt/SimanticsView.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.views.swt / src / org / simantics / views / swt / SimanticsView.java
diff --git a/bundles/org.simantics.views.swt/src/org/simantics/views/swt/SimanticsView.java b/bundles/org.simantics.views.swt/src/org/simantics/views/swt/SimanticsView.java
new file mode 100644 (file)
index 0000000..6f424c5
--- /dev/null
@@ -0,0 +1,503 @@
+/*******************************************************************************\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.views.swt;\r
+\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashSet;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.resource.JFaceResources;\r
+import org.eclipse.jface.resource.LocalResourceManager;\r
+import org.eclipse.jface.viewers.ISelectionProvider;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.dnd.DND;\r
+import org.eclipse.swt.dnd.DragSource;\r
+import org.eclipse.swt.dnd.DragSourceListener;\r
+import org.eclipse.swt.dnd.FileTransfer;\r
+import org.eclipse.swt.dnd.Transfer;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.ui.IMemento;\r
+import org.eclipse.ui.ISelectionListener;\r
+import org.eclipse.ui.IViewSite;\r
+import org.eclipse.ui.IWorkbenchSite;\r
+import org.eclipse.ui.PartInitException;\r
+import org.eclipse.ui.contexts.IContextService;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.browsing.ui.BuiltinKeys;\r
+import org.simantics.browsing.ui.Column;\r
+import org.simantics.browsing.ui.GraphExplorer;\r
+import org.simantics.browsing.ui.NodeContext;\r
+import org.simantics.browsing.ui.common.ColumnKeys;\r
+import org.simantics.browsing.ui.common.node.IDropTargetNode;\r
+import org.simantics.browsing.ui.graph.impl.GraphInputSources;\r
+import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;\r
+import org.simantics.browsing.ui.swt.ContextMenuInitializer;\r
+import org.simantics.browsing.ui.swt.DefaultKeyListener;\r
+import org.simantics.browsing.ui.swt.DefaultMouseListener;\r
+import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver;\r
+import org.simantics.browsing.ui.swt.GraphExplorerFactory;\r
+import org.simantics.browsing.ui.swt.IContextMenuInitializer;\r
+import org.simantics.browsing.ui.swt.ViewArgumentUtils;\r
+import org.simantics.browsing.ui.swt.widgets.GraphExplorerComposite;\r
+import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;\r
+import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl;\r
+import org.simantics.db.Disposable;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.db.management.ISessionContextChangedListener;\r
+import org.simantics.db.management.ISessionContextProvider;\r
+import org.simantics.db.management.SessionContextChangedEvent;\r
+import org.simantics.project.ProjectKeys;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.ui.dnd.LocalObjectTransfer;\r
+import org.simantics.ui.dnd.LocalSelectionDragSourceListener;\r
+import org.simantics.ui.dnd.NoImageDragSourceEffect;\r
+import org.simantics.ui.workbench.IPropertyPage;\r
+import org.simantics.utils.ObjectUtils;\r
+import org.simantics.utils.datastructures.Function;\r
+import org.simantics.utils.datastructures.disposable.DisposeState;\r
+import org.simantics.utils.datastructures.hints.HintContext;\r
+import org.simantics.utils.datastructures.hints.HintListenerAdapter;\r
+import org.simantics.utils.datastructures.hints.HintTracker;\r
+import org.simantics.utils.datastructures.hints.IHintContext;\r
+import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+import org.simantics.utils.datastructures.hints.IHintListener;\r
+import org.simantics.utils.datastructures.hints.IHintObservable;\r
+import org.simantics.utils.datastructures.hints.IHintTracker;\r
+import org.simantics.utils.ui.LayoutUtils;\r
+\r
+/**\r
+ * @author Antti Villberg\r
+ * @deprecated in favor of org.simantics.views.swt.ModelledView\r
+ */\r
+public abstract class SimanticsView extends ViewPart {\r
+\r
+    private final WidgetSupportImpl          widgetSupport = createSupport();\r
+\r
+    protected IHintContext                   factoryHints = new HintContext();\r
+\r
+    protected LocalResourceManager           resourceManager;\r
+\r
+    protected ISelectionListener             workbenchSelectionListener;\r
+\r
+    protected Composite                      parent;\r
+\r
+    private Map<String, String>              args;\r
+\r
+    private ISessionContextProvider          contextProvider;\r
+\r
+    private ISessionContext                  sessionContext;\r
+\r
+    protected IMemento                       memento;\r
+\r
+    private IHintTracker                     sessionContextTracker = new SessionContextProjectTracker();\r
+\r
+    private SessionContextInputSource        inputSource           = GraphInputSources.projectSource();\r
+\r
+    private DisposeState                     disposeState          = DisposeState.Alive;\r
+\r
+    protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {\r
+        @Override\r
+        public void sessionContextChanged(SessionContextChangedEvent event) {\r
+            sessionContext = event.getNewValue();\r
+            sessionContextTracker.track(sessionContext);\r
+        }\r
+    };\r
+\r
+    protected Set<String> getBrowseContexts() {\r
+        return Collections.emptySet();\r
+    }\r
+\r
+    protected WidgetSupportImpl createSupport() {\r
+        return new WidgetSupportImpl();\r
+    }\r
+    \r
+    abstract protected void createControls(Composite body, IWorkbenchSite site, ISessionContext context, WidgetSupport support);\r
+\r
+    protected void activateUiContexts() {\r
+        Collection<String> contexts = getUiContexts();\r
+        if (!contexts.isEmpty()) {\r
+            IContextService cs = (IContextService) getSite().getService(IContextService.class);\r
+            for (String context : contexts)\r
+                cs.activateContext(context);\r
+        }\r
+    }\r
+\r
+    protected Transfer[] getAcceptedDataTypes() {\r
+        return new Transfer[] {  LocalObjectTransfer.getTransfer(), FileTransfer.getInstance() };\r
+    }\r
+\r
+    protected void handleDrop(Object data, NodeContext target) {\r
+        if (target != null) {\r
+            Object input = target.getConstant(BuiltinKeys.INPUT);\r
+            //System.out.println("DROPPED " + data + " ON " + target);\r
+            if (input instanceof IDropTargetNode)\r
+                ((IDropTargetNode) input).drop(data);\r
+        }\r
+    }\r
+\r
+    protected Object createDragSource(GraphExplorer explorer) {\r
+        ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);\r
+\r
+        DragSourceListener listener = new LocalSelectionDragSourceListener(selectionProvider);\r
+\r
+        Control control = explorer.getControl();\r
+        DragSource source = new DragSource(control, DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT);\r
+        source.setTransfer(new Transfer[] {LocalObjectTransfer.getTransfer()});\r
+        source.addDragListener(listener);\r
+        source.setDragSourceEffect(new NoImageDragSourceEffect(control));\r
+\r
+        return listener;\r
+    }\r
+\r
+    /**\r
+     * @return the set of <code>org.eclipse.ui.context</code> contexts to\r
+     *         activate for this view site\r
+     */\r
+    protected Set<String> getUiContexts() {\r
+        return Collections.emptySet();\r
+    }\r
+\r
+    /**\r
+     * The default hint tracker that will be active if\r
+     * {@link SimanticsViewBase#setSessionContextTracker(IHintTracker) is\r
+     * not called.\r
+     */\r
+    public class SessionContextProjectTracker extends HintTracker {\r
+        public SessionContextProjectTracker() {\r
+            IHintListener activeProjectListener = new HintListenerAdapter() {\r
+                @Override\r
+                public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
+                    applySessionContext(getSessionContext());\r
+                }\r
+            };\r
+            addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);\r
+        }\r
+    }\r
+\r
+    protected void setSessionContextTracker(IHintTracker tracker) {\r
+        this.sessionContextTracker = tracker;\r
+    }\r
+\r
+    public void setInputSource(SessionContextInputSource source) {\r
+        this.inputSource = source;\r
+    }\r
+\r
+    protected final SessionContextInputSource getInputSource() {\r
+        return inputSource;\r
+    }\r
+\r
+    protected Map<String, String> getViewArguments() {\r
+        return args;\r
+    }\r
+\r
+    protected DisposeState getDisposeState() {\r
+        return disposeState;\r
+    }\r
+\r
+    public ISessionContext getSessionContext() {\r
+        return sessionContext;\r
+    }\r
+\r
+    public ISessionContextProvider getSessionContextProvider() {\r
+        return contextProvider;\r
+    }\r
+\r
+    @Override\r
+    public void createPartControl(Composite parent) {\r
+        this.parent = parent;\r
+        this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()));\r
+\r
+        contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());\r
+\r
+        parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false));\r
+\r
+        setWorkbenchListeners();\r
+        activateUiContexts();\r
+\r
+        createControls(parent, getSite(), getSessionContext(), widgetSupport);\r
+\r
+        attachToSession();\r
+\r
+    }\r
+\r
+    /**\r
+     * Invoked when this viewpart is disposed. Unhooks the view from its\r
+     * ISessionContextProvider. Overriding is allowed but super.dispose() must\r
+     * be called.\r
+     * \r
+     * @see org.eclipse.ui.part.WorkbenchPart#dispose()\r
+     */\r
+    @Override\r
+    public void dispose() {\r
+        removeWorkbenchListeners();\r
+        disposeState = DisposeState.Disposing;\r
+        try {\r
+            if (inputSource instanceof Disposable) {\r
+                ((Disposable) inputSource).dispose();\r
+            }\r
+            //System.out.println(this + ".GraphExplorerViewBase.dispose()");\r
+            if (contextProvider != null) {\r
+                contextProvider.removeContextChangedListener(contextChangeListener);\r
+                contextProvider = null;\r
+            }\r
+            sessionContextTracker.untrack();\r
+            resourceManager.dispose();\r
+            if (widgetSupport instanceof Disposable)\r
+                ((Disposable) widgetSupport).dispose();\r
+            resourceManager = null;\r
+            args = null;\r
+            sessionContext = null;\r
+            parent = null;\r
+            super.dispose();\r
+        } finally {\r
+            disposeState = DisposeState.Disposed;\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void setFocus() {\r
+    }\r
+\r
+    @Override\r
+    public void init(IViewSite site) throws PartInitException {\r
+        super.init(site);\r
+        this.args = ViewArgumentUtils.parseViewArguments(this);\r
+    }\r
+\r
+    @Override\r
+    public void init(IViewSite site, IMemento memento) throws PartInitException {\r
+        super.init(site, memento);\r
+        this.args = ViewArgumentUtils.parseViewArguments(this);\r
+        this.memento = memento;\r
+    }\r
+\r
+    @Override\r
+    public void saveState(IMemento memento) {\r
+        if (this.memento != null) {\r
+            memento.putMemento(this.memento);\r
+        }\r
+//        if (explorer != null)\r
+//            explorer.saveState(memento);\r
+    }\r
+\r
+    protected void setWorkbenchListeners() {\r
+        if (workbenchSelectionListener == null) {\r
+\r
+//            ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);\r
+//            getSite().setSelectionProvider(selectionProvider);\r
+\r
+            // Listen to the workbench selection also to propagate it to\r
+            // the explorer also.\r
+//            workbenchSelectionListener = new DefaultExplorerSelectionListener(this, explorer);\r
+//            getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener);\r
+        }\r
+    }\r
+\r
+    protected void removeWorkbenchListeners() {\r
+        // Remember to remove the installed workbench selection listener\r
+        if (workbenchSelectionListener != null) {\r
+            getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener);\r
+            workbenchSelectionListener = null;\r
+\r
+            getSite().setSelectionProvider(null);\r
+        }\r
+    }\r
+\r
+    protected final void attachToSession() {\r
+        // Track active ISessionContext changes\r
+        //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());\r
+        contextProvider.addContextChangedListener(contextChangeListener);\r
+\r
+        // Start tracking the current session context for input changes.\r
+        // This will/must cause applySessionContext to get called.\r
+        // Doing the applySessionContext initialization this way\r
+        // instead of directly calling it will also make sure that\r
+        // applySessionContext is only called once when first initialized,\r
+        // and not twice like with the direct invocation.\r
+        this.sessionContext = contextProvider.getSessionContext();\r
+        sessionContextTracker.track(sessionContext);\r
+    }\r
+\r
+    // /////////////////////////////////////////////////////////////////////////\r
+    // Override / implement these:\r
+\r
+    protected Column[] getColumns() {\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * Override this method to add controls to the view part. This is invoked\r
+     * before attaching the view part to a database session.\r
+     * \r
+     * @param parent\r
+     */\r
+    protected void createControls(Composite parent) {\r
+\r
+        parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false));\r
+\r
+    }\r
+\r
+    /**\r
+     * Override this method and provide a proper context menu initializer if you\r
+     * want to have this base class initialize one for you.\r
+     * \r
+     * @return the initializer to be used by {@link #createControls(Composite)}\r
+     */\r
+    protected IContextMenuInitializer getContextMenuInitializer() {\r
+        String contextMenuId = getContextMenuId();\r
+        if(contextMenuId != null) {\r
+            return new ContextMenuInitializer(contextMenuId);\r
+        } else {\r
+            return null;\r
+        }\r
+    }\r
+\r
+    protected String getContextMenuId() {\r
+        return null;\r
+    }\r
+\r
+    protected int getStyle() {\r
+        return SWT.MULTI;\r
+    }\r
+\r
+    /**\r
+     * @param parent\r
+     * @return\r
+     */\r
+    protected GraphExplorer createExplorerControl(Composite parent) {\r
+        return GraphExplorerFactory.getInstance()\r
+        .selectionDataResolver(new DefaultSelectionDataResolver())\r
+        .create(parent, getStyle());\r
+    }\r
+\r
+    /**\r
+     * Override to customize the addition of listeners a newly created\r
+     * GraphExplorer.\r
+     * \r
+     * @param explorer\r
+     */\r
+    protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {\r
+        addSelectionInputListeners(explorer, menuManager);\r
+    }\r
+\r
+    protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {\r
+        // Consider ENTER presses to simulate mouse left button double clicks\r
+        explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function<String[]>() {\r
+            @Override\r
+            public String[] execute(Object... obj) {\r
+                return new String[] { getEditingColumn((NodeContext) obj[0]) };\r
+            }\r
+        }));\r
+        // Default double click handling\r
+        explorer.addListener(new DefaultMouseListener(explorer));\r
+    }\r
+\r
+    protected String getEditingColumn(NodeContext context) {\r
+        return ColumnKeys.SINGLE;\r
+    }\r
+\r
+    // Needed for preventing unnecessary re-initialization of the explorer with the same input.\r
+    private Object currentInput;\r
+\r
+    protected boolean isImportantInput(Object previousInput, Object input) {\r
+        return !ObjectUtils.objectEquals(previousInput, input);\r
+    }\r
+\r
+    /**\r
+     * Invoke this to reinitialize the explorer and reset its input. The input\r
+     * will be resolved from the specified ISessionContext based on the\r
+     * {@link SessionContextInputSource} that is currently in use. If the input\r
+     * is identical to the previous input, nothing will be done.\r
+     * \r
+     * @param context\r
+     */\r
+    protected final boolean applySessionContext(ISessionContext context) {\r
+        // If control is not alive anymore, do nothing.\r
+        //System.out.println(this + "(SimanticsView).applySessionContext(context=" + context + ")");\r
+        if (disposeState != DisposeState.Alive)\r
+            return false;\r
+        \r
+        if(this.sessionContext == null && context == null)\r
+            return false;\r
+\r
+        this.sessionContext = context;\r
+        Object input = getInputSource().get(context);\r
+        //System.out.println(this + "(SimanticsView).applySessionContext(input=" + input + ")");\r
+        if (!isImportantInput(currentInput, input))\r
+            return false;\r
+\r
+//        System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");\r
+//        initializeExplorer(explorer, context);\r
+//        System.out.println(this + ": setRoot(" + input + ")");\r
+//        explorer.setRoot(input);\r
+\r
+        currentInput = input;\r
+        //System.out.println(this + "(SimanticsView).applySessionContext(new input=" + currentInput + ")");\r
+\r
+        widgetSupport.fireInput(context, input);\r
+\r
+        // Start tracking the session context.\r
+        //\r
+        // If this is not the same session that is currently tracked, it will\r
+        // cause IHintListeners of the sessionContextTracker to fire.\r
+        // For this we need the above input equality (identity) checking.\r
+        // This is here just to make sure that we are tracking the correct\r
+        // session context.\r
+        sessionContextTracker.track(sessionContext);\r
+\r
+        return true;\r
+    }\r
+    \r
+    @SuppressWarnings("unchecked")\r
+    <T extends Control> void searchControl(Control control, Class<T> c, Set<T> result) {\r
+       if(c.isInstance(control))\r
+               result.add((T)control);\r
+       if(control instanceof Composite) {\r
+               for(Control child : ((Composite)control).getChildren()) {\r
+                       searchControl(child, c, result);\r
+               }\r
+       }\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public <T> T getAdapter(Class<T> adapter) {\r
+\r
+        if(ISessionContextProvider.class == adapter)\r
+            return (T) getSessionContextProvider();\r
+        else if(IPropertyPage.class == adapter)\r
+            return (T) getPropertyPage();\r
+        else if(GraphExplorer.class == adapter) {\r
+               Set<GraphExplorerComposite> composites = new HashSet<>();\r
+               searchControl(parent, GraphExplorerComposite.class, composites);\r
+               if(composites.size() == 1) {\r
+                       GraphExplorerComposite gec = composites.iterator().next(); \r
+                       return (T) gec.getExplorer();\r
+               }\r
+               return null;\r
+        }\r
+\r
+        return super.getAdapter(adapter);\r
+\r
+    }\r
+\r
+    abstract protected IPropertyPage getPropertyPage();\r
+    \r
+//    protected IPropertyPage getPropertyPage() {\r
+//        return new StandardPropertyPage(getSite(), getBrowseContexts());\r
+//    }\r
+\r
+}\r