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.browsing.ui.common;
\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
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
27 * Use this class in {@link Viewpoint}, and particularly
\r
28 * {@link Viewpoint#getChildren()} implementations to construct new INodeContext
\r
31 * @author Antti Villberg
\r
32 * @author Tuukka Lehtonen
\r
34 public final class NodeContextBuilder {
\r
36 private static Set<ConstantKey<?>> SINGLE_INPUT_KEYS =
\r
37 Collections.<ConstantKey<?>> singleton(BuiltinKeys.INPUT);
\r
39 MapNodeContext context;
\r
41 private static class InputNodeContext implements NodeContext {
\r
45 private InputNodeContext(Object input) {
\r
49 @SuppressWarnings({ "unchecked", "rawtypes" })
\r
51 public Object getAdapter(Class adapter) {
\r
52 if (NodeContext.class.equals(adapter))
\r
54 if (input != null) {
\r
55 if (adapter.isAssignableFrom(input.getClass()))
\r
57 if (input instanceof IAdaptable)
\r
58 return ((IAdaptable) input).getAdapter(adapter);
\r
63 @SuppressWarnings("unchecked")
\r
65 public <T> T getConstant(ConstantKey<T> key) {
\r
66 return key == BuiltinKeys.INPUT ? (T) input : null;
\r
70 public Set<ConstantKey<?>> getKeys() {
\r
71 return SINGLE_INPUT_KEYS;
\r
75 public int hashCode() {
\r
76 return ((input == null) ? 0 : input.hashCode());
\r
80 public boolean equals(Object obj) {
\r
85 if (getClass() != obj.getClass())
\r
87 InputNodeContext other = (InputNodeContext) obj;
\r
88 if (input == null) {
\r
89 if (other.input != null)
\r
91 } else if (!input.equals(other.input))
\r
97 public String toString() {
\r
98 return "InputNodeContext(" + hashCode() + ") [" + input + "]";
\r
102 public static class MapNodeContext implements NodeContext {
\r
104 private Map<ConstantKey<?>, Object> data;
\r
107 private MapNodeContext() {
\r
111 this.hash = (data == null) ? 0 : data.hashCode();
\r
114 @SuppressWarnings({ "unchecked", "rawtypes" })
\r
116 public Object getAdapter(Class adapter) {
\r
117 if (NodeContext.class.equals(adapter))
\r
119 Object input = data.get(BuiltinKeys.INPUT);
\r
120 if (input != null) {
\r
121 if (adapter.isAssignableFrom(input.getClass()))
\r
123 if (input instanceof IAdaptable)
\r
124 return ((IAdaptable) input).getAdapter(adapter);
\r
129 @SuppressWarnings("unchecked")
\r
131 public <T> T getConstant(ConstantKey<T> key) {
\r
132 return data != null ? (T) data.get(key) : null;
\r
136 public Set<ConstantKey<?>> getKeys() {
\r
137 return data.keySet();
\r
141 public int hashCode() {
\r
146 public boolean equals(Object obj) {
\r
151 if (getClass() != obj.getClass())
\r
153 MapNodeContext other = (MapNodeContext) obj;
\r
154 if (data == null) {
\r
155 if (other.data != null)
\r
157 } else if (!data.equals(other.data))
\r
163 public String toString() {
\r
164 return "MapNodeContext(" + hashCode() + ") [" + (data != null ? data : "") + "]";
\r
168 public NodeContextBuilder() {
\r
169 this.context = new MapNodeContext();
\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
179 public NodeContext createContext() {
\r
180 context.makeHash();
\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
189 * This method works around the need to create NodeContextBuilder instances.
\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
200 * @return an INodeContext containing a single constant as specified by
\r
201 * <code>key</code> and <code>value</code>
\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
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
216 * This method works around the need to create NodeContextBuilder instances.
\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
225 * @param keyValuePairs
\r
226 * @return an INodeContext containing the specified key,value pairs as its
\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
235 for (int i = 0; i < keyValuePairs.length; i += 2) {
\r
236 map.put((ConstantKey<?>) keyValuePairs[i], keyValuePairs[i+1]);
\r
239 context.data = map;
\r
240 context.makeHash();
\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
253 * This method works around the need to create NodeContextBuilder instances.
\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
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
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
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
281 * This method works around the need to create NodeContextBuilder instances.
\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
291 * @return an INodeContext containing the specified object as with the key
\r
292 * {@link BuiltinKeys#INPUT}
\r
294 public static NodeContext buildWithInput(Object input) {
\r
295 return new InputNodeContext(input);
\r