]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui/src/org/simantics/browsing/ui/NodeContext.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.browsing.ui / src / org / simantics / browsing / ui / NodeContext.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.browsing.ui;
13
14 import java.util.Arrays;
15 import java.util.Set;
16
17 import org.eclipse.core.runtime.IAdaptable;
18
19 /**
20  * A context used to represent a single visible UI item.
21  * 
22  * <p>
23  * An INodeContext can be initialized to contain multiple constants accessible
24  * with {@link ConstantKey}s through {@link #getConstant(ConstantKey)}.
25  * </p>
26  * <p>
27  * It is vital that every instance of INodeContext contains a constant with the
28  * {@link ConstantKey} {@link BuiltinKeys#INPUT}, since that data is used all
29  * over the graph explorer framework for resolving labelers, imager, decorators
30  * and others.
31  * </p>
32  * 
33  * <p>
34  * INodeContext must implement {@link #equals(Object)} and {@link #hashCode()}
35  * to enable the graph explorer to work properly.
36  * </p>
37  * 
38  * @see NodeContextBuilder
39  * @see NodeContextUtil
40  */
41 public interface NodeContext extends IAdaptable {
42
43     NodeContext[] NONE = new NodeContext[0];
44
45     /**
46      * A key interface used for querying constants from INodeContext. Create
47      * static instances of this interface to create re-usable keys.
48      * 
49      * <p>
50      * See {@link BuiltinKeys} for standard concrete keys used in the
51      * implementations
52      * 
53      * @param <T> type of the value stored with this key.
54      * 
55      * See NodeContextBuilder
56      */
57     public static interface ConstantKey<T> {}
58
59     /**
60      * @param <T> the type of the value designated by the specified key
61      * @param key
62      * @return the value with the specified key or <code>null</code> there was
63      *         no value for the key
64      * @throws ClassCastException if the key stored in the node is does not
65      *         match T. This should not happen.
66      */
67     <T> T getConstant(ConstantKey<T> key);
68     Set<ConstantKey<?>> getKeys();
69
70     /**
71      * Do not implement this directly, look at {@link PrimitiveQueryKey} and
72      * {@link QueryKey} instead.
73      */
74     public static interface CacheKey<T> {
75         /**
76          * This method must return a unique object that is used to decide which
77          * QueryProcessor is used to calculate the query result.
78          * 
79          * The returned value is compared only using object identity (==), not
80          * equals.
81          * 
82          * @return the identifier of this processor
83          */
84         Object processorIdenfitier();
85     }
86
87     /**
88      * This key class is used for <i>non-leaf</i> queries that only functionally
89      * perform other queries to produce their result.
90      * 
91      * <p>
92      * These are always cleared (invalidated) or updated inside the query
93      * manager. The methods available in {@link NodeQueryManager} are the only
94      * methods within the query system that the query implementation can use. It
95      * cannot perform lazy evaluation.
96      * 
97      * @see NodeQueryManager
98      * @see NodeQueryProcessor
99      */
100     public static abstract class QueryKey<T> implements CacheKey<T> {
101         @Override
102         public Object processorIdenfitier() {
103             return this;
104         }
105     }
106
107     /**
108      * Primitive query keys are used only for <i>leaf</i> queries that do not
109      * perform more queries. Only these queries are updated from external
110      * sources that are registered through
111      * {@link GraphExplorer#setDataSource(DataSource)}.
112      * 
113      * <p>
114      * The difference between these queries and {@link QueryKey} queries is that
115      * these queries cannot do any further queries, which is already prohibited
116      * by the only available interface, {@link PrimitiveQueryUpdater}. Instead
117      * these queries can use the
118      * {@link PrimitiveQueryUpdater#scheduleReplace(NodeContext, PrimitiveQueryKey, T)}
119      * method to store concrete values within the query manager and possibly
120      * replace them later when lazy evaluation has completed. Replacing a lazily
121      * evaluated result will automatically invalidate all queries depending on
122      * this result, also causing the UI to respond to the changes.
123      * 
124      * @see PrimitiveQueryUpdater
125      * @see PrimitiveQueryProcessor
126      */
127     public static abstract class PrimitiveQueryKey<T> implements CacheKey<T> {
128         @Override
129         public Object processorIdenfitier() {
130             return this;
131         }
132     }
133
134     /**
135      * This primitive query key implementation can be used for passing other
136      * parameters to primitive queries besides the input {@link NodeContext}.
137      * 
138      * <p>
139      * The extending class must implement the getKeyName() method to provide a
140      * human-readable name for the key that is used in the default
141      * {@link #toString()} implementation.
142      * 
143      * <p>
144      * This class uses the class object as the default processor identifier
145      * object (see {@link CacheKey#processorIdenfitier()}. This should work
146      * out-of-the-box for most cases and need not be customized.
147      */
148     public abstract static class ParametrizedPrimitiveQueryKey<T> extends PrimitiveQueryKey<T> {
149         private final Object[] parameters;
150         private final int hash;
151         protected ParametrizedPrimitiveQueryKey(Object ... parameters) {
152             this.parameters = parameters;
153             this.hash = hash();
154         }
155
156         @Override
157         public Object processorIdenfitier() {
158             return getClass();
159         }
160
161         @Override
162         public String toString() {
163             return getKeyName() + Arrays.toString(parameters);
164         }
165
166         /**
167          * @param <P> the assumed type of the parameter object
168          * @param index the index of the reqeusted parameter
169          * @return the parameter with the specified index
170          * @throws ClassCastException if the key stored in the node is does not
171          *         match P.
172          * @throws ArrayIndexOutOfBoundsException if a parameter with the
173          *         specified index is not availble.
174          */
175         @SuppressWarnings("unchecked")
176         public <P> P getParameter(int index) {
177             return (P) parameters[index];
178         }
179
180         public abstract String getKeyName();
181
182         /**
183          * Calculates the hash value for this key. The default implementation is
184          * based on the hash of the actual key class and the hash of the
185          * parameters.
186          * 
187          * @return the hash value
188          */
189         protected int hash() {
190             return getClass().hashCode() * 31 + Arrays.hashCode(parameters);
191         }
192
193         @Override
194         public boolean equals(Object obj) {
195             if (this == obj)
196                 return true;
197             if (obj == null)
198                 return false;
199             if (getClass() != obj.getClass())
200                 return false;
201             ParametrizedPrimitiveQueryKey<?> o = (ParametrizedPrimitiveQueryKey<?>) obj;
202             return Arrays.equals(parameters, o.parameters);
203         }
204
205         @Override
206         public int hashCode() {
207             return hash;
208         }
209     }
210
211 }