]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/actions/ConfigureConnectionTypes.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / actions / ConfigureConnectionTypes.java
diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/actions/ConfigureConnectionTypes.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/actions/ConfigureConnectionTypes.java
new file mode 100644 (file)
index 0000000..20bb053
--- /dev/null
@@ -0,0 +1,307 @@
+/*******************************************************************************\r
+ * Copyright (c) 2012 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.actions;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.concurrent.atomic.AtomicReference;\r
+\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.viewers.ICheckStateProvider;\r
+import org.eclipse.jface.viewers.IStructuredContentProvider;\r
+import org.eclipse.jface.viewers.LabelProvider;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.simantics.Simantics;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.request.PossibleIndexRoot;\r
+import org.simantics.db.common.request.UniqueRead;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.ActionFactory;\r
+import org.simantics.db.layer0.adapter.ActionFactory2;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.modeling.AssignConnectionTypesRequest;\r
+import org.simantics.modeling.GetConnectionTypes;\r
+import org.simantics.structural2.modelingRules.AllowedConnectionTypes;\r
+import org.simantics.utils.strings.AlphanumComparator;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+import org.simantics.utils.ui.dialogs.ShowMessage;\r
+\r
+/**\r
+ * @author Antti Villberg\r
+ */\r
+public class ConfigureConnectionTypes implements ActionFactory, ActionFactory2 {\r
+\r
+    @Override\r
+    public Runnable create(Collection<?> targets) {\r
+        final ArrayList<Resource> resources = new ArrayList<Resource>();\r
+        for (Object target : targets) {\r
+            if (!(target instanceof Resource))\r
+                return null;\r
+            resources.add((Resource) target);\r
+        }\r
+        return new Runnable() {\r
+            @Override\r
+            public void run() {\r
+                assignTypes(resources);\r
+            }\r
+        };\r
+    }\r
+\r
+    @Override\r
+    public Runnable create(Object target) {\r
+        if(!(target instanceof Resource))\r
+            return null;\r
+        final Resource connectionPoint = (Resource)target;\r
+        return new Runnable() {\r
+            @Override\r
+            public void run() {\r
+                assignTypes(Collections.singletonList(connectionPoint));\r
+            }\r
+        };\r
+    }\r
+\r
+    private static final ConnectionType[] NO_CONNECTION_TYPES = new ConnectionType[0];\r
+\r
+    static enum Tristate {\r
+        NONE, SOME, ALL;\r
+\r
+        public static Tristate add(Tristate current, boolean next) {\r
+            if (current == null)\r
+                return next ? ALL : NONE;\r
+            switch (current) {\r
+            case ALL: return next ? ALL : SOME; \r
+            case SOME: return next ? SOME : SOME;\r
+            case NONE: return next ? SOME : NONE;\r
+            default: return NONE;\r
+            }\r
+        }\r
+    }\r
+\r
+    private static class ConnectionType implements Comparable<ConnectionType> {\r
+        Resource resource;\r
+        String name;\r
+        Tristate originallySelected;\r
+        Tristate selected;\r
+\r
+        public ConnectionType(Resource resource, String name, Tristate originallySelected, Tristate selected) {\r
+            super();\r
+            this.resource = resource;\r
+            this.name = name;\r
+            this.originallySelected = originallySelected;\r
+            this.selected = selected;\r
+        }\r
+\r
+        @Override\r
+        public int compareTo(ConnectionType o) {\r
+            return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(name, o.name);\r
+        }\r
+\r
+        @Override\r
+        public String toString() {\r
+            return getClass().getSimpleName() + "[name=" + name\r
+                    + ", originally selected=" + originallySelected\r
+                    + ", selected=" + selected + "]";\r
+        }\r
+    }\r
+\r
+    private static class ContentProviderImpl implements IStructuredContentProvider {    \r
+        @Override\r
+        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+        }\r
+\r
+        @Override\r
+        public void dispose() {\r
+        }\r
+\r
+        @Override\r
+        public Object[] getElements(Object inputElement) {\r
+            return (Object[])inputElement;\r
+        }\r
+    };\r
+\r
+    private static class LabelProviderImpl extends LabelProvider {\r
+        @Override\r
+        public String getText(Object element) {\r
+            return ((ConnectionType)element).name;\r
+        }\r
+    }\r
+\r
+    private static class CheckStateProviderImpl implements ICheckStateProvider {\r
+        @Override\r
+        public boolean isChecked(Object element) {\r
+            return ((ConnectionType) element).selected != Tristate.NONE;\r
+        }\r
+        @Override\r
+        public boolean isGrayed(Object element) {\r
+            return ((ConnectionType) element).selected == Tristate.SOME;\r
+        }\r
+    }\r
+\r
+    private static Resource getCommonModel(final Collection<Resource> connectionPoints) {\r
+        try {\r
+            return Simantics.sync(new UniqueRead<Resource>() {\r
+                @Override\r
+                public Resource perform(ReadGraph graph) throws DatabaseException {\r
+                    return getPossibleIndexRoot(graph, connectionPoints);\r
+                }\r
+            });\r
+        } catch (DatabaseException e) {\r
+            ErrorLogger.defaultLogError(e);\r
+            return null;\r
+        }\r
+    }\r
+\r
+    private static Resource getPossibleIndexRoot(ReadGraph g, Collection<Resource> connectionPoints) throws DatabaseException {\r
+        Resource model = null;\r
+        for (Resource connectionPoint : connectionPoints) {\r
+            Resource m = getIndexRootOf(g, connectionPoint);\r
+            if (m == null)\r
+                return null;\r
+            if (model == null)\r
+                model = m;\r
+            else if (!model.equals(m))\r
+                return null;\r
+        }\r
+        return model;\r
+    }\r
+\r
+    private static Resource getIndexRootOf(ReadGraph g, Resource connectionPoint) throws DatabaseException {\r
+        return g.syncRequest(new PossibleIndexRoot(connectionPoint));\r
+    }\r
+\r
+    private static ConnectionType[] getConnectionTypes(final Collection<Resource> connectionPoints) {\r
+        try {\r
+            return Simantics.getSession().syncRequest(new Read<ConnectionType[]>() {\r
+                @Override\r
+                public ConnectionType[] perform(ReadGraph g) throws DatabaseException {\r
+                    return getConnectionTypes(g, connectionPoints);\r
+                }\r
+            });\r
+        } catch(DatabaseException e) {\r
+            e.printStackTrace();\r
+            return NO_CONNECTION_TYPES;\r
+        }\r
+    }\r
+\r
+    private static ConnectionType[] getConnectionTypes(ReadGraph g, Collection<Resource> connectionPoints) throws DatabaseException {\r
+        Resource root = getPossibleIndexRoot(g, connectionPoints);\r
+        if (root == null)\r
+            return NO_CONNECTION_TYPES;\r
+        // All connection points have same index root.\r
+        // Resolve the connection type selection states now.\r
+        ArrayList<ConnectionType> result = new ArrayList<ConnectionType>();\r
+        DiagramResource DIA = DiagramResource.getInstance(g);\r
+        for (Resource type : GetConnectionTypes.getConnectionTypes(g, root)) {\r
+            Tristate selected = getConnectionTypeSelectionState(g, type, connectionPoints, DIA);\r
+            selected = selected != null ? selected : Tristate.NONE;\r
+            result.add( new ConnectionType(\r
+                    type,\r
+                    NameUtils.getSafeLabel(g, type),\r
+                    selected,\r
+                    selected) );\r
+        }\r
+        //System.out.println("result: " + EString.implode(result));\r
+        Collections.sort(result);\r
+        //System.out.println("sorted result: " + EString.implode(result));\r
+        return result.toArray(new ConnectionType[result.size()]);\r
+    }\r
+\r
+    protected static Tristate getConnectionTypeSelectionState(ReadGraph graph, Resource connectionType,\r
+            Collection<Resource> connectionPoints, DiagramResource DIA) throws DatabaseException {\r
+        Tristate selected = null;\r
+        for (Resource connectionPoint : connectionPoints) {\r
+               Collection<Resource> allowed = graph.syncRequest(new AllowedConnectionTypes(connectionPoint));\r
+            selected = Tristate.add(selected, allowed.contains(connectionType));\r
+        }\r
+        return selected != null ? selected : Tristate.NONE;\r
+    }\r
+\r
+    private static ConnectionType[] selectedElements(ConnectionType[] connectionTypes) {\r
+        int count = 0;\r
+        for(ConnectionType connectionType : connectionTypes)\r
+            if(connectionType.selected != Tristate.NONE)\r
+                ++count;\r
+        ConnectionType[] result = new ConnectionType[count];\r
+        count = 0;\r
+        for(ConnectionType connectionType : connectionTypes)\r
+            if(connectionType.selected != Tristate.NONE)\r
+                result[count++] = connectionType;\r
+        return result;\r
+    }\r
+\r
+    public void assignTypes(final Collection<Resource> connectionPoints) {\r
+        if (connectionPoints.isEmpty())\r
+            return;\r
+\r
+        final Resource indexRoot = getCommonModel(connectionPoints);\r
+        if (indexRoot == null) {\r
+            ShowMessage.showInformation("Same Model Required", "All the selected connection points must be from within the same index root.");\r
+            return;\r
+        }\r
+\r
+        final AtomicReference<ConnectionType[]> types =\r
+                new AtomicReference<ConnectionType[]>( getConnectionTypes(connectionPoints) );\r
+\r
+        StringBuilder message = new StringBuilder();\r
+        if (connectionPoints.size() > 1)\r
+            message.append("Select connection types for the selected connection points");\r
+        else\r
+            message.append("Select connection types for the selected connection point");\r
+\r
+        ConfigureConnectionTypesDialog dialog = new ConfigureConnectionTypesDialog(\r
+                PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),\r
+                types.get(),\r
+                new ContentProviderImpl(), \r
+                new LabelProviderImpl(), \r
+                new CheckStateProviderImpl(),\r
+                message.toString()) {\r
+\r
+            @Override\r
+            protected void checkStateChanged(Object[] elements, boolean checked) {\r
+                for (Object _g : elements) {\r
+                    ConnectionType g = (ConnectionType) _g;\r
+                    g.selected = checked ? Tristate.ALL : Tristate.NONE;\r
+                    // Refresh checked states through provider.\r
+                    listViewer.refresh();\r
+                }\r
+            }\r
+\r
+        };\r
+        dialog.setTitle("Connection Type Assignments");\r
+        dialog.setInitialSelections(selectedElements(types.get()));\r
+        if (dialog.open() == Dialog.OK) {\r
+            final ArrayList<ConnectionType> added = new ArrayList<ConnectionType>();\r
+            final ArrayList<ConnectionType> removed = new ArrayList<ConnectionType>();\r
+            for (ConnectionType g : types.get()) {\r
+                if (g.selected != g.originallySelected && g.selected == Tristate.ALL)\r
+                    added.add(g);\r
+                if (g.selected != g.originallySelected && g.selected == Tristate.NONE)\r
+                    removed.add(g);\r
+            }\r
+            if (!added.isEmpty() || !removed.isEmpty()) {\r
+                ArrayList<Resource> addedConnectionTypes = new ArrayList<Resource>();\r
+                ArrayList<Resource> removedConnectionTypes = new ArrayList<Resource>();\r
+                for (ConnectionType type : added)\r
+                    addedConnectionTypes.add(type.resource);\r
+                for (ConnectionType type : removed)\r
+                    removedConnectionTypes.add(type.resource);\r
+                Simantics.getSession().asyncRequest(new AssignConnectionTypesRequest(addedConnectionTypes, removedConnectionTypes, connectionPoints));\r
+            }\r
+        }\r
+    }\r
+\r
+}\r