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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling.ui.actions;
\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
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
44 * @author Antti Villberg
\r
46 public class ConfigureConnectionTypes implements ActionFactory, ActionFactory2 {
\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
54 resources.add((Resource) target);
\r
56 return new Runnable() {
\r
59 assignTypes(resources);
\r
65 public Runnable create(Object target) {
\r
66 if(!(target instanceof Resource))
\r
68 final Resource connectionPoint = (Resource)target;
\r
69 return new Runnable() {
\r
72 assignTypes(Collections.singletonList(connectionPoint));
\r
77 private static final ConnectionType[] NO_CONNECTION_TYPES = new ConnectionType[0];
\r
79 static enum Tristate {
\r
82 public static Tristate add(Tristate current, boolean next) {
\r
83 if (current == null)
\r
84 return next ? ALL : NONE;
\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
94 private static class ConnectionType implements Comparable<ConnectionType> {
\r
97 Tristate originallySelected;
\r
100 public ConnectionType(Resource resource, String name, Tristate originallySelected, Tristate selected) {
\r
102 this.resource = resource;
\r
104 this.originallySelected = originallySelected;
\r
105 this.selected = selected;
\r
109 public int compareTo(ConnectionType o) {
\r
110 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(name, o.name);
\r
114 public String toString() {
\r
115 return getClass().getSimpleName() + "[name=" + name
\r
116 + ", originally selected=" + originallySelected
\r
117 + ", selected=" + selected + "]";
\r
121 private static class ContentProviderImpl implements IStructuredContentProvider {
\r
123 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
\r
127 public void dispose() {
\r
131 public Object[] getElements(Object inputElement) {
\r
132 return (Object[])inputElement;
\r
136 private static class LabelProviderImpl extends LabelProvider {
\r
138 public String getText(Object element) {
\r
139 return ((ConnectionType)element).name;
\r
143 private static class CheckStateProviderImpl implements ICheckStateProvider {
\r
145 public boolean isChecked(Object element) {
\r
146 return ((ConnectionType) element).selected != Tristate.NONE;
\r
149 public boolean isGrayed(Object element) {
\r
150 return ((ConnectionType) element).selected == Tristate.SOME;
\r
154 private static Resource getCommonModel(final Collection<Resource> connectionPoints) {
\r
156 return Simantics.sync(new UniqueRead<Resource>() {
\r
158 public Resource perform(ReadGraph graph) throws DatabaseException {
\r
159 return getPossibleIndexRoot(graph, connectionPoints);
\r
162 } catch (DatabaseException e) {
\r
163 ErrorLogger.defaultLogError(e);
\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
176 else if (!model.equals(m))
\r
182 private static Resource getIndexRootOf(ReadGraph g, Resource connectionPoint) throws DatabaseException {
\r
183 return g.syncRequest(new PossibleIndexRoot(connectionPoint));
\r
186 private static ConnectionType[] getConnectionTypes(final Collection<Resource> connectionPoints) {
\r
188 return Simantics.getSession().syncRequest(new Read<ConnectionType[]>() {
\r
190 public ConnectionType[] perform(ReadGraph g) throws DatabaseException {
\r
191 return getConnectionTypes(g, connectionPoints);
\r
194 } catch(DatabaseException e) {
\r
195 e.printStackTrace();
\r
196 return NO_CONNECTION_TYPES;
\r
200 private static ConnectionType[] getConnectionTypes(ReadGraph g, Collection<Resource> connectionPoints) throws DatabaseException {
\r
201 Resource root = getPossibleIndexRoot(g, connectionPoints);
\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
213 NameUtils.getSafeLabel(g, type),
\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
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
230 return selected != null ? selected : Tristate.NONE;
\r
233 private static ConnectionType[] selectedElements(ConnectionType[] connectionTypes) {
\r
235 for(ConnectionType connectionType : connectionTypes)
\r
236 if(connectionType.selected != Tristate.NONE)
\r
238 ConnectionType[] result = new ConnectionType[count];
\r
240 for(ConnectionType connectionType : connectionTypes)
\r
241 if(connectionType.selected != Tristate.NONE)
\r
242 result[count++] = connectionType;
\r
246 public void assignTypes(final Collection<Resource> connectionPoints) {
\r
247 if (connectionPoints.isEmpty())
\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
256 final AtomicReference<ConnectionType[]> types =
\r
257 new AtomicReference<ConnectionType[]>( getConnectionTypes(connectionPoints) );
\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
263 message.append("Select connection types for the selected connection point");
\r
265 ConfigureConnectionTypesDialog dialog = new ConfigureConnectionTypesDialog(
\r
266 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
\r
268 new ContentProviderImpl(),
\r
269 new LabelProviderImpl(),
\r
270 new CheckStateProviderImpl(),
\r
271 message.toString()) {
\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
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
292 if (g.selected != g.originallySelected && g.selected == Tristate.NONE)
\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