1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 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.diagram.flag;
\r
14 import java.util.Collection;
\r
15 import java.util.Collections;
\r
16 import java.util.HashSet;
\r
17 import java.util.List;
\r
18 import java.util.Set;
\r
20 import org.simantics.db.ReadGraph;
\r
21 import org.simantics.db.Resource;
\r
22 import org.simantics.db.Statement;
\r
23 import org.simantics.db.WriteGraph;
\r
24 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
\r
25 import org.simantics.db.common.request.PossibleObjectWithType;
\r
26 import org.simantics.db.common.request.TernaryRead;
\r
27 import org.simantics.db.common.utils.NameUtils;
\r
28 import org.simantics.db.common.utils.OrderedSetUtils;
\r
29 import org.simantics.db.exception.DatabaseException;
\r
30 import org.simantics.db.exception.ServiceException;
\r
31 import org.simantics.db.function.DbBiFunction;
\r
32 import org.simantics.db.function.DbConsumer;
\r
33 import org.simantics.db.layer0.util.RemoverUtil;
\r
34 import org.simantics.db.layer0.variable.Variable;
\r
35 import org.simantics.diagram.content.ConnectionUtil;
\r
36 import org.simantics.diagram.flag.IFlagType.FlagInfo;
\r
37 import org.simantics.diagram.stubs.DiagramResource;
\r
38 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
\r
39 import org.simantics.g2d.elementclass.FlagClass;
\r
40 import org.simantics.layer0.Layer0;
\r
41 import org.simantics.layer0.utils.triggers.IActivationManager;
\r
42 import org.simantics.modeling.ModelingResources;
\r
43 import org.simantics.structural.stubs.StructuralResource2;
\r
44 import org.simantics.structural2.modelingRules.IModelingRules;
\r
45 import org.simantics.structural2.queries.Terminal;
\r
46 import org.simantics.structural2.variables.ConnectionBrowser;
\r
47 import org.simantics.structural2.variables.ResourceWithContext;
\r
48 import org.simantics.utils.datastructures.Triple;
\r
50 import gnu.trove.set.hash.THashSet;
\r
53 * @author Tuukka Lehtonen
\r
55 public final class FlagUtil {
\r
57 public static boolean isDisconnected(ReadGraph graph, Resource flag) throws DatabaseException {
\r
58 return !isJoined(graph, flag) && !isMarkedExternal(graph, flag);
\r
61 private static boolean isMarkedExternal(ReadGraph graph, Resource flag) throws DatabaseException {
\r
62 return graph.hasStatement(flag, DiagramResource.getInstance(graph).ExternalFlag);
\r
65 public static boolean isExternal(ReadGraph graph, Resource flag) throws DatabaseException {
\r
66 return isMarkedExternal(graph, flag) && !isJoined(graph, flag);
\r
69 public static boolean isJoined(ReadGraph graph, Resource flag) throws DatabaseException {
\r
70 return countCounterparts(graph, flag) > 0;
\r
73 public static boolean isLifted(ReadGraph graph, Resource flag) throws DatabaseException {
\r
74 Resource cp = getPossibleConnectionPoint(graph, flag);
\r
75 return cp == null ? false : graph.isInstanceOf(cp, StructuralResource2.getInstance(graph).ConnectionRelation);
\r
78 public static Resource getPossibleConnectionPoint(ReadGraph graph, Resource flag) throws DatabaseException {
\r
79 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
80 return graph.getPossibleObject(flag, DIA.IsLiftedAs);
\r
83 public static Resource getPossibleCounterpart(ReadGraph graph, Resource flag) throws DatabaseException {
\r
84 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
85 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
\r
86 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
\r
87 if (flag.equals(otherFlag))
\r
95 public static int countCounterparts(ReadGraph graph, Resource flag) throws DatabaseException {
\r
96 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
98 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
\r
99 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
\r
100 if (flag.equals(otherFlag))
\r
108 public static Set<Resource> getCounterparts(ReadGraph graph, Resource flag, Set<Resource> result) throws DatabaseException {
\r
109 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
110 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
\r
111 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
\r
112 if (flag.equals(otherFlag))
\r
114 result.add(otherFlag);
\r
120 public static int forCounterparts(ReadGraph graph, Resource flag, DbConsumer<Resource> procedure) throws DatabaseException {
\r
121 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
123 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
\r
124 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
\r
125 if (!flag.equals(otherFlag)) {
\r
126 procedure.accept(otherFlag);
\r
134 public static int forCounterparts(ReadGraph graph, Resource flag, DbBiFunction<Resource, Resource, Boolean> procedure) throws DatabaseException {
\r
135 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
137 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
\r
138 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
\r
139 if (!flag.equals(otherFlag)) {
\r
140 if (!procedure.apply(connectionJoin, otherFlag))
\r
150 * Returns all flags that are joined with the given flag including the flag given as parameter.
\r
152 public static Set<Resource> getCounterparts(ReadGraph graph, Resource flag) throws DatabaseException {
\r
153 return getCounterparts(graph, flag, new HashSet<Resource>(8));
\r
156 public static Set<Resource> getCounterpartsAndSelf(ReadGraph graph, Resource flag, Set<Resource> result) throws DatabaseException {
\r
157 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
158 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
\r
159 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
\r
160 result.add(otherFlag);
\r
163 if (result.size() == 0)
\r
168 public static Set<Resource> getCounterpartsAndSelf(ReadGraph graph, Resource flag) throws DatabaseException {
\r
169 return getCounterpartsAndSelf(graph, flag, new HashSet<Resource>(8));
\r
175 * @return the created DIA.ConnectionJoin instance
\r
176 * @throws DatabaseException
\r
178 public static Resource join(WriteGraph g, Resource flag, Resource otherFlag) throws DatabaseException {
\r
179 DiagramResource DIA = DiagramResource.getInstance(g);
\r
180 StructuralResource2 STR = StructuralResource2.getInstance(g);
\r
181 Resource connectionJoin = g.newResource();
\r
182 Layer0 L0 = Layer0.getInstance(g);
\r
183 g.claim(connectionJoin, L0.InstanceOf, null, STR.ConnectionJoin);
\r
184 g.claim(connectionJoin, DIA.JoinsFlag, flag);
\r
185 g.claim(connectionJoin, DIA.JoinsFlag, otherFlag);
\r
187 IActivationManager manager = g.getService(IActivationManager.class);
\r
188 for(Resource diagram : OrderedSetUtils.getSubjects(g, flag))
\r
189 manager.activateOnce(diagram);
\r
190 for(Resource diagram : OrderedSetUtils.getSubjects(g, otherFlag))
\r
191 manager.activateOnce(diagram);
\r
192 return connectionJoin;
\r
195 public static void disconnectFlag(WriteGraph graph, Resource flag) throws DatabaseException {
\r
196 // Remove any :ConnectionJoin's this flag is joined by
\r
197 // if there's less than two flags joined by the join.
\r
198 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
199 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
200 THashSet<Resource> affectedConnections = new THashSet<Resource>(4);
\r
201 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
\r
202 affectedConnections.addAll(graph.getObjects(connectionJoin, STR.Joins));
\r
203 graph.deny(flag, DIA.FlagIsJoinedBy, connectionJoin);
\r
204 if (graph.getObjects(connectionJoin, DIA.JoinsFlag).size() < 2) {
\r
205 RemoverUtil.remove(graph, connectionJoin);
\r
208 fixBindsStatements(graph, STR, DIA, affectedConnections);
\r
211 private static boolean isBindsStatementLegimite(ReadGraph graph,
\r
212 DiagramResource DIA,
\r
213 Resource connection,
\r
214 Resource connectionRelation) throws DatabaseException {
\r
215 ModelingResources MOD = ModelingResources.getInstance(graph);
\r
216 for(Resource diagramConnection : graph.getObjects(connection, MOD.ConnectionToDiagramConnection))
\r
217 for(Resource connector : graph.getObjects(diagramConnection, DIA.HasConnector))
\r
218 for(Resource flag : graph.getObjects(connector, DIA.Flag_ConnectionPoint_Inverse))
\r
219 if(graph.hasStatement(flag, DIA.IsLiftedAs, connectionRelation))
\r
224 private static void fixBindsStatements(WriteGraph graph, StructuralResource2 STR, DiagramResource DIA, Collection<Resource> connections) throws DatabaseException {
\r
225 for(Resource connection : connections)
\r
226 for(Resource connectionRelation : graph.getObjects(connection, STR.Binds))
\r
227 if(!isBindsStatementLegimite(graph, DIA, connection, connectionRelation))
\r
228 graph.denyStatement(connection, STR.Binds, connectionRelation);
\r
231 public static void fixBindsStatements(WriteGraph graph, Resource connection) throws DatabaseException {
\r
232 if(connection == null)
\r
234 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
235 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
236 for(Resource connectionRelation : graph.getObjects(connection, STR.Binds))
\r
237 if(!isBindsStatementLegimite(graph, DIA, connection, connectionRelation))
\r
238 graph.denyStatement(connection, STR.Binds, connectionRelation);
\r
241 public static void disconnectFlag(WriteGraph graph, Resource flag, Resource fromFlag) throws DatabaseException {
\r
242 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
243 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
244 THashSet<Resource> affectedConnections = new THashSet<Resource>(4);
\r
245 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
\r
246 affectedConnections.addAll(graph.getObjects(connectionJoin, STR.Joins));
\r
247 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
\r
248 if (flag.equals(otherFlag))
\r
250 if (otherFlag.equals(fromFlag)) {
\r
251 graph.deny(connectionJoin, DIA.JoinsFlag, DIA.FlagIsJoinedBy, flag);
\r
252 if (graph.getObjects(connectionJoin, DIA.JoinsFlag).size() < 2) {
\r
253 RemoverUtil.remove(graph, connectionJoin);
\r
258 fixBindsStatements(graph, STR, DIA, affectedConnections);
\r
261 public static void removeFlag(WriteGraph graph, Resource flag) throws DatabaseException {
\r
262 disconnectFlag(graph, flag);
\r
263 RemoverUtil.remove(graph, flag);
\r
269 * @return <code>true</code> only if the specified flag is joined only
\r
270 * within the single diagram it resides in
\r
271 * @throws DatabaseException
\r
273 public static boolean isJoinedInSingleDiagram(ReadGraph graph, Resource flag) throws DatabaseException {
\r
274 Collection<Resource> counterparts = getCounterparts(graph, flag);
\r
275 if (counterparts.isEmpty())
\r
277 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
278 Collection<Resource> flagDiagrams = OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram);
\r
279 for (Resource counterpart : counterparts) {
\r
280 if (Collections.disjoint(flagDiagrams,
\r
281 OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram)))
\r
287 public static boolean isJoinedBetweenDiagrams(ReadGraph graph, Resource flag) throws DatabaseException {
\r
288 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
289 Collection<Resource> counterparts = getCounterparts(graph, flag);
\r
290 if (counterparts.isEmpty())
\r
292 Collection<Resource> flagDiagrams = OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram);
\r
293 for (Resource counterpart : counterparts)
\r
294 if (Collections.disjoint(
\r
296 OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram)))
\r
303 * @throws DatabaseException
\r
305 public static FlagClass.Type getFlagType(ReadGraph graph, Resource flag) throws DatabaseException {
\r
306 return getFlagType(graph, flag, null);
\r
311 * @throws DatabaseException
\r
313 public static FlagClass.Type getFlagType(ReadGraph graph, Resource flag, FlagClass.Type defaultFlagType) throws DatabaseException {
\r
314 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
315 Resource type = graph.getPossibleObject(flag, DIA.HasFlagType);
\r
316 return DiagramGraphUtil.toFlagType(DIA, type, defaultFlagType);
\r
321 * @throws DatabaseException
\r
323 public static void setFlagType(WriteGraph graph, Resource flag, FlagClass.Type type) throws DatabaseException {
\r
324 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
325 Resource flagType = DiagramGraphUtil.toFlagTypeResource(DIA, type);
\r
326 Resource existingFlagType = graph.getPossibleObject(flag, DIA.HasFlagType);
\r
327 if (flagType.equals(existingFlagType))
\r
329 graph.deny(flag, DIA.HasFlagType);
\r
330 // Resource defaultFlagType = graph.getPossibleObject(flag, DIA.HasFlagType);
\r
331 // if (flagType.equals(defaultFlagType))
\r
333 graph.claim(flag, DIA.HasFlagType, null, flagType);
\r
336 public static Set<Resource> findDirectlyConnectedComponents(ReadGraph graph, Resource flag) throws DatabaseException {
\r
337 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
338 ModelingResources MOD = ModelingResources.getInstance(graph);
\r
340 for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {
\r
341 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector);
\r
342 if (diagramConnection == null)
\r
345 Resource connection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
\r
346 if (connection == null)
\r
349 return new HashSet<Resource>(graph.getObjects(connection, STR.Connects));
\r
351 return Collections.emptySet();
\r
354 public static Set<Terminal> findDirectlyConnectedTerminals(ReadGraph graph, Resource flag) throws DatabaseException {
\r
355 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
356 ModelingResources MOD = ModelingResources.getInstance(graph);
\r
358 for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {
\r
359 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector);
\r
360 if (diagramConnection == null)
\r
363 Resource connection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
\r
364 if (connection == null)
\r
367 Set<Terminal> terminals = new HashSet<Terminal>();
\r
368 for (Statement stm : graph.getStatements(connection, STR.Connects)) {
\r
369 terminals.add(new Terminal(stm.getObject(), graph.getInverse(stm.getPredicate())));
\r
373 return Collections.emptySet();
\r
379 * @return set of (module, terminal relation, attachment relation) triples
\r
380 * @throws DatabaseException
\r
382 public static Set<Triple<Resource,Resource,Resource>> findDirectlyConnectedElementTerminals(ReadGraph graph, Resource toElement) throws DatabaseException {
\r
383 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
384 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
386 Set<Triple<Resource, Resource, Resource>> result = new HashSet<Triple<Resource, Resource, Resource>>();
\r
388 for (Resource connector : graph.getObjects(toElement, STR.IsConnectedTo)) {
\r
389 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector);
\r
390 if (diagramConnection == null)
\r
393 //System.out.println("DC: " + NameUtils.getSafeName(graph, diagramConnection, true));
\r
395 for (Statement connectionToConnector : graph.getStatements(diagramConnection, DIA.HasConnector)) {
\r
396 Resource connector2 = connectionToConnector.getObject();
\r
397 if (connector.equals(connector2))
\r
400 Resource attachmentRelation = connectionToConnector.getPredicate();
\r
402 // Get element + terminal relation
\r
403 for (Statement connectorToElement : graph.getStatements(connector2, STR.Connects)) {
\r
404 Resource element = connectorToElement.getObject();
\r
405 if (diagramConnection.equals(element))
\r
407 Resource terminalRelation = graph.getPossibleInverse(connectorToElement.getPredicate());
\r
408 if (terminalRelation == null)
\r
410 result.add(Triple.make(element, terminalRelation, attachmentRelation));
\r
418 public static Variable getPossibleFlagSignal(ReadGraph graph, Variable configuration, Resource flag, Resource type) throws DatabaseException {
\r
420 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
421 ModelingResources MOD = ModelingResources.getInstance(graph);
\r
423 Resource component = graph.getPossibleObject(flag, MOD.ElementToComponent);
\r
424 if (component != null && graph.isInstanceOf(component, type)) {
\r
425 Variable v = configuration.browsePossible(graph, component);
\r
430 Resource connector = graph.getPossibleObject(flag, DIA.Flag_ConnectionPoint);
\r
431 if(connector == null) return null;
\r
433 Resource connection = graph.sync(new PossibleObjectWithType(connector, DIA.IsConnectorOf, DIA.Connection));
\r
434 if(connection == null) return null;
\r
436 return getPossibleConnectionSignal(graph, configuration, connection, type);
\r
440 public static Variable getPossibleConnectionSignal(ReadGraph graph, Variable configuration, Resource connection, Resource type) throws DatabaseException {
\r
442 return graph.syncRequest(new PossibleConnectionSignal(configuration, connection, type), TransientCacheListener.<Variable>instance());
\r
446 public static class PossibleConnectionSignal extends TernaryRead<Variable, Resource, Resource, Variable> {
\r
448 public PossibleConnectionSignal(Variable configuration, Resource connection, Resource type) {
\r
449 super(configuration, connection, type);
\r
453 public Variable perform(ReadGraph graph) throws DatabaseException {
\r
455 ModelingResources MOD = ModelingResources.getInstance(graph);
\r
456 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
458 Resource connection = parameter2;
\r
459 Resource mapped = graph.getPossibleObject(connection, MOD.DiagramConnectionToConnection);
\r
460 if(mapped != null) connection = mapped;
\r
462 for (ResourceWithContext module : ConnectionBrowser.findConnectedComponents(graph, connection, parameter)) {
\r
463 if (graph.isInstanceOf(module.getResource(), parameter3)) {
\r
464 Resource element = graph.getPossibleObject(module.getResource(), MOD.ComponentToElement);
\r
465 if(element != null) {
\r
466 if(graph.isInstanceOf(element, DIA.Flag) || graph.isInstanceOf(element, DIA.Connection))
\r
467 return module.getContext();
\r
469 System.err.println("no element for " + NameUtils.getSafeName(graph, module.getResource()));
\r
481 * Verifies that the specified flag has the correct flag type as resolved
\r
482 * through {@link IFlagType}. Please note that using this method assumes
\r
483 * that the diagram mapping has been executed and the configuration is in
\r
484 * sync with the diagram.
\r
487 * @param modelingRules
\r
488 * modeling rules for getting the connection type of the flag for
\r
489 * retrieving {@link IFlagTypeReader} and {@link IFlagType}
\r
491 * the flag for to verify type
\r
493 * the current type of the flag
\r
494 * @throws DatabaseException
\r
496 public static void verifyFlagType(WriteGraph graph, IModelingRules modelingRules, Resource flag, FlagClass.Type flagType) throws DatabaseException {
\r
497 if (modelingRules != null) {
\r
498 // Follows the flag loading logic in FlagClassFactory.
\r
499 IFlagTypeReader ftr = null;
\r
500 Resource connectionType = DiagramGraphUtil.getConnectionTypeForFlag(graph, flag);
\r
501 if (connectionType != null) {
\r
502 //System.out.println("FLAG " + NameUtils.getSafeName(g, flag) + ", CONNECTION TYPE " + NameUtils.getSafeName(g, connectionType));
\r
503 ftr = graph.getPossibleAdapter(connectionType, IFlagTypeReader.class);
\r
506 //System.out.println("FLAG " + NameUtils.getSafeName(g, flag) + ", NO CONNECTION TYPE");
\r
507 ftr = graph.getPossibleAdapter(flag, IFlagTypeReader.class);
\r
511 IFlagType ft = ftr.read(graph, flag, modelingRules);
\r
513 FlagInfo info = ft.getInfo(graph);
\r
514 if (flagType != info.getType()) {
\r
515 FlagUtil.setFlagType(graph, flag, info.getType());
\r
522 public static List<Resource> setFlagExternal (WriteGraph graph, List<Resource> flags, boolean external) throws ServiceException {
\r
524 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
525 for (Resource flag : flags) {
\r
527 graph.claim(flag, DIA.ExternalFlag, DIA.ExternalFlag, flag);
\r
529 graph.deny(flag, DIA.ExternalFlag);
\r