1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.browsing.ui.common;
14 import java.util.Collections;
15 import java.util.HashMap;
19 import org.eclipse.core.runtime.IAdaptable;
20 import org.simantics.browsing.ui.BuiltinKeys;
21 import org.simantics.browsing.ui.NodeContext;
22 import org.simantics.browsing.ui.NodeContext.ConstantKey;
23 import org.simantics.browsing.ui.content.Viewpoint;
24 import org.simantics.utils.datastructures.ArrayMap;
27 * Use this class in {@link Viewpoint}, and particularly
28 * {@link Viewpoint#getChildren()} implementations to construct new INodeContext
31 * @author Antti Villberg
32 * @author Tuukka Lehtonen
34 public final class NodeContextBuilder {
36 private static Set<ConstantKey<?>> SINGLE_INPUT_KEYS =
37 Collections.<ConstantKey<?>> singleton(BuiltinKeys.INPUT);
39 MapNodeContext context;
41 private static class InputNodeContext implements NodeContext {
45 private InputNodeContext(Object input) {
49 @SuppressWarnings({ "unchecked", "rawtypes" })
51 public Object getAdapter(Class adapter) {
52 if (NodeContext.class.equals(adapter))
55 if (adapter.isAssignableFrom(input.getClass()))
57 if (input instanceof IAdaptable)
58 return ((IAdaptable) input).getAdapter(adapter);
63 @SuppressWarnings("unchecked")
65 public <T> T getConstant(ConstantKey<T> key) {
66 return key == BuiltinKeys.INPUT ? (T) input : null;
70 public Set<ConstantKey<?>> getKeys() {
71 return SINGLE_INPUT_KEYS;
75 public int hashCode() {
76 return ((input == null) ? 0 : input.hashCode());
80 public boolean equals(Object obj) {
85 if (getClass() != obj.getClass())
87 InputNodeContext other = (InputNodeContext) obj;
89 if (other.input != null)
91 } else if (!input.equals(other.input))
97 public String toString() {
98 return "InputNodeContext(" + hashCode() + ") [" + input + "]";
102 public static class MapNodeContext implements NodeContext {
104 private Map<ConstantKey<?>, Object> data;
107 private MapNodeContext() {
111 this.hash = (data == null) ? 0 : data.hashCode();
114 @SuppressWarnings({ "unchecked", "rawtypes" })
116 public Object getAdapter(Class adapter) {
117 if (NodeContext.class.equals(adapter))
119 Object input = data.get(BuiltinKeys.INPUT);
121 if (adapter.isAssignableFrom(input.getClass()))
123 if (input instanceof IAdaptable)
124 return ((IAdaptable) input).getAdapter(adapter);
129 @SuppressWarnings("unchecked")
131 public <T> T getConstant(ConstantKey<T> key) {
132 return data != null ? (T) data.get(key) : null;
136 public Set<ConstantKey<?>> getKeys() {
137 return data.keySet();
141 public int hashCode() {
146 public boolean equals(Object obj) {
151 if (getClass() != obj.getClass())
153 MapNodeContext other = (MapNodeContext) obj;
155 if (other.data != null)
157 } else if (!data.equals(other.data))
163 public String toString() {
164 return "MapNodeContext(" + hashCode() + ") [" + (data != null ? data : "") + "]";
168 public NodeContextBuilder() {
169 this.context = new MapNodeContext();
172 public <T> NodeContextBuilder define(ConstantKey<T> key, T value) {
173 if (context.data == null)
174 context.data = new HashMap<ConstantKey<?>, Object>();
175 context.data.put(key, value);
179 public NodeContext createContext() {
185 * A special case builder for an INodeContext that will only take one
186 * (key,value) pair and insert that into the built INodeContext.
189 * This method works around the need to create NodeContextBuilder instances.
193 * Notice that your input key and value must properly implement
194 * <code>equals</code> and <code>hashCode</code> in order for
195 * GraphExplorer's automatic node expansion state tracking to work.
200 * @return an INodeContext containing a single constant as specified by
201 * <code>key</code> and <code>value</code>
203 public static <T> NodeContext buildWithSingleData(ConstantKey<T> key, T value) {
204 MapNodeContext context = new MapNodeContext();
205 context.data = Collections.<ConstantKey<?>, Object>singletonMap(key, value);
211 * A generic case builder for an INodeContext that will take as many
212 * (key,value) pairs as it is given and insert all of them into a map
213 * that is backing the built INodeContext implementation.
216 * This method works around the need to create NodeContextBuilder instances.
220 * Notice that your input keys and values must properly implement
221 * <code>equals</code> and <code>hashCode</code> in order for
222 * GraphExplorer's automatic node expansion state tracking to work.
225 * @param keyValuePairs
226 * @return an INodeContext containing the specified key,value pairs as its
229 public static <T> NodeContext buildWithData(Object... keyValuePairs) {
230 assert keyValuePairs.length % 2 == 0;
231 MapNodeContext context = new MapNodeContext();
232 int size = keyValuePairs.length;
233 Map<ConstantKey<?>, Object> map = new HashMap<ConstantKey<?>, Object>(size);
235 for (int i = 0; i < keyValuePairs.length; i += 2) {
236 map.put((ConstantKey<?>) keyValuePairs[i], keyValuePairs[i+1]);
245 * A generic case builder for an INodeContext that will take as many
246 * (key,value) pairs as it is given and insert all of them into a map that
247 * is backing the built INodeContext implementation. This method takes the
248 * keys and values separately, which allows the use of {@link ArrayMap} that
249 * provides a space-optimized Map implementation. Note that the key set of
250 * an {@link ArrayMap} is immutable.
253 * This method works around the need to create NodeContextBuilder instances.
257 * Notice that your input keys and values must properly implement
258 * <code>equals</code> and <code>hashCode</code> in order for
259 * GraphExplorer's automatic node expansion state tracking to work.
262 * @param keys the keys of the map, must equal values array in size
263 * @param values the values of the map, must equal keys array in size
264 * @return a <code>NodeContext</code> containing the specified key,value
265 * pairs as its constants
267 public static <T> NodeContext buildWithData(ConstantKey<?>[] keys, Object[] values) {
268 assert keys.length == values.length;
269 MapNodeContext context = new MapNodeContext();
270 Map<ConstantKey<?>, Object> map = new ArrayMap<ConstantKey<?>, Object>(keys, values);
277 * A special case builder for an INodeContext that will only take one
278 * (key,value) pair and insert that into the built INodeContext.
281 * This method works around the need to create NodeContextBuilder instances.
285 * Notice that your input object must properly implement <code>equals</code>
286 * and <code>hashCode</code> in order for GraphExplorer's automatic node
287 * expansion state tracking to work.
291 * @return an INodeContext containing the specified object as with the key
292 * {@link BuiltinKeys#INPUT}
294 public static NodeContext buildWithInput(Object input) {
295 return new InputNodeContext(input);