]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/NodeContextBuilder.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.browsing.ui.common / src / org / simantics / browsing / ui / common / NodeContextBuilder.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.browsing.ui.common;\r
13 \r
14 import java.util.Collections;\r
15 import java.util.HashMap;\r
16 import java.util.Map;\r
17 import java.util.Set;\r
18 \r
19 import org.eclipse.core.runtime.IAdaptable;\r
20 import org.simantics.browsing.ui.BuiltinKeys;\r
21 import org.simantics.browsing.ui.NodeContext;\r
22 import org.simantics.browsing.ui.NodeContext.ConstantKey;\r
23 import org.simantics.browsing.ui.content.Viewpoint;\r
24 import org.simantics.utils.datastructures.ArrayMap;\r
25 \r
26 /**\r
27  * Use this class in {@link Viewpoint}, and particularly\r
28  * {@link Viewpoint#getChildren()} implementations to construct new INodeContext\r
29  * instances.\r
30  * \r
31  * @author Antti Villberg\r
32  * @author Tuukka Lehtonen\r
33  */\r
34 public final class NodeContextBuilder {\r
35 \r
36     private static Set<ConstantKey<?>> SINGLE_INPUT_KEYS =\r
37         Collections.<ConstantKey<?>> singleton(BuiltinKeys.INPUT);\r
38 \r
39     MapNodeContext context;\r
40 \r
41     private static class InputNodeContext implements NodeContext {\r
42 \r
43         final Object input;\r
44 \r
45         private InputNodeContext(Object input) {\r
46             this.input = input;\r
47         }\r
48 \r
49         @SuppressWarnings({ "unchecked", "rawtypes" })\r
50         @Override\r
51         public Object getAdapter(Class adapter) {\r
52             if (NodeContext.class.equals(adapter))\r
53                 return this;\r
54             if (input != null) {\r
55                 if (adapter.isAssignableFrom(input.getClass()))\r
56                     return input;\r
57                 if (input instanceof IAdaptable)\r
58                     return ((IAdaptable) input).getAdapter(adapter);\r
59             }\r
60             return null;\r
61         }\r
62 \r
63         @SuppressWarnings("unchecked")\r
64         @Override\r
65         public <T> T getConstant(ConstantKey<T> key) {\r
66             return key == BuiltinKeys.INPUT ? (T) input : null;\r
67         }\r
68 \r
69         @Override\r
70         public Set<ConstantKey<?>> getKeys() {\r
71             return SINGLE_INPUT_KEYS;\r
72         }\r
73 \r
74         @Override\r
75         public int hashCode() {\r
76             return ((input == null) ? 0 : input.hashCode());\r
77         }\r
78 \r
79         @Override\r
80         public boolean equals(Object obj) {\r
81             if (this == obj)\r
82                 return true;\r
83             if (obj == null)\r
84                 return false;\r
85             if (getClass() != obj.getClass())\r
86                 return false;\r
87             InputNodeContext other = (InputNodeContext) obj;\r
88             if (input == null) {\r
89                 if (other.input != null)\r
90                     return false;\r
91             } else if (!input.equals(other.input))\r
92                 return false;\r
93             return true;\r
94         }\r
95 \r
96         @Override\r
97         public String toString() {\r
98             return "InputNodeContext(" + hashCode() + ") [" + input + "]";\r
99         }\r
100     }\r
101 \r
102     public static class MapNodeContext implements NodeContext {\r
103 \r
104         private Map<ConstantKey<?>, Object> data;\r
105         private int hash;\r
106 \r
107         private MapNodeContext() {\r
108         }\r
109 \r
110         void makeHash() {\r
111             this.hash = (data == null) ? 0 : data.hashCode();\r
112         }\r
113 \r
114         @SuppressWarnings({ "unchecked", "rawtypes" })\r
115         @Override\r
116         public Object getAdapter(Class adapter) {\r
117             if (NodeContext.class.equals(adapter))\r
118                 return this;\r
119             Object input = data.get(BuiltinKeys.INPUT);\r
120             if (input != null) {\r
121                 if (adapter.isAssignableFrom(input.getClass()))\r
122                     return input;\r
123                 if (input instanceof IAdaptable)\r
124                     return ((IAdaptable) input).getAdapter(adapter);\r
125             }\r
126             return null;\r
127         }\r
128 \r
129         @SuppressWarnings("unchecked")\r
130         @Override\r
131         public <T> T getConstant(ConstantKey<T> key) {\r
132             return data != null ? (T) data.get(key) : null;\r
133         }\r
134 \r
135         @Override\r
136         public Set<ConstantKey<?>> getKeys() {\r
137             return data.keySet();\r
138         }\r
139 \r
140         @Override\r
141         public int hashCode() {\r
142             return hash;\r
143         }\r
144 \r
145         @Override\r
146         public boolean equals(Object obj) {\r
147             if (this == obj)\r
148                 return true;\r
149             if (obj == null)\r
150                 return false;\r
151             if (getClass() != obj.getClass())\r
152                 return false;\r
153             MapNodeContext other = (MapNodeContext) obj;\r
154             if (data == null) {\r
155                 if (other.data != null)\r
156                     return false;\r
157             } else if (!data.equals(other.data))\r
158                 return false;\r
159             return true;\r
160         }\r
161 \r
162         @Override\r
163         public String toString() {\r
164             return "MapNodeContext(" + hashCode() + ") [" + (data != null ? data : "") + "]";\r
165         }\r
166     }\r
167 \r
168     public NodeContextBuilder() {\r
169         this.context = new MapNodeContext();\r
170     }\r
171 \r
172     public <T> NodeContextBuilder define(ConstantKey<T> key, T value) {\r
173         if (context.data == null)\r
174             context.data = new HashMap<ConstantKey<?>, Object>();\r
175         context.data.put(key, value);\r
176         return this;\r
177     }\r
178 \r
179     public NodeContext createContext() {\r
180         context.makeHash();\r
181         return context;\r
182     }\r
183 \r
184     /**\r
185      * A special case builder for an INodeContext that will only take one\r
186      * (key,value) pair and insert that into the built INodeContext.\r
187      * \r
188      * <p>\r
189      * This method works around the need to create NodeContextBuilder instances.\r
190      * </p>\r
191      * \r
192      * <p>\r
193      * Notice that your input key and value must properly implement\r
194      * <code>equals</code> and <code>hashCode</code> in order for\r
195      * GraphExplorer's automatic node expansion state tracking to work.\r
196      * </p>\r
197      * \r
198      * @param key\r
199      * @param value\r
200      * @return an INodeContext containing a single constant as specified by\r
201      *         <code>key</code> and <code>value</code>\r
202      */\r
203     public static <T> NodeContext buildWithSingleData(ConstantKey<T> key, T value) {\r
204         MapNodeContext context = new MapNodeContext();\r
205         context.data = Collections.<ConstantKey<?>, Object>singletonMap(key, value);\r
206         context.makeHash();\r
207         return context;\r
208     }\r
209 \r
210     /**\r
211      * A generic case builder for an INodeContext that will take as many\r
212      * (key,value) pairs as it is given and insert all of them into a map\r
213      * that is backing the built INodeContext implementation.\r
214      * \r
215      * <p>\r
216      * This method works around the need to create NodeContextBuilder instances.\r
217      * </p>\r
218      * \r
219      * <p>\r
220      * Notice that your input keys and values must properly implement\r
221      * <code>equals</code> and <code>hashCode</code> in order for\r
222      * GraphExplorer's automatic node expansion state tracking to work.\r
223      * </p>\r
224      * \r
225      * @param keyValuePairs\r
226      * @return an INodeContext containing the specified key,value pairs as its\r
227      *         constants\r
228      */\r
229     public static <T> NodeContext buildWithData(Object... keyValuePairs) {\r
230         assert keyValuePairs.length % 2 == 0;\r
231         MapNodeContext context = new MapNodeContext();\r
232         int size = keyValuePairs.length;\r
233         Map<ConstantKey<?>, Object> map = new HashMap<ConstantKey<?>, Object>(size);\r
234 \r
235         for (int i = 0; i < keyValuePairs.length; i += 2) {\r
236             map.put((ConstantKey<?>) keyValuePairs[i], keyValuePairs[i+1]);\r
237         }\r
238 \r
239         context.data = map;\r
240         context.makeHash();\r
241         return context;\r
242     }\r
243 \r
244     /**\r
245      * A generic case builder for an INodeContext that will take as many\r
246      * (key,value) pairs as it is given and insert all of them into a map that\r
247      * is backing the built INodeContext implementation. This method takes the\r
248      * keys and values separately, which allows the use of {@link ArrayMap} that\r
249      * provides a space-optimized Map implementation. Note that the key set of\r
250      * an {@link ArrayMap} is immutable.\r
251      * \r
252      * <p>\r
253      * This method works around the need to create NodeContextBuilder instances.\r
254      * </p>\r
255      * \r
256      * <p>\r
257      * Notice that your input keys and values must properly implement\r
258      * <code>equals</code> and <code>hashCode</code> in order for\r
259      * GraphExplorer's automatic node expansion state tracking to work.\r
260      * </p>\r
261      * \r
262      * @param keys the keys of the map, must equal values array in size\r
263      * @param values the values of the map, must equal keys array in size\r
264      * @return a <code>NodeContext</code> containing the specified key,value\r
265      *         pairs as its constants\r
266      */\r
267     public static <T> NodeContext buildWithData(ConstantKey<?>[] keys, Object[] values) {\r
268         assert keys.length == values.length;\r
269         MapNodeContext context = new MapNodeContext();\r
270         Map<ConstantKey<?>, Object> map = new ArrayMap<ConstantKey<?>, Object>(keys, values);\r
271         context.data = map;\r
272         context.makeHash();\r
273         return context;\r
274     }\r
275 \r
276     /**\r
277      * A special case builder for an INodeContext that will only take one\r
278      * (key,value) pair and insert that into the built INodeContext.\r
279      * \r
280      * <p>\r
281      * This method works around the need to create NodeContextBuilder instances.\r
282      * </p>\r
283      * \r
284      * <p>\r
285      * Notice that your input object must properly implement <code>equals</code>\r
286      * and <code>hashCode</code> in order for GraphExplorer's automatic node\r
287      * expansion state tracking to work.\r
288      * </p>\r
289      * \r
290      * @param input\r
291      * @return an INodeContext containing the specified object as with the key\r
292      *         {@link BuiltinKeys#INPUT}\r
293      */\r
294     public static NodeContext buildWithInput(Object input) {\r
295         return new InputNodeContext(input);\r
296     }\r
297 \r
298 }\r