001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.texteditor;
011:
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: import org.eclipse.core.runtime.Assert;
017: import org.eclipse.core.runtime.ListenerList;
018:
019: import org.eclipse.jface.preference.IPreferenceStore;
020: import org.eclipse.jface.util.IPropertyChangeListener;
021: import org.eclipse.jface.util.PropertyChangeEvent;
022:
023: /**
024: * Preference store that composes multiple preference stores in a
025: * chain and serves a preference value from the first preference store in the
026: * chain that contains the preference.
027: * <p>
028: * This preference store is read-only i.e. write access
029: * throws an {@link java.lang.UnsupportedOperationException}.</p>
030: *
031: * @since 3.0
032: */
033: public class ChainedPreferenceStore implements IPreferenceStore {
034:
035: /** Child preference stores. */
036: private IPreferenceStore[] fPreferenceStores;
037:
038: /** Listeners on this chained preference store. */
039: private ListenerList fClientListeners = new ListenerList(
040: ListenerList.IDENTITY);
041:
042: /** Listeners on the child preference stores. */
043: private List fChildListeners = new ArrayList();
044:
045: /**
046: * Listener on the chained preference stores. Forwards only the events
047: * that are visible to clients.
048: */
049: private class PropertyChangeListener implements
050: IPropertyChangeListener {
051:
052: /** Preference store to listen too. */
053: private IPreferenceStore fPreferenceStore;
054:
055: /**
056: * Initialize with the given preference store.
057: *
058: * @param preferenceStore the preference store
059: */
060: public PropertyChangeListener(IPreferenceStore preferenceStore) {
061: setPreferenceStore(preferenceStore);
062: }
063:
064: /*
065: * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
066: */
067: public void propertyChange(PropertyChangeEvent event) {
068: IPreferenceStore childPreferenceStore = getPreferenceStore();
069: handlePropertyChangeEvent(childPreferenceStore, event);
070: }
071:
072: /**
073: * Registers this listener on the preference store.
074: */
075: public void register() {
076: getPreferenceStore().addPropertyChangeListener(this );
077: }
078:
079: /**
080: * Unregisters this listener from the preference store.
081: */
082: public void unregister() {
083: getPreferenceStore().removePropertyChangeListener(this );
084: }
085:
086: /**
087: * Returns the preference store.
088: *
089: * @return the preference store
090: */
091: public IPreferenceStore getPreferenceStore() {
092: return fPreferenceStore;
093: }
094:
095: /**
096: * Sets the preference store.
097: *
098: * @param preferenceStore the preference store to set
099: */
100: public void setPreferenceStore(IPreferenceStore preferenceStore) {
101: fPreferenceStore = preferenceStore;
102: }
103:
104: }
105:
106: /**
107: * Sets the chained preference stores.
108: *
109: * @param preferenceStores the chained preference stores to set
110: */
111: public ChainedPreferenceStore(IPreferenceStore[] preferenceStores) {
112: Assert.isTrue(preferenceStores != null
113: && preferenceStores.length > 0);
114: fPreferenceStores = new IPreferenceStore[preferenceStores.length];
115: System.arraycopy(preferenceStores, 0, fPreferenceStores, 0,
116: preferenceStores.length);
117: // Create listeners
118: for (int i = 0, length = fPreferenceStores.length; i < length; i++) {
119: PropertyChangeListener listener = new PropertyChangeListener(
120: fPreferenceStores[i]);
121: fChildListeners.add(listener);
122: }
123: }
124:
125: /*
126: * @see org.eclipse.jface.preference.IPreferenceStore#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
127: */
128: public void addPropertyChangeListener(
129: IPropertyChangeListener listener) {
130: if (fClientListeners.size() == 0) {
131: registerChildListeners();
132: }
133: fClientListeners.add(listener);
134: }
135:
136: /*
137: * @see org.eclipse.jface.preference.IPreferenceStore#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
138: */
139: public void removePropertyChangeListener(
140: IPropertyChangeListener listener) {
141: fClientListeners.remove(listener);
142: if (fClientListeners.size() == 0) {
143: unregisterChildListeners();
144: }
145: }
146:
147: /*
148: * @see org.eclipse.jface.preference.IPreferenceStore#contains(java.lang.String)
149: */
150: public boolean contains(String name) {
151: return getVisibleStore(name) != null;
152: }
153:
154: /*
155: * @see org.eclipse.jface.preference.IPreferenceStore#firePropertyChangeEvent(java.lang.String, java.lang.Object, java.lang.Object)
156: */
157: public void firePropertyChangeEvent(String name, Object oldValue,
158: Object newValue) {
159: firePropertyChangeEvent(new PropertyChangeEvent(this , name,
160: oldValue, newValue));
161: }
162:
163: /**
164: * Fire the given property change event.
165: *
166: * @param event the property change event
167: */
168: private void firePropertyChangeEvent(PropertyChangeEvent event) {
169: Object[] listeners = fClientListeners.getListeners();
170: for (int i = 0; i < listeners.length; i++)
171: ((IPropertyChangeListener) listeners[i])
172: .propertyChange(event);
173: }
174:
175: /*
176: * @see org.eclipse.jface.preference.IPreferenceStore#getBoolean(java.lang.String)
177: */
178: public boolean getBoolean(String name) {
179: IPreferenceStore visibleStore = getVisibleStore(name);
180: if (visibleStore != null)
181: return visibleStore.getBoolean(name);
182: return BOOLEAN_DEFAULT_DEFAULT;
183: }
184:
185: /*
186: * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultBoolean(java.lang.String)
187: */
188: public boolean getDefaultBoolean(String name) {
189: IPreferenceStore visibleStore = getVisibleStore(name);
190: if (visibleStore != null)
191: return visibleStore.getDefaultBoolean(name);
192: return BOOLEAN_DEFAULT_DEFAULT;
193: }
194:
195: /*
196: * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultDouble(java.lang.String)
197: */
198: public double getDefaultDouble(String name) {
199: IPreferenceStore visibleStore = getVisibleStore(name);
200: if (visibleStore != null)
201: return visibleStore.getDefaultDouble(name);
202: return DOUBLE_DEFAULT_DEFAULT;
203: }
204:
205: /*
206: * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultFloat(java.lang.String)
207: */
208: public float getDefaultFloat(String name) {
209: IPreferenceStore visibleStore = getVisibleStore(name);
210: if (visibleStore != null)
211: return visibleStore.getDefaultFloat(name);
212: return FLOAT_DEFAULT_DEFAULT;
213: }
214:
215: /*
216: * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultInt(java.lang.String)
217: */
218: public int getDefaultInt(String name) {
219: IPreferenceStore visibleStore = getVisibleStore(name);
220: if (visibleStore != null)
221: return visibleStore.getDefaultInt(name);
222: return INT_DEFAULT_DEFAULT;
223: }
224:
225: /*
226: * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultLong(java.lang.String)
227: */
228: public long getDefaultLong(String name) {
229: IPreferenceStore visibleStore = getVisibleStore(name);
230: if (visibleStore != null)
231: return visibleStore.getDefaultLong(name);
232: return LONG_DEFAULT_DEFAULT;
233: }
234:
235: /*
236: * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultString(java.lang.String)
237: */
238: public String getDefaultString(String name) {
239: IPreferenceStore visibleStore = getVisibleStore(name);
240: if (visibleStore != null)
241: return visibleStore.getDefaultString(name);
242: return STRING_DEFAULT_DEFAULT;
243: }
244:
245: /*
246: * @see org.eclipse.jface.preference.IPreferenceStore#getDouble(java.lang.String)
247: */
248: public double getDouble(String name) {
249: IPreferenceStore visibleStore = getVisibleStore(name);
250: if (visibleStore != null)
251: return visibleStore.getDouble(name);
252: return DOUBLE_DEFAULT_DEFAULT;
253: }
254:
255: /*
256: * @see org.eclipse.jface.preference.IPreferenceStore#getFloat(java.lang.String)
257: */
258: public float getFloat(String name) {
259: IPreferenceStore visibleStore = getVisibleStore(name);
260: if (visibleStore != null)
261: return visibleStore.getFloat(name);
262: return FLOAT_DEFAULT_DEFAULT;
263: }
264:
265: /*
266: * @see org.eclipse.jface.preference.IPreferenceStore#getInt(java.lang.String)
267: */
268: public int getInt(String name) {
269: IPreferenceStore visibleStore = getVisibleStore(name);
270: if (visibleStore != null)
271: return visibleStore.getInt(name);
272: return INT_DEFAULT_DEFAULT;
273: }
274:
275: /*
276: * @see org.eclipse.jface.preference.IPreferenceStore#getLong(java.lang.String)
277: */
278: public long getLong(String name) {
279: IPreferenceStore visibleStore = getVisibleStore(name);
280: if (visibleStore != null)
281: return visibleStore.getLong(name);
282: return LONG_DEFAULT_DEFAULT;
283: }
284:
285: /*
286: * @see org.eclipse.jface.preference.IPreferenceStore#getString(java.lang.String)
287: */
288: public String getString(String name) {
289: IPreferenceStore visibleStore = getVisibleStore(name);
290: if (visibleStore != null)
291: return visibleStore.getString(name);
292: return STRING_DEFAULT_DEFAULT;
293: }
294:
295: /*
296: * @see org.eclipse.jface.preference.IPreferenceStore#isDefault(java.lang.String)
297: */
298: public boolean isDefault(String name) {
299: IPreferenceStore visibleStore = getVisibleStore(name);
300: if (visibleStore != null)
301: return visibleStore.isDefault(name);
302: return false;
303: }
304:
305: /*
306: * @see org.eclipse.jface.preference.IPreferenceStore#needsSaving()
307: */
308: public boolean needsSaving() {
309: throw new UnsupportedOperationException();
310: }
311:
312: /*
313: * @see org.eclipse.jface.preference.IPreferenceStore#putValue(java.lang.String, java.lang.String)
314: */
315: public void putValue(String name, String value) {
316: throw new UnsupportedOperationException();
317: }
318:
319: /*
320: * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, double)
321: */
322: public void setDefault(String name, double value) {
323: throw new UnsupportedOperationException();
324: }
325:
326: /*
327: * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, float)
328: */
329: public void setDefault(String name, float value) {
330: throw new UnsupportedOperationException();
331: }
332:
333: /*
334: * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, int)
335: */
336: public void setDefault(String name, int value) {
337: throw new UnsupportedOperationException();
338: }
339:
340: /*
341: * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, long)
342: */
343: public void setDefault(String name, long value) {
344: throw new UnsupportedOperationException();
345: }
346:
347: /*
348: * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, java.lang.String)
349: */
350: public void setDefault(String name, String defaultObject) {
351: throw new UnsupportedOperationException();
352: }
353:
354: /*
355: * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, boolean)
356: */
357: public void setDefault(String name, boolean value) {
358: throw new UnsupportedOperationException();
359: }
360:
361: /*
362: * @see org.eclipse.jface.preference.IPreferenceStore#setToDefault(java.lang.String)
363: */
364: public void setToDefault(String name) {
365: throw new UnsupportedOperationException();
366: }
367:
368: /*
369: * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, double)
370: */
371: public void setValue(String name, double value) {
372: throw new UnsupportedOperationException();
373: }
374:
375: /*
376: * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, float)
377: */
378: public void setValue(String name, float value) {
379: throw new UnsupportedOperationException();
380: }
381:
382: /*
383: * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, int)
384: */
385: public void setValue(String name, int value) {
386: throw new UnsupportedOperationException();
387: }
388:
389: /*
390: * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, long)
391: */
392: public void setValue(String name, long value) {
393: throw new UnsupportedOperationException();
394: }
395:
396: /*
397: * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, java.lang.String)
398: */
399: public void setValue(String name, String value) {
400: throw new UnsupportedOperationException();
401: }
402:
403: /*
404: * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, boolean)
405: */
406: public void setValue(String name, boolean value) {
407: throw new UnsupportedOperationException();
408: }
409:
410: /**
411: * Handle property change event from the child listener with the given child preference store.
412: *
413: * @param childPreferenceStore the child preference store
414: * @param event the event
415: */
416: private void handlePropertyChangeEvent(
417: IPreferenceStore childPreferenceStore,
418: PropertyChangeEvent event) {
419: String property = event.getProperty();
420: Object oldValue = event.getOldValue();
421: Object newValue = event.getNewValue();
422:
423: IPreferenceStore visibleStore = getVisibleStore(property);
424:
425: /*
426: * Assume that the property is there but has no default value (its owner relies on the default-default value)
427: * see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=52827
428: */
429: if (visibleStore == null && newValue != null)
430: visibleStore = childPreferenceStore;
431:
432: if (visibleStore == null) {
433: // no visible store
434: if (oldValue != null)
435: // removal in child, last in chain -> removal in this chained preference store
436: firePropertyChangeEvent(event);
437: } else if (visibleStore == childPreferenceStore) {
438: // event from visible store
439: if (oldValue != null) {
440: // change in child, visible store -> change in this chained preference store
441: firePropertyChangeEvent(event);
442: } else {
443: // insertion in child
444: IPreferenceStore oldVisibleStore = null;
445: int i = 0;
446: int length = fPreferenceStores.length;
447: while (i < length
448: && fPreferenceStores[i++] != visibleStore) {
449: // do nothing
450: }
451: while (oldVisibleStore == null && i < length) {
452: if (fPreferenceStores[i].contains(property))
453: oldVisibleStore = fPreferenceStores[i];
454: i++;
455: }
456:
457: if (oldVisibleStore == null) {
458: // insertion in child, first in chain -> insertion in this chained preference store
459: firePropertyChangeEvent(event);
460: } else {
461: // insertion in child, not first in chain
462: oldValue = getOtherValue(property, oldVisibleStore,
463: newValue);
464: if (!oldValue.equals(newValue))
465: // insertion in child, different old value -> change in this chained preference store
466: firePropertyChangeEvent(property, oldValue,
467: newValue);
468: // else: insertion in child, same old value -> no change in this chained preference store
469: }
470: }
471: } else {
472: // event from other than the visible store
473: boolean eventBeforeVisibleStore = false;
474: for (int i = 0, length = fPreferenceStores.length; i < length; i++) {
475: IPreferenceStore store = fPreferenceStores[i];
476: if (store == visibleStore)
477: break;
478: if (store == childPreferenceStore) {
479: eventBeforeVisibleStore = true;
480: break;
481: }
482: }
483:
484: if (eventBeforeVisibleStore) {
485: // removal in child, before visible store
486:
487: /*
488: * The original event's new value can be non-null (removed assertion).
489: * see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=69419
490: */
491:
492: newValue = getOtherValue(property, visibleStore,
493: oldValue);
494: if (!newValue.equals(oldValue))
495: // removal in child, before visible store, different old value -> change in this chained preference store
496: firePropertyChangeEvent(property, oldValue,
497: newValue);
498: // else: removal in child, before visible store, same old value -> no change in this chained preference store
499: }
500: // else: event behind visible store -> no change in this chained preference store
501: }
502: }
503:
504: /**
505: * Returns an object of the same dynamic type as <code>thisValue</code>, the returned object
506: * encapsulates the value of the <code>property</code> from the preference <code>store</code>.
507: *
508: * @param property the name of the considered property
509: * @param store the preference store
510: * @param thisValue the given value
511: * @return the other value
512: */
513: private Object getOtherValue(String property,
514: IPreferenceStore store, Object this Value) {
515:
516: if (this Value instanceof Boolean)
517: return store.getBoolean(property) ? Boolean.TRUE
518: : Boolean.FALSE;
519: else if (this Value instanceof Double)
520: return new Double(store.getDouble(property));
521: else if (this Value instanceof Float)
522: return new Float(store.getFloat(property));
523: else if (this Value instanceof Integer)
524: return new Integer(store.getInt(property));
525: else if (this Value instanceof Long)
526: return new Long(store.getLong(property));
527: else if (this Value instanceof String)
528: return store.getString(property);
529:
530: return store.getString(property);
531: }
532:
533: /**
534: * Returns the preference store from which the given property's value
535: * is visible.
536: *
537: * @param property the name of the property
538: * @return the preference store from which the property's value is visible,
539: * <code>null</code> if the property is unknown
540: */
541: private IPreferenceStore getVisibleStore(String property) {
542: IPreferenceStore visibleStore = null;
543:
544: for (int i = 0, length = fPreferenceStores.length; i < length
545: && visibleStore == null; i++) {
546: IPreferenceStore store = fPreferenceStores[i];
547: if (store.contains(property))
548: visibleStore = store;
549: }
550: return visibleStore;
551: }
552:
553: /**
554: * Register the child listeners on the child preference stores.
555: */
556: private void registerChildListeners() {
557: Iterator iter = fChildListeners.iterator();
558: while (iter.hasNext()) {
559: PropertyChangeListener listener = (PropertyChangeListener) iter
560: .next();
561: listener.register();
562: }
563: }
564:
565: /**
566: * Unregister the child listeners from the child preference stores.
567: */
568: private void unregisterChildListeners() {
569: Iterator iter = fChildListeners.iterator();
570: while (iter.hasNext()) {
571: PropertyChangeListener listener = (PropertyChangeListener) iter
572: .next();
573: listener.unregister();
574: }
575: }
576: }
|