]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.team.ui/src/org/simantics/team/ui/StagingView.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.team.ui / src / org / simantics / team / ui / StagingView.java
diff --git a/bundles/org.simantics.team.ui/src/org/simantics/team/ui/StagingView.java b/bundles/org.simantics.team.ui/src/org/simantics/team/ui/StagingView.java
new file mode 100644 (file)
index 0000000..231d54d
--- /dev/null
@@ -0,0 +1,550 @@
+/*******************************************************************************\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.team.ui;\r
+\r
+import java.util.Map;\r
+import java.util.Vector;\r
+\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.layout.TreeColumnLayout;\r
+import org.eclipse.jface.resource.JFaceResources;\r
+import org.eclipse.jface.resource.LocalResourceManager;\r
+import org.eclipse.jface.viewers.ColumnLabelProvider;\r
+import org.eclipse.jface.viewers.ColumnWeightData;\r
+import org.eclipse.jface.viewers.ITreeContentProvider;\r
+import org.eclipse.jface.viewers.LabelProvider;\r
+import org.eclipse.jface.viewers.TreeViewer;\r
+import org.eclipse.jface.viewers.TreeViewerColumn;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.jface.viewers.ViewerCell;\r
+import org.eclipse.jface.viewers.ViewerFilter;\r
+import org.eclipse.jface.window.ToolTip;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.swt.widgets.Tree;\r
+import org.eclipse.ui.IMemento;\r
+import org.eclipse.ui.IViewSite;\r
+import org.eclipse.ui.PartInitException;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.browsing.ui.GraphExplorer;\r
+import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;\r
+import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver;\r
+import org.simantics.browsing.ui.swt.GraphExplorerFactory;\r
+import org.simantics.browsing.ui.swt.ViewArgumentUtils;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.exception.DatabaseException;\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.db.service.TeamSupport;\r
+import org.simantics.project.ProjectKeys;\r
+import org.simantics.team.Utils;\r
+import org.simantics.team.internal.Images;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.utils.datastructures.disposable.DisposeState;\r
+import org.simantics.utils.datastructures.hints.HintListenerAdapter;\r
+import org.simantics.utils.datastructures.hints.HintTracker;\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 Kalle Kondelin\r
+ */\r
+public class StagingView extends ViewPart {\r
+\r
+    public StagingView() {\r
+    }\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 LocalResourceManager resourceManager;\r
+    protected Composite parent;\r
+    protected TreeViewer treeViewer;\r
+    private Map<String, String> args;\r
+    private ISessionContextProvider contextProvider;\r
+    private ISessionContext sessionContext;\r
+    protected IMemento memento;\r
+    private IHintTracker sessionContextTracker = new SessionContextProjectTracker();\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 void setSessionContextTracker(IHintTracker tracker) {\r
+        this.sessionContextTracker = tracker;\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.treeViewer = new TreeViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION);\r
+        this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), treeViewer.getTree());\r
+        Images.getInstance(JFaceResources.getResources());\r
+        TreeColumnLayout ad = new TreeColumnLayout();\r
+        parent.setLayout(ad);\r
+        treeViewer.getTree().setHeaderVisible(true);\r
+        TreeViewerColumn nameColumn = new TreeViewerColumn(treeViewer, SWT.LEFT);\r
+        nameColumn.getColumn().setText("Comment");\r
+        nameColumn.getColumn().setWidth(200);\r
+//        TreeViewerColumn typeColumn = new TreeViewerColumn(treeViewer, SWT.LEFT);\r
+\r
+        nameColumn.setLabelProvider(new MyColumnLabelProvider());\r
+//        typeColumn.setLabelProvider(new MyColumnLabelProvider());\r
+\r
+        ad.setColumnData(nameColumn.getColumn(), new ColumnWeightData(80, 100));\r
+//        typeColumn.getColumn().setText("Comment");\r
+//        typeColumn.getColumn().setWidth(20);\r
+//        ad.setColumnData(typeColumn.getColumn(), new ColumnWeightData(20, 120));\r
+\r
+        createControls(parent);\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
+        disposeState = DisposeState.Disposing;\r
+        try {\r
+            if (contextProvider != null) {\r
+                contextProvider.removeContextChangedListener(contextChangeListener);\r
+                contextProvider = null;\r
+            }\r
+            sessionContextTracker.untrack();\r
+            resourceManager.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
+\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
+    }\r
+\r
+    protected final void attachToSession() {\r
+        // Track active ISessionContext changes\r
+        contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());\r
+        contextProvider.addContextChangedListener(contextChangeListener);\r
+\r
+        // Perform first-time initialization of the explorer and its input.\r
+        applySessionContext(contextProvider.getSessionContext());\r
+    }\r
+\r
+    private abstract class NameAndDescriptionToolTip extends ToolTip {\r
+        public NameAndDescriptionToolTip(Control control, int style) {\r
+            super(control, style, false);\r
+        }\r
+\r
+        protected abstract Object getModelElement(Event event);\r
+\r
+        /**\r
+         * Adds logic to only show a tooltip if a meaningful item is under the cursor.\r
+         */\r
+        @Override\r
+        protected boolean shouldCreateToolTip(Event event) {\r
+            if (!super.shouldCreateToolTip(event))\r
+                return false;\r
+            Object tableElement = getModelElement(event);\r
+            return tableElement != null && tableElement instanceof DisplayElement;\r
+        }\r
+\r
+        @Override\r
+        protected Composite createToolTipContentArea(Event event, Composite parent) {\r
+            Object modelElement = getModelElement(event);\r
+\r
+            Image iconImage = null;\r
+            String nameString = "no name";\r
+\r
+            if (modelElement instanceof DisplayElement) {\r
+                iconImage = null;\r
+                nameString = "name";\r
+            }\r
+\r
+            // Create the content area\r
+            Composite composite = new Composite(parent, SWT.NONE);\r
+            composite.setBackground(parent.getDisplay().getSystemColor(\r
+                    SWT.COLOR_INFO_BACKGROUND));\r
+            composite.setLayout(new GridLayout(2, false));\r
+\r
+            // The title area with the icon (if there is one) and label.\r
+            Label title = createEntry(composite, iconImage, nameString);\r
+//            title.setFont(tooltipHeading);\r
+            GridDataFactory.createFrom((GridData)title.getLayoutData())\r
+                .hint(SWT.DEFAULT, SWT.DEFAULT)\r
+//                .minSize(MIN_TOOLTIP_WIDTH, 1)\r
+                .applyTo(title);\r
+\r
+            // The description (if there is one)\r
+//            String descriptionString = "description";\r
+//            if (descriptionString != null)\r
+//                createEntry(composite, null, descriptionString);\r
+\r
+            // Other Content to add\r
+            addContent(composite, modelElement);\r
+\r
+            return composite;\r
+        }\r
+\r
+        /**\r
+         * Adds a line of information to <code>parent</code>. If\r
+         * <code>icon</code> is not <code>null</code>, an icon is placed on the\r
+         * left, and then a label with <code>text</code>.\r
+         *\r
+         * @param parent\r
+         *            the composite to add the entry to\r
+         * @param icon\r
+         *            the icon to place next to the text. <code>null</code> for\r
+         *            none.\r
+         * @param text\r
+         *            the text to display\r
+         * @return the created label\r
+         */\r
+        protected Label createEntry(Composite parent, Image icon, String text) {\r
+            if (icon != null) {\r
+                Label iconLabel = new Label(parent, SWT.NONE);\r
+                iconLabel.setImage(icon);\r
+                iconLabel.setBackground(parent.getDisplay().getSystemColor(\r
+                        SWT.COLOR_INFO_BACKGROUND));\r
+                iconLabel.setData(new GridData());\r
+            }\r
+\r
+            Label textLabel = new Label(parent, SWT.WRAP);\r
+\r
+            if(icon == null) {\r
+                GridDataFactory.generate(textLabel, 2, 1);\r
+            } else {\r
+                GridDataFactory.generate(textLabel, 1, 1);\r
+            }\r
+\r
+            textLabel.setText(text);\r
+            textLabel.setBackground(parent.getDisplay().getSystemColor(\r
+                    SWT.COLOR_INFO_BACKGROUND));\r
+            return textLabel;\r
+        }\r
+\r
+        /**\r
+         * Adds a line of information to <code>parent</code>. If\r
+         * <code>icon</code> is not <code>null</code>, an icon is placed on the\r
+         * left, and then a label with <code>text</code>, which supports using\r
+         * anchor tags to creates links\r
+         *\r
+         * @param parent\r
+         *            the composite to add the entry to\r
+         * @param icon\r
+         *            the icon to place next to the text. <code>null</code> for\r
+         *            none.\r
+         * @param text\r
+         *            the text to display\r
+         * @return the created link\r
+         */\r
+        protected Text createEntryWithText(Composite parent, Image icon, String text) {\r
+            if (icon != null) {\r
+                Label iconLabel = new Label(parent, SWT.NONE);\r
+                iconLabel.setImage(icon);\r
+                iconLabel.setBackground(parent.getDisplay().getSystemColor(\r
+                        SWT.COLOR_INFO_BACKGROUND));\r
+                iconLabel.setData(new GridData());\r
+            }\r
+            Text texts = new Text(parent, SWT.READ_ONLY | SWT.MULTI | SWT.V_SCROLL);\r
+            if(icon == null) {\r
+                GridDataFactory.generate(texts, 2, 1);\r
+            }\r
+            texts.setText(text);\r
+            texts.setBackground(parent.getDisplay().getSystemColor(\r
+                    SWT.COLOR_INFO_BACKGROUND));\r
+            return texts;\r
+        }\r
+\r
+        protected void addContent(Composite destination, Object modelElement) {\r
+        }\r
+    }\r
+\r
+    private class ItemDetailToolTip extends NameAndDescriptionToolTip {\r
+        private final boolean DEBUG = false;\r
+        private TreeViewer viewer;\r
+        private Tree tree;\r
+        private ItemDetailToolTip(TreeViewer viewer, Tree tree, ViewerFilter filter) {\r
+            super(tree,NO_RECREATE);\r
+            this.tree = tree;\r
+            this.viewer = viewer;\r
+            this.setHideOnMouseDown(false);\r
+        }\r
+        @Override\r
+        public Point getLocation(Point tipSize, Event event) {\r
+            // try to position the tooltip at the bottom of the cell\r
+            ViewerCell cell = viewer.getCell(new Point(event.x, event.y));\r
+            if( cell != null )\r
+                return tree.toDisplay(event.x,cell.getBounds().y+cell.getBounds().height);\r
+            return super.getLocation(tipSize, event);\r
+        }\r
+        @Override\r
+        protected Object getToolTipArea(Event event) {\r
+            // Ensure that the tooltip is hidden when the cell is left\r
+            return viewer.getCell(new Point(event.x, event.y));\r
+        }\r
+        @Override\r
+        protected void addContent(Composite destination, Object modelElement) {\r
+            final DisplayElement item = (DisplayElement)modelElement;\r
+            if (DEBUG)\r
+                System.out.println("add content");\r
+            String text = null;\r
+            if (null != item) {\r
+                text = modelElement.toString();\r
+                createEntryWithText(destination, null, text.toString());\r
+            }\r
+        }\r
+        @Override\r
+        protected Object getModelElement(Event event) {\r
+            org.eclipse.swt.widgets.TreeItem treeItem = tree.getItem(new Point(event.x, event.y));\r
+            if (treeItem == null)\r
+                return null;\r
+            return treeItem.getData();\r
+        }\r
+    }\r
+    class MyColumnLabelProvider extends ColumnLabelProvider {\r
+        @Override\r
+        public void update(ViewerCell cell) {\r
+            //NodeProxy proxy = (NodeProxy) cell.getElement();\r
+            cell.setText("Kraa");\r
+            cell.setImage(Images.getInstance().OTHER_IMAGE);\r
+        }\r
+    }\r
+    protected void createControls(final Composite parent) {\r
+        parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false));\r
+        GridDataFactory.fillDefaults().grab(true, true).applyTo(treeViewer.getTree());\r
+        treeViewer.setContentProvider(new CommentContentProvider(SimanticsUI.getSession()));\r
+        treeViewer.setLabelProvider(new LabelProvider() {\r
+            @Override\r
+            public Image getImage(Object element) {\r
+                if (element instanceof ChangeSetElement)\r
+                    return Images.getInstance().CHANGE_SET_IMAGE;\r
+                else if (element instanceof DisplayElement)\r
+                    return Images.getInstance().DISPLAY_IMAGE;\r
+                else if (element instanceof ResourceElement)\r
+                    return Images.getInstance().RESOURCE_IMAGE;\r
+                else if (element instanceof StringElement)\r
+                    return Images.getInstance().STRING_IMAGE;\r
+                else if (element instanceof UndoCombinedElement)\r
+                    return Images.getInstance().COMBINED_IMAGE;\r
+                else if (element instanceof RedoContextElement)\r
+                    return Images.getInstance().REDO_IMAGE;\r
+                else if (element instanceof UndoContextElement)\r
+                    return Images.getInstance().UNDO_IMAGE;\r
+                else\r
+                    return Images.getInstance().OTHER_IMAGE;\r
+            }\r
+            @Override\r
+            public String getText(Object element) {\r
+                return element.toString();\r
+            }\r
+        });\r
+        //viewer.setSorter(new ViewerSorter());\r
+        treeViewer.setInput(this);\r
+//        getViewSite().getActionBars().getToolBarManager().add(new Action("GetIncoming", Activator.DOOR_IN_ICON) {\r
+//            @Override\r
+//            public void run() {\r
+//                treeViewer.setContentProvider(new IncomingContentProvider(SimanticsUI.getSession(), parent.getShell()));\r
+//            }\r
+//        });\r
+        new ItemDetailToolTip(treeViewer, treeViewer.getTree(), null);\r
+    }\r
+\r
+    /**\r
+     * @param parent\r
+     * @return\r
+     */\r
+    protected GraphExplorer createExplorerControl(Composite parent) {\r
+        return GraphExplorerFactory.getInstance().selectionDataResolver(new DefaultSelectionDataResolver()).create(parent);\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
+        if (disposeState != DisposeState.Alive)\r
+            return false;\r
+\r
+        this.sessionContext = context;\r
+\r
+        // Start tracking the session context.\r
+        // This will cause IHintListeners of the sessionContextTracker to fire.\r
+        // For this we need the above input equality (identity) checking.\r
+        sessionContextTracker.track(sessionContext);\r
+        return true;\r
+    }\r
+}\r
+class CommentContentProvider implements ITreeContentProvider {\r
+    protected Viewer viewer = null;\r
+    private final Vector<String >comments = new Vector<String>();\r
+    private final Session session;\r
+    private final TeamSupport teamSupport;\r
+    CommentContentProvider(Session session) {\r
+        this.session = session;\r
+        teamSupport = this.session.getService(TeamSupport.class);\r
+        try {\r
+            teamSupport.getComments(Utils.getTeamFolder(), comments);\r
+        } catch (DatabaseException e) {\r
+            comments.add(e.getMessage());\r
+        }\r
+    }\r
+    protected Object[] getElements() {\r
+        final int SIZE = comments.size();\r
+        Object[] objects = new Object[SIZE];\r
+        for (int i=0; i<SIZE; ++i)\r
+            objects[i] = new StagingContextElement(i, comments.get(i));\r
+        return objects;\r
+    }\r
+    @Override\r
+    public void dispose() {\r
+        viewer = null;\r
+    }\r
+    @Override\r
+    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+        this.viewer = viewer;\r
+    }\r
+    @Override\r
+    public Object[] getElements(Object inputElement) {\r
+        return getElements();\r
+    }\r
+    @Override\r
+    public Object[] getChildren(Object parentElement) {\r
+        if (parentElement instanceof  TreeElement)\r
+            return ((TreeElement)parentElement).getChildren();\r
+        else\r
+            return null;\r
+    }\r
+    @Override\r
+    public Object getParent(Object childElement) {\r
+            return null;\r
+    }\r
+    @Override\r
+    public boolean hasChildren(Object element) {\r
+        if (element instanceof  TreeElement)\r
+            return ((TreeElement)element).hasChildren();\r
+        return false;\r
+    }\r
+}\r
+\r
+abstract class StagingViewElement extends TreeElement {\r
+    StagingViewElement() {\r
+    }\r
+    @Override\r
+    boolean hasChildren() {\r
+            return false;\r
+    }\r
+    @Override\r
+    Object[] getChildren() {\r
+        return new Object[0];\r
+    }\r
+}\r
+\r
+class StagingContextElement extends StagingViewElement {\r
+    protected String name = "Staging";\r
+    private final String comment;\r
+    StagingContextElement(int index, String comment) {\r
+        this.comment = comment;\r
+    }\r
+    @Override\r
+    protected Image getIdImage() {\r
+        return Images.getInstance().OTHER_IMAGE;\r
+    }\r
+    @Override\r
+    protected String getIdText() {\r
+        String s = toString();\r
+        return s.substring(0, Math.min(10, s.length()));\r
+    }\r
+    @Override\r
+    public String toString() {\r
+        return comment;\r
+    }\r
+}\r