]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 /*******************************************************************************\r
2  * Copyright (c) 2012 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.modeling.ui.actions;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.Collections;\r
17 import java.util.concurrent.atomic.AtomicReference;\r
18 \r
19 import org.eclipse.jface.dialogs.Dialog;\r
20 import org.eclipse.jface.viewers.ICheckStateProvider;\r
21 import org.eclipse.jface.viewers.IStructuredContentProvider;\r
22 import org.eclipse.jface.viewers.LabelProvider;\r
23 import org.eclipse.jface.viewers.Viewer;\r
24 import org.eclipse.ui.PlatformUI;\r
25 import org.simantics.Simantics;\r
26 import org.simantics.db.ReadGraph;\r
27 import org.simantics.db.Resource;\r
28 import org.simantics.db.common.request.PossibleIndexRoot;\r
29 import org.simantics.db.common.request.UniqueRead;\r
30 import org.simantics.db.common.utils.NameUtils;\r
31 import org.simantics.db.exception.DatabaseException;\r
32 import org.simantics.db.layer0.adapter.ActionFactory;\r
33 import org.simantics.db.layer0.adapter.ActionFactory2;\r
34 import org.simantics.db.request.Read;\r
35 import org.simantics.diagram.stubs.DiagramResource;\r
36 import org.simantics.modeling.AssignConnectionTypesRequest;\r
37 import org.simantics.modeling.GetConnectionTypes;\r
38 import org.simantics.structural2.modelingRules.AllowedConnectionTypes;\r
39 import org.simantics.utils.strings.AlphanumComparator;\r
40 import org.simantics.utils.ui.ErrorLogger;\r
41 import org.simantics.utils.ui.dialogs.ShowMessage;\r
42 \r
43 /**\r
44  * @author Antti Villberg\r
45  */\r
46 public class ConfigureConnectionTypes implements ActionFactory, ActionFactory2 {\r
47 \r
48     @Override\r
49     public Runnable create(Collection<?> targets) {\r
50         final ArrayList<Resource> resources = new ArrayList<Resource>();\r
51         for (Object target : targets) {\r
52             if (!(target instanceof Resource))\r
53                 return null;\r
54             resources.add((Resource) target);\r
55         }\r
56         return new Runnable() {\r
57             @Override\r
58             public void run() {\r
59                 assignTypes(resources);\r
60             }\r
61         };\r
62     }\r
63 \r
64     @Override\r
65     public Runnable create(Object target) {\r
66         if(!(target instanceof Resource))\r
67             return null;\r
68         final Resource connectionPoint = (Resource)target;\r
69         return new Runnable() {\r
70             @Override\r
71             public void run() {\r
72                 assignTypes(Collections.singletonList(connectionPoint));\r
73             }\r
74         };\r
75     }\r
76 \r
77     private static final ConnectionType[] NO_CONNECTION_TYPES = new ConnectionType[0];\r
78 \r
79     static enum Tristate {\r
80         NONE, SOME, ALL;\r
81 \r
82         public static Tristate add(Tristate current, boolean next) {\r
83             if (current == null)\r
84                 return next ? ALL : NONE;\r
85             switch (current) {\r
86             case ALL: return next ? ALL : SOME; \r
87             case SOME: return next ? SOME : SOME;\r
88             case NONE: return next ? SOME : NONE;\r
89             default: return NONE;\r
90             }\r
91         }\r
92     }\r
93 \r
94     private static class ConnectionType implements Comparable<ConnectionType> {\r
95         Resource resource;\r
96         String name;\r
97         Tristate originallySelected;\r
98         Tristate selected;\r
99 \r
100         public ConnectionType(Resource resource, String name, Tristate originallySelected, Tristate selected) {\r
101             super();\r
102             this.resource = resource;\r
103             this.name = name;\r
104             this.originallySelected = originallySelected;\r
105             this.selected = selected;\r
106         }\r
107 \r
108         @Override\r
109         public int compareTo(ConnectionType o) {\r
110             return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(name, o.name);\r
111         }\r
112 \r
113         @Override\r
114         public String toString() {\r
115             return getClass().getSimpleName() + "[name=" + name\r
116                     + ", originally selected=" + originallySelected\r
117                     + ", selected=" + selected + "]";\r
118         }\r
119     }\r
120 \r
121     private static class ContentProviderImpl implements IStructuredContentProvider {    \r
122         @Override\r
123         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
124         }\r
125 \r
126         @Override\r
127         public void dispose() {\r
128         }\r
129 \r
130         @Override\r
131         public Object[] getElements(Object inputElement) {\r
132             return (Object[])inputElement;\r
133         }\r
134     };\r
135 \r
136     private static class LabelProviderImpl extends LabelProvider {\r
137         @Override\r
138         public String getText(Object element) {\r
139             return ((ConnectionType)element).name;\r
140         }\r
141     }\r
142 \r
143     private static class CheckStateProviderImpl implements ICheckStateProvider {\r
144         @Override\r
145         public boolean isChecked(Object element) {\r
146             return ((ConnectionType) element).selected != Tristate.NONE;\r
147         }\r
148         @Override\r
149         public boolean isGrayed(Object element) {\r
150             return ((ConnectionType) element).selected == Tristate.SOME;\r
151         }\r
152     }\r
153 \r
154     private static Resource getCommonModel(final Collection<Resource> connectionPoints) {\r
155         try {\r
156             return Simantics.sync(new UniqueRead<Resource>() {\r
157                 @Override\r
158                 public Resource perform(ReadGraph graph) throws DatabaseException {\r
159                     return getPossibleIndexRoot(graph, connectionPoints);\r
160                 }\r
161             });\r
162         } catch (DatabaseException e) {\r
163             ErrorLogger.defaultLogError(e);\r
164             return null;\r
165         }\r
166     }\r
167 \r
168     private static Resource getPossibleIndexRoot(ReadGraph g, Collection<Resource> connectionPoints) throws DatabaseException {\r
169         Resource model = null;\r
170         for (Resource connectionPoint : connectionPoints) {\r
171             Resource m = getIndexRootOf(g, connectionPoint);\r
172             if (m == null)\r
173                 return null;\r
174             if (model == null)\r
175                 model = m;\r
176             else if (!model.equals(m))\r
177                 return null;\r
178         }\r
179         return model;\r
180     }\r
181 \r
182     private static Resource getIndexRootOf(ReadGraph g, Resource connectionPoint) throws DatabaseException {\r
183         return g.syncRequest(new PossibleIndexRoot(connectionPoint));\r
184     }\r
185 \r
186     private static ConnectionType[] getConnectionTypes(final Collection<Resource> connectionPoints) {\r
187         try {\r
188             return Simantics.getSession().syncRequest(new Read<ConnectionType[]>() {\r
189                 @Override\r
190                 public ConnectionType[] perform(ReadGraph g) throws DatabaseException {\r
191                     return getConnectionTypes(g, connectionPoints);\r
192                 }\r
193             });\r
194         } catch(DatabaseException e) {\r
195             e.printStackTrace();\r
196             return NO_CONNECTION_TYPES;\r
197         }\r
198     }\r
199 \r
200     private static ConnectionType[] getConnectionTypes(ReadGraph g, Collection<Resource> connectionPoints) throws DatabaseException {\r
201         Resource root = getPossibleIndexRoot(g, connectionPoints);\r
202         if (root == null)\r
203             return NO_CONNECTION_TYPES;\r
204         // All connection points have same index root.\r
205         // Resolve the connection type selection states now.\r
206         ArrayList<ConnectionType> result = new ArrayList<ConnectionType>();\r
207         DiagramResource DIA = DiagramResource.getInstance(g);\r
208         for (Resource type : GetConnectionTypes.getConnectionTypes(g, root)) {\r
209             Tristate selected = getConnectionTypeSelectionState(g, type, connectionPoints, DIA);\r
210             selected = selected != null ? selected : Tristate.NONE;\r
211             result.add( new ConnectionType(\r
212                     type,\r
213                     NameUtils.getSafeLabel(g, type),\r
214                     selected,\r
215                     selected) );\r
216         }\r
217         //System.out.println("result: " + EString.implode(result));\r
218         Collections.sort(result);\r
219         //System.out.println("sorted result: " + EString.implode(result));\r
220         return result.toArray(new ConnectionType[result.size()]);\r
221     }\r
222 \r
223     protected static Tristate getConnectionTypeSelectionState(ReadGraph graph, Resource connectionType,\r
224             Collection<Resource> connectionPoints, DiagramResource DIA) throws DatabaseException {\r
225         Tristate selected = null;\r
226         for (Resource connectionPoint : connectionPoints) {\r
227                 Collection<Resource> allowed = graph.syncRequest(new AllowedConnectionTypes(connectionPoint));\r
228             selected = Tristate.add(selected, allowed.contains(connectionType));\r
229         }\r
230         return selected != null ? selected : Tristate.NONE;\r
231     }\r
232 \r
233     private static ConnectionType[] selectedElements(ConnectionType[] connectionTypes) {\r
234         int count = 0;\r
235         for(ConnectionType connectionType : connectionTypes)\r
236             if(connectionType.selected != Tristate.NONE)\r
237                 ++count;\r
238         ConnectionType[] result = new ConnectionType[count];\r
239         count = 0;\r
240         for(ConnectionType connectionType : connectionTypes)\r
241             if(connectionType.selected != Tristate.NONE)\r
242                 result[count++] = connectionType;\r
243         return result;\r
244     }\r
245 \r
246     public void assignTypes(final Collection<Resource> connectionPoints) {\r
247         if (connectionPoints.isEmpty())\r
248             return;\r
249 \r
250         final Resource indexRoot = getCommonModel(connectionPoints);\r
251         if (indexRoot == null) {\r
252             ShowMessage.showInformation("Same Model Required", "All the selected connection points must be from within the same index root.");\r
253             return;\r
254         }\r
255 \r
256         final AtomicReference<ConnectionType[]> types =\r
257                 new AtomicReference<ConnectionType[]>( getConnectionTypes(connectionPoints) );\r
258 \r
259         StringBuilder message = new StringBuilder();\r
260         if (connectionPoints.size() > 1)\r
261             message.append("Select connection types for the selected connection points");\r
262         else\r
263             message.append("Select connection types for the selected connection point");\r
264 \r
265         ConfigureConnectionTypesDialog dialog = new ConfigureConnectionTypesDialog(\r
266                 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),\r
267                 types.get(),\r
268                 new ContentProviderImpl(), \r
269                 new LabelProviderImpl(), \r
270                 new CheckStateProviderImpl(),\r
271                 message.toString()) {\r
272 \r
273             @Override\r
274             protected void checkStateChanged(Object[] elements, boolean checked) {\r
275                 for (Object _g : elements) {\r
276                     ConnectionType g = (ConnectionType) _g;\r
277                     g.selected = checked ? Tristate.ALL : Tristate.NONE;\r
278                     // Refresh checked states through provider.\r
279                     listViewer.refresh();\r
280                 }\r
281             }\r
282 \r
283         };\r
284         dialog.setTitle("Connection Type Assignments");\r
285         dialog.setInitialSelections(selectedElements(types.get()));\r
286         if (dialog.open() == Dialog.OK) {\r
287             final ArrayList<ConnectionType> added = new ArrayList<ConnectionType>();\r
288             final ArrayList<ConnectionType> removed = new ArrayList<ConnectionType>();\r
289             for (ConnectionType g : types.get()) {\r
290                 if (g.selected != g.originallySelected && g.selected == Tristate.ALL)\r
291                     added.add(g);\r
292                 if (g.selected != g.originallySelected && g.selected == Tristate.NONE)\r
293                     removed.add(g);\r
294             }\r
295             if (!added.isEmpty() || !removed.isEmpty()) {\r
296                 ArrayList<Resource> addedConnectionTypes = new ArrayList<Resource>();\r
297                 ArrayList<Resource> removedConnectionTypes = new ArrayList<Resource>();\r
298                 for (ConnectionType type : added)\r
299                     addedConnectionTypes.add(type.resource);\r
300                 for (ConnectionType type : removed)\r
301                     removedConnectionTypes.add(type.resource);\r
302                 Simantics.getSession().asyncRequest(new AssignConnectionTypesRequest(addedConnectionTypes, removedConnectionTypes, connectionPoints));\r
303             }\r
304         }\r
305     }\r
306 \r
307 }\r