Merge commit 'bd5bc6e45f700e755b61bd112631796631330ecb'
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / connection / ModelledConnectionAdvisor.java
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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.diagram.connection;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Arrays;\r
16 \r
17 import org.simantics.db.ReadGraph;\r
18 import org.simantics.db.RequestProcessor;\r
19 import org.simantics.db.Resource;\r
20 import org.simantics.db.Session;\r
21 import org.simantics.db.exception.DatabaseException;\r
22 import org.simantics.db.request.Read;\r
23 import org.simantics.diagram.content.ConnectionUtil;\r
24 import org.simantics.g2d.connection.IConnectionAdvisor;\r
25 import org.simantics.g2d.diagram.handler.Topology.Terminal;\r
26 import org.simantics.g2d.element.ElementUtils;\r
27 import org.simantics.g2d.element.IElement;\r
28 import org.simantics.g2d.elementclass.FlagHandler;\r
29 import org.simantics.structural2.modelingRules.CPIgnore;\r
30 import org.simantics.structural2.modelingRules.ConnectionJudgement;\r
31 import org.simantics.structural2.modelingRules.ConnectionJudgementType;\r
32 import org.simantics.structural2.modelingRules.IConnectionPoint;\r
33 import org.simantics.structural2.modelingRules.IModelingRules;\r
34 \r
35 /**\r
36  * To customize, prefer overriding\r
37  * {@link #canBeConnected(ReadGraph, IElement, Terminal, IElement, Terminal)}\r
38  * and {@link #canBeginConnection(ReadGraph, IElement, Terminal)}.\r
39  * \r
40  * @author Hannu Niemistö\r
41  */\r
42 public class ModelledConnectionAdvisor implements IConnectionAdvisor {\r
43 \r
44     protected IModelingRules modelingRules;\r
45     protected Session        session;\r
46 \r
47     /**\r
48      * @param modelingRules\r
49      * @param session\r
50      */\r
51     public ModelledConnectionAdvisor(IModelingRules modelingRules,\r
52             Session session) {\r
53         this.modelingRules = modelingRules;\r
54         this.session = session;\r
55     }\r
56 \r
57     protected IConnectionPoint getConnectionPoint(ReadGraph g, IElement element, Terminal term) throws DatabaseException {\r
58         return getConnectionPoint(g, element, term, false);\r
59     }\r
60 \r
61     protected IConnectionPoint getConnectionPoint(ReadGraph g, IElement element, Terminal term, boolean ignoreUnrecognized) throws DatabaseException {\r
62         Object obj = null;\r
63         if (element != null)\r
64             obj = ElementUtils.getObject(element);\r
65 \r
66         if (obj instanceof Resource) {\r
67             Resource elementResource = (Resource) obj;\r
68             return ConnectionUtil.toConnectionPoint(g, elementResource, term);\r
69         }\r
70 \r
71         // FIXME: this currently allows connections to begin from flags\r
72         // but is rather hackish.\r
73         if (element.getElementClass().containsClass(FlagHandler.class)) {\r
74             return CPIgnore.NULL_INSTANCE;\r
75         }\r
76 \r
77         if (ignoreUnrecognized)\r
78             return CPIgnore.NULL_INSTANCE;\r
79 \r
80         throw new IllegalArgumentException("Cannot get IConnectionPoint for (element,terminal) pair:\n\t" + element + "\n\t" + term);\r
81     }\r
82 \r
83     @Override\r
84     public Object canBeConnected(Object backend,\r
85             final IElement element1, final Terminal term1,\r
86             final IElement element2, final Terminal term2) {\r
87         try {\r
88             if (backend == null)\r
89                 backend = session;\r
90             return ((RequestProcessor)backend).syncRequest(new Read<Object>() {\r
91                 @Override\r
92                 public Object perform(ReadGraph g) throws DatabaseException {\r
93                     return canBeConnected(g, element1, term1, element2, term2);\r
94                 }\r
95             });\r
96         } catch(DatabaseException e) {\r
97             e.printStackTrace();\r
98             return null;\r
99         }\r
100     }\r
101 \r
102     @Override\r
103     public boolean canBeginConnection(Object backend,\r
104             final IElement element, final Terminal term) {\r
105         try {\r
106             if (backend == null)\r
107                 backend = session;\r
108             return ((RequestProcessor)backend).syncRequest(new Read<Boolean>() {\r
109                 @Override\r
110                 public Boolean perform(ReadGraph g) throws DatabaseException {\r
111                     return canBeginConnection(g, element, term);\r
112                 }\r
113             });\r
114         } catch (DatabaseException e) {\r
115             e.printStackTrace();\r
116             return false;\r
117         }\r
118     }\r
119 \r
120     protected Object canBeConnected(ReadGraph graph,\r
121             IElement element1, Terminal term1,\r
122             IElement element2, Terminal term2) throws DatabaseException {\r
123         ArrayList<IConnectionPoint> cps = new ArrayList<IConnectionPoint>(2);\r
124         if (element1 != null)\r
125             cps.add(getConnectionPoint(graph, element1, term1, true));\r
126         if (element2 != null)\r
127             cps.add(getConnectionPoint(graph, element2, term2, true));\r
128 \r
129         ConnectionJudgement judgement = modelingRules.judgeConnection(graph, cps);\r
130         if (judgement.type == ConnectionJudgementType.LEGAL\r
131                 // #6751, Apros #12404: a connection should not be automatically\r
132                 // denied just because it is not perfectly legal. Further legality\r
133                 // should be decided on the client side even though the IConnectionAdvisor\r
134                 // interface is not documented to return ConnectionJudgement instances,\r
135                 // because the interface knows nothing about this class.\r
136                 || judgement.type == ConnectionJudgementType.CANBEMADELEGAL) \r
137             return judgement;\r
138         return null;\r
139     }\r
140 \r
141     protected boolean canBeginConnection(ReadGraph graph,\r
142             IElement element, Terminal term) throws DatabaseException {\r
143         return modelingRules.judgeConnection(graph,\r
144                 Arrays.asList(getConnectionPoint(graph, element, term)))\r
145                 .type != ConnectionJudgementType.ILLEGAL;\r
146     }\r
147 \r
148 }\r