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;
\r
14 import java.util.Arrays;
\r
15 import java.util.Set;
\r
17 import org.eclipse.core.runtime.IAdaptable;
\r
20 * A context used to represent a single visible UI item.
\r
23 * An INodeContext can be initialized to contain multiple constants accessible
\r
24 * with {@link ConstantKey}s through {@link #getConstant(ConstantKey)}.
\r
27 * It is vital that every instance of INodeContext contains a constant with the
\r
28 * {@link ConstantKey} {@link BuiltinKeys#INPUT}, since that data is used all
\r
29 * over the graph explorer framework for resolving labelers, imager, decorators
\r
34 * INodeContext must implement {@link #equals(Object)} and {@link #hashCode()}
\r
35 * to enable the graph explorer to work properly.
\r
38 * @see NodeContextBuilder
\r
39 * @see NodeContextUtil
\r
41 public interface NodeContext extends IAdaptable {
\r
43 NodeContext[] NONE = new NodeContext[0];
\r
46 * A key interface used for querying constants from INodeContext. Create
\r
47 * static instances of this interface to create re-usable keys.
\r
50 * See {@link BuiltinKeys} for standard concrete keys used in the
\r
53 * @param <T> type of the value stored with this key.
\r
55 * See NodeContextBuilder
\r
57 public static interface ConstantKey<T> {}
\r
60 * @param <T> the type of the value designated by the specified key
\r
62 * @return the value with the specified key or <code>null</code> there was
\r
63 * no value for the key
\r
64 * @throws ClassCastException if the key stored in the node is does not
\r
65 * match T. This should not happen.
\r
67 <T> T getConstant(ConstantKey<T> key);
\r
68 Set<ConstantKey<?>> getKeys();
\r
71 * Do not implement this directly, look at {@link PrimitiveQueryKey} and
\r
72 * {@link QueryKey} instead.
\r
74 public static interface CacheKey<T> {
\r
76 * This method must return a unique object that is used to decide which
\r
77 * QueryProcessor is used to calculate the query result.
\r
79 * The returned value is compared only using object identity (==), not
\r
82 * @return the identifier of this processor
\r
84 Object processorIdenfitier();
\r
88 * This key class is used for <i>non-leaf</i> queries that only functionally
\r
89 * perform other queries to produce their result.
\r
92 * These are always cleared (invalidated) or updated inside the query
\r
93 * manager. The methods available in {@link NodeQueryManager} are the only
\r
94 * methods within the query system that the query implementation can use. It
\r
95 * cannot perform lazy evaluation.
\r
97 * @see NodeQueryManager
\r
98 * @see NodeQueryProcessor
\r
100 public static abstract class QueryKey<T> implements CacheKey<T> {
\r
102 public Object processorIdenfitier() {
\r
108 * Primitive query keys are used only for <i>leaf</i> queries that do not
\r
109 * perform more queries. Only these queries are updated from external
\r
110 * sources that are registered through
\r
111 * {@link GraphExplorer#setDataSource(DataSource)}.
\r
114 * The difference between these queries and {@link QueryKey} queries is that
\r
115 * these queries cannot do any further queries, which is already prohibited
\r
116 * by the only available interface, {@link PrimitiveQueryUpdater}. Instead
\r
117 * these queries can use the
\r
118 * {@link PrimitiveQueryUpdater#scheduleReplace(NodeContext, PrimitiveQueryKey, T)}
\r
119 * method to store concrete values within the query manager and possibly
\r
120 * replace them later when lazy evaluation has completed. Replacing a lazily
\r
121 * evaluated result will automatically invalidate all queries depending on
\r
122 * this result, also causing the UI to respond to the changes.
\r
124 * @see PrimitiveQueryUpdater
\r
125 * @see PrimitiveQueryProcessor
\r
127 public static abstract class PrimitiveQueryKey<T> implements CacheKey<T> {
\r
129 public Object processorIdenfitier() {
\r
135 * This primitive query key implementation can be used for passing other
\r
136 * parameters to primitive queries besides the input {@link NodeContext}.
\r
139 * The extending class must implement the getKeyName() method to provide a
\r
140 * human-readable name for the key that is used in the default
\r
141 * {@link #toString()} implementation.
\r
144 * This class uses the class object as the default processor identifier
\r
145 * object (see {@link CacheKey#processorIdenfitier()}. This should work
\r
146 * out-of-the-box for most cases and need not be customized.
\r
148 public abstract static class ParametrizedPrimitiveQueryKey<T> extends PrimitiveQueryKey<T> {
\r
149 private final Object[] parameters;
\r
150 private final int hash;
\r
151 protected ParametrizedPrimitiveQueryKey(Object ... parameters) {
\r
152 this.parameters = parameters;
\r
153 this.hash = hash();
\r
157 public Object processorIdenfitier() {
\r
162 public String toString() {
\r
163 return getKeyName() + Arrays.toString(parameters);
\r
167 * @param <P> the assumed type of the parameter object
\r
168 * @param index the index of the reqeusted parameter
\r
169 * @return the parameter with the specified index
\r
170 * @throws ClassCastException if the key stored in the node is does not
\r
172 * @throws ArrayIndexOutOfBoundsException if a parameter with the
\r
173 * specified index is not availble.
\r
175 @SuppressWarnings("unchecked")
\r
176 public <P> P getParameter(int index) {
\r
177 return (P) parameters[index];
\r
180 public abstract String getKeyName();
\r
183 * Calculates the hash value for this key. The default implementation is
\r
184 * based on the hash of the actual key class and the hash of the
\r
187 * @return the hash value
\r
189 protected int hash() {
\r
190 return getClass().hashCode() * 31 + Arrays.hashCode(parameters);
\r
194 public boolean equals(Object obj) {
\r
199 if (getClass() != obj.getClass())
\r
201 ParametrizedPrimitiveQueryKey<?> o = (ParametrizedPrimitiveQueryKey<?>) obj;
\r
202 return Arrays.equals(parameters, o.parameters);
\r
206 public int hashCode() {
\r