comparison dwtx/jface/bindings/CachedBindingSet.d @ 16:e0f0aaf75edd

PopupDialog, bindings and actions
author Frank Benoit <benoit@tionex.de>
date Tue, 01 Apr 2008 08:00:31 +0200
parents
children 04b47443bb01
comparison
equal deleted inserted replaced
15:db8940420ed8 16:e0f0aaf75edd
1 /*******************************************************************************
2 * Copyright (c) 2004, 2007 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module dwtx.jface.bindings.CachedBindingSet;
14
15 import dwtx.jface.bindings.TriggerSequence;
16 import dwtx.jface.bindings.Binding;
17
18 import tango.util.collection.model.Map;
19
20 import dwtx.jface.util.Util;
21
22 import dwt.dwthelper.utils;
23
24 /**
25 * <p>
26 * A resolution of bindings for a given state. To see if we already have a
27 * cached binding set, just create one of these binding sets and then look it up
28 * in a map. If it is not already there, then add it and set the cached binding
29 * resolution.
30 * </p>
31 *
32 * @since 3.1
33 */
34 final class CachedBindingSet {
35
36 /**
37 * A factor for computing the hash code for all cached binding sets.
38 */
39 private const static int HASH_FACTOR = 89;
40
41 /**
42 * <p>
43 * A representation of the tree of active contexts at the time this cached
44 * binding set was computed. It is a map of context id (<code>String</code>)
45 * to context id (<code>String</code>). Each key represents one of the
46 * active contexts or one of its ancestors, while each value represents its
47 * parent. This is a way of perserving information about what the hierarchy
48 * looked like.
49 * </p>
50 * <p>
51 * This value will be <code>null</code> if the contexts were disregarded
52 * in the computation. It may also be empty. All of the keys are guaranteed
53 * to be non- <code>null</code>, but the values can be <code>null</code>
54 * (i.e., no parent).
55 * </p>
56 */
57 private const Map!(Object,Object) activeContextTree;
58
59 /**
60 * The map representing the resolved state of the bindings. This is a map of
61 * a trigger (<code>TriggerSequence</code>) to binding (<code>Binding</code>).
62 * This value may be <code>null</code> if it has not yet been initialized.
63 */
64 private Map!(Object,Object) bindingsByTrigger = null;
65
66 /**
67 * A map of triggers to collections of bindings. If this binding set
68 * contains conflicts, they are logged here.
69 *
70 * @since 3.3
71 */
72 private Map!(Object,Object) conflictsByTrigger = null;
73
74 /**
75 * The hash code for this object. This value is computed lazily, and marked
76 * as invalid when one of the values on which it is based changes.
77 */
78 private /+transient+/ int hashCode;
79
80 /**
81 * Whether <code>hashCode</code> still contains a valid value.
82 */
83 private /+transient+/ bool hashCodeComputed = false;
84
85 /**
86 * <p>
87 * The list of locales that were active at the time this binding set was
88 * computed. This list starts with the most specific representation of the
89 * locale, and moves to more general representations. For example, this
90 * array might look like ["en_US", "en", "", null].
91 * </p>
92 * <p>
93 * This value will never be <code>null</code>, and it will never be
94 * empty. It must contain at least one element, but its elements can be
95 * <code>null</code>.
96 * </p>
97 */
98 private const String[] locales;
99
100 /**
101 * <p>
102 * The list of platforms that were active at the time this binding set was
103 * computed. This list starts with the most specific representation of the
104 * platform, and moves to more general representations. For example, this
105 * array might look like ["gtk", "", null].
106 * </p>
107 * <p>
108 * This value will never be <code>null</code>, and it will never be
109 * empty. It must contain at least one element, but its elements can be
110 * <code>null</code>.
111 * </p>
112 */
113 private const String[] platforms;
114
115 /**
116 * A map of prefixes (<code>TriggerSequence</code>) to a map of
117 * available completions (possibly <code>null</code>, which means there
118 * is an exact match). The available completions is a map of trigger (<code>TriggerSequence</code>)
119 * to command identifier (<code>String</code>). This value is
120 * <code>null</code> if it has not yet been initialized.
121 */
122 private Map!(Object,Object) prefixTable = null;
123
124 /**
125 * <p>
126 * The list of schemes that were active at the time this binding set was
127 * computed. This list starts with the active scheme, and then continues
128 * with all of its ancestors -- in order. For example, this might look like
129 * ["emacs", "default"].
130 * </p>
131 * <p>
132 * This value will never be <code>null</code>, and it will never be
133 * empty. It must contain at least one element. Its elements cannot be
134 * <code>null</code>.
135 * </p>
136 */
137 private const String[] schemeIds;
138
139 /**
140 * The map representing the resolved state of the bindings. This is a map of
141 * a command id (<code>String</code>) to triggers (<code>Collection</code>
142 * of <code>TriggerSequence</code>). This value may be <code>null</code>
143 * if it has not yet been initialized.
144 */
145 private Map!(Object,Object) triggersByCommandId = null;
146
147 /**
148 * Constructs a new instance of <code>CachedBindingSet</code>.
149 *
150 * @param activeContextTree
151 * The set of context identifiers that were active when this
152 * binding set was calculated; may be empty. If it is
153 * <code>null</code>, then the contexts were disregarded in
154 * the computation. This is a map of context id (
155 * <code>String</code>) to parent context id (
156 * <code>String</code>). This is a way of caching the look of
157 * the context tree at the time the binding set was computed.
158 * @param locales
159 * The locales that were active when this binding set was
160 * calculated. The first element is the currently active locale,
161 * and it is followed by increasingly more general locales. This
162 * must not be <code>null</code> and must contain at least one
163 * element. The elements can be <code>null</code>, though.
164 * @param platforms
165 * The platform that were active when this binding set was
166 * calculated. The first element is the currently active
167 * platform, and it is followed by increasingly more general
168 * platforms. This must not be <code>null</code> and must
169 * contain at least one element. The elements can be
170 * <code>null</code>, though.
171 * @param schemeIds
172 * The scheme that was active when this binding set was
173 * calculated, followed by its ancestors. This may be
174 * <code>null</code or empty. The
175 * elements cannot be <code>null</code>.
176 */
177 this(Map!(Object,Object) activeContextTree, String[] locales,
178 String[] platforms, String[] schemeIds) {
179 if (locales is null) {
180 throw new NullPointerException("The locales cannot be null."); //$NON-NLS-1$
181 }
182
183 if (locales.length is 0) {
184 throw new NullPointerException("The locales cannot be empty."); //$NON-NLS-1$
185 }
186
187 if (platforms is null) {
188 throw new NullPointerException("The platforms cannot be null."); //$NON-NLS-1$
189 }
190
191 if (platforms.length is 0) {
192 throw new NullPointerException("The platforms cannot be empty."); //$NON-NLS-1$
193 }
194
195 this.activeContextTree = activeContextTree;
196 this.locales = locales;
197 this.platforms = platforms;
198 this.schemeIds = schemeIds;
199 }
200
201 /**
202 * Compares this binding set with another object. The objects will be equal
203 * if they are both instance of <code>CachedBindingSet</code> and have
204 * equivalent values for all of their properties.
205 *
206 * @param object
207 * The object with which to compare; may be <code>null</code>.
208 * @return <code>true</code> if they are both instances of
209 * <code>CachedBindingSet</code> and have the same values for all
210 * of their properties; <code>false</code> otherwise.
211 */
212 public final override int opEquals(Object object) {
213 if (!(cast(CachedBindingSet)object )) {
214 return false;
215 }
216
217 CachedBindingSet other = cast(CachedBindingSet) object;
218
219 if (!Util.opEquals(cast(Object)activeContextTree, cast(Object)other.activeContextTree)) {
220 return false;
221 }
222 if (!Util.opEquals(locales, other.locales)) {
223 return false;
224 }
225 if (!Util.opEquals(platforms, other.platforms)) {
226 return false;
227 }
228 return Util.opEquals(schemeIds, other.schemeIds);
229 }
230
231 /**
232 * Returns the map of command identifiers indexed by trigger sequence.
233 *
234 * @return A map of triggers (<code>TriggerSequence</code>) to bindings (<code>Binding</code>).
235 * This value may be <code>null</code> if this was not yet
236 * initialized.
237 */
238 final Map!(Object,Object) getBindingsByTrigger() {
239 return bindingsByTrigger;
240 }
241
242 /**
243 * Returns a map of conflicts for this set of contexts.
244 *
245 * @return A map of trigger to a collection of Bindings. May be
246 * <code>null</code>.
247 * @since 3.3
248 */
249 final Map!(Object,Object) getConflictsByTrigger() {
250 return conflictsByTrigger;
251 }
252
253 /**
254 * Returns the map of prefixes to a map of trigger sequence to command
255 * identifiers.
256 *
257 * @return A map of prefixes (<code>TriggerSequence</code>) to a map of
258 * available completions (possibly <code>null</code>, which means
259 * there is an exact match). The available completions is a map of
260 * trigger (<code>TriggerSequence</code>) to command identifier (<code>String</code>).
261 * This value may be <code>null</code> if it has not yet been
262 * initialized.
263 */
264 final Map!(Object,Object) getPrefixTable() {
265 return prefixTable;
266 }
267
268 /**
269 * Returns the map of triggers indexed by command identifiers.
270 *
271 * @return A map of command identifiers (<code>String</code>) to
272 * triggers (<code>Collection</code> of
273 * <code>TriggerSequence</code>). This value may be
274 * <code>null</code> if this was not yet initialized.
275 */
276 final Map!(Object,Object) getTriggersByCommandId() {
277 return triggersByCommandId;
278 }
279
280 /**
281 * Computes the hash code for this cached binding set. The hash code is
282 * based only on the immutable values. This allows the set to be created and
283 * checked for in a hashed collection <em>before</em> doing any
284 * computation.
285 *
286 * @return The hash code for this cached binding set.
287 */
288 public final override hash_t toHash() {
289 if (!hashCodeComputed) {
290
291 auto HASH_INITIAL = dwt.dwthelper.utils.toHash(CachedBindingSet.classinfo.name );
292 hashCode = HASH_INITIAL;
293 hashCode = hashCode * HASH_FACTOR
294 + Util.toHash(cast(Object)activeContextTree);
295 hashCode = hashCode * HASH_FACTOR + Util.toHash(locales);
296 hashCode = hashCode * HASH_FACTOR + Util.toHash(platforms);
297 hashCode = hashCode * HASH_FACTOR + Util.toHash(schemeIds);
298 hashCodeComputed = true;
299 }
300
301 return hashCode;
302 }
303
304 /**
305 * Sets the map of command identifiers indexed by trigger.
306 *
307 * @param commandIdsByTrigger
308 * The map to set; must not be <code>null</code>. This is a
309 * map of triggers (<code>TriggerSequence</code>) to binding (<code>Binding</code>).
310 */
311 final void setBindingsByTrigger(Map!(Object,Object) commandIdsByTrigger) {
312 if (commandIdsByTrigger is null) {
313 throw new NullPointerException(
314 "Cannot set a null binding resolution"); //$NON-NLS-1$
315 }
316
317 this.bindingsByTrigger = commandIdsByTrigger;
318 }
319
320 /**
321 * Sets the map of conflicting bindings by trigger.
322 *
323 * @param conflicts
324 * The map to set; must not be <code>null</code>.
325 * @since 3.3
326 */
327 final void setConflictsByTrigger(Map!(Object,Object) conflicts) {
328 if (conflicts is null) {
329 throw new NullPointerException(
330 "Cannot set a null binding conflicts"); //$NON-NLS-1$
331 }
332 conflictsByTrigger = conflicts;
333 }
334
335 /**
336 * Sets the map of prefixes to a map of trigger sequence to command
337 * identifiers.
338 *
339 * @param prefixTable
340 * A map of prefixes (<code>TriggerSequence</code>) to a map
341 * of available completions (possibly <code>null</code>, which
342 * means there is an exact match). The available completions is a
343 * map of trigger (<code>TriggerSequence</code>) to command
344 * identifier (<code>String</code>). Must not be
345 * <code>null</code>.
346 */
347 final void setPrefixTable(Map!(Object,Object) prefixTable) {
348 if (prefixTable is null) {
349 throw new NullPointerException("Cannot set a null prefix table"); //$NON-NLS-1$
350 }
351
352 this.prefixTable = prefixTable;
353 }
354
355 /**
356 * Sets the map of triggers indexed by command identifiers.
357 *
358 * @param triggersByCommandId
359 * The map to set; must not be <code>null</code>. This is a
360 * map of command identifiers (<code>String</code>) to
361 * triggers (<code>Collection</code> of
362 * <code>TriggerSequence</code>).
363 */
364 final void setTriggersByCommandId(Map!(Object,Object) triggersByCommandId) {
365 if (triggersByCommandId is null) {
366 throw new NullPointerException(
367 "Cannot set a null binding resolution"); //$NON-NLS-1$
368 }
369
370 this.triggersByCommandId = triggersByCommandId;
371 }
372 }