### Eclipse Workspace Patch 1.0
#P org.eclipse.rap.ui.workbench
Index: META-INF/MANIFEST.MF
===================================================================
RCS file: /cvsroot/technology/org.eclipse.rap/org.eclipse.rap.ui.workbench/META-INF/MANIFEST.MF,v
retrieving revision 1.18
diff -u -r1.18 MANIFEST.MF
--- META-INF/MANIFEST.MF 21 Feb 2008 10:11:46 -0000 1.18
+++ META-INF/MANIFEST.MF 11 Mar 2008 23:39:49 -0000
@@ -17,7 +17,10 @@
org.eclipse.core.expressions
Import-Package: javax.servlet;version="[2.3.0,2.5.0]",
javax.servlet.http;version="[2.3.0,2.5.0]"
-Export-Package: org.eclipse.ui;
+Export-Package: org.eclipse.rap.ui.internal.preferences;x-internal:=true,
+ org.eclipse.rap.ui.preferences,
+ org.eclipse.rap.ui.service,
+ org.eclipse.ui;
uses:="org.eclipse.jface.util,
org.eclipse.jface.viewers,
org.eclipse.ui.views,
@@ -99,6 +102,7 @@
org.eclipse.jface.resource,
org.eclipse.core.runtime,
org.eclipse.ui",
+ org.eclipse.ui.preferences,
org.eclipse.ui.presentations;
uses:="org.eclipse.jface.util,
org.eclipse.swt.graphics,
Index: plugin.xml
===================================================================
RCS file: /cvsroot/technology/org.eclipse.rap/org.eclipse.rap.ui.workbench/plugin.xml,v
retrieving revision 1.18
diff -u -r1.18 plugin.xml
--- plugin.xml 16 Aug 2007 20:46:14 -0000 1.18
+++ plugin.xml 11 Mar 2008 23:39:48 -0000
@@ -31,5 +31,10 @@
null
if not yet
@@ -260,16 +262,18 @@
* will have to access the compatibility layer themselves.
*
+ * A ScopedPreferenceStore does the lookup of a preference based on it's search + * scopes and sets the value of the preference based on its store scope. + *
+ *+ * The default scope is always included in the search scopes when searching for + * preference values. + *
+ * + * @see org.eclipse.core.runtime.preferences + * @since 1.1 + */ +public class ScopedPreferenceStore extends EventManager implements + IPreferenceStore, IPersistentPreferenceStore { + + /** + * The storeContext is the context where values will stored with the + * setValue methods. If there are no searchContexts this will be the search + * context. (along with the "default" context) + */ + private IScopeContext storeContext; + + /** + * The searchContext is the array of contexts that will be used by the get + * methods for searching for values. + */ + private IScopeContext[] searchContexts; + + /** + * A boolean to indicate the property changes should not be propagated. + */ + protected boolean silentRunning = false; + + /** + * The listener on the IEclipsePreferences. This is used to forward updates + * to the property change listeners on the preference store. + */ + IEclipsePreferences.IPreferenceChangeListener preferencesListener; + + /** + * The default context is the context where getDefault and setDefault + * methods will search. This context is also used in the search. + */ + private IScopeContext defaultContext = new DefaultScope(); + + /** + * The nodeQualifer is the string used to look up the node in the contexts. + */ + String nodeQualifier; + + /** + * The defaultQualifier is the string used to look up the default node. + */ + String defaultQualifier; + + /** + * Boolean value indicating whether or not this store has changes to be + * saved. + */ + private boolean dirty; + + /** + * Create a new instance of the receiver. Store the values in context in the + * node looked up by qualifier. NOTE: Any instance of + * ScopedPreferenceStore should call + * + * @param context + * the scope to store to + * @param qualifier + * the qualifier used to look up the preference node + * @param defaultQualifierPath + * the qualifier used when looking up the defaults + */ + public ScopedPreferenceStore(IScopeContext context, String qualifier, + String defaultQualifierPath) { + this(context, qualifier); + this.defaultQualifier = defaultQualifierPath; + } + + /** + * Create a new instance of the receiver. Store the values in context in the + * node looked up by qualifier. + * + * @param context + * the scope to store to + * @param qualifier + * the qualifer used to look up the preference node + */ + public ScopedPreferenceStore(IScopeContext context, String qualifier) { + storeContext = context; + this.nodeQualifier = qualifier; + this.defaultQualifier = qualifier; + + ((IEclipsePreferences) getStorePreferences().parent()) + .addNodeChangeListener(getNodeChangeListener()); + } + + /** + * Return a node change listener that adds a removes the receiver when nodes + * change. + * + * @return INodeChangeListener + */ + private INodeChangeListener getNodeChangeListener() { + return new IEclipsePreferences.INodeChangeListener() { + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#added(org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent) + */ + public void added(NodeChangeEvent event) { + if (nodeQualifier.equals(event.getChild().name()) + && isListenerAttached()) { + getStorePreferences().addPreferenceChangeListener( + preferencesListener); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#removed(org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent) + */ + public void removed(NodeChangeEvent event) { + // Do nothing as there are no events from removed node + } + }; + } + + /** + * Initialize the preferences listener. + */ + private void initializePreferencesListener() { + if (preferencesListener == null) { + preferencesListener = new IEclipsePreferences.IPreferenceChangeListener() { + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent) + */ + public void preferenceChange(PreferenceChangeEvent event) { + + if (silentRunning) { + return; + } + + Object oldValue = event.getOldValue(); + Object newValue = event.getNewValue(); + String key = event.getKey(); + if (newValue == null) { + newValue = getDefault(key, oldValue); + } else if (oldValue == null) { + oldValue = getDefault(key, newValue); + } + firePropertyChangeEvent(event.getKey(), oldValue, newValue); + } + }; + getStorePreferences().addPreferenceChangeListener( + preferencesListener); + } + + } + + /** + * Does its best at determining the default value for the given key. Checks + * the given object's type and then looks in the list of defaults to see if + * a value exists. If not or if there is a problem converting the value, the + * default default value for that type is returned. + * + * @param key + * the key to search + * @param obj + * the object who default we are looking for + * @return Object ornull
+ */
+ Object getDefault(String key, Object obj) {
+ IEclipsePreferences defaults = getDefaultPreferences();
+ if (obj instanceof String) {
+ return defaults.get(key, STRING_DEFAULT_DEFAULT);
+ } else if (obj instanceof Integer) {
+ return new Integer(defaults.getInt(key, INT_DEFAULT_DEFAULT));
+ } else if (obj instanceof Double) {
+ return new Double(defaults.getDouble(key, DOUBLE_DEFAULT_DEFAULT));
+ } else if (obj instanceof Float) {
+ return new Float(defaults.getFloat(key, FLOAT_DEFAULT_DEFAULT));
+ } else if (obj instanceof Long) {
+ return new Long(defaults.getLong(key, LONG_DEFAULT_DEFAULT));
+ } else if (obj instanceof Boolean) {
+ return defaults.getBoolean(key, BOOLEAN_DEFAULT_DEFAULT) ? Boolean.TRUE : Boolean.FALSE;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return the IEclipsePreferences node associated with this store.
+ *
+ * @return the preference node for this store
+ */
+ IEclipsePreferences getStorePreferences() {
+ return storeContext.getNode(nodeQualifier);
+ }
+
+ /**
+ * Return the default IEclipsePreferences for this store.
+ *
+ * @return this store's default preference node
+ */
+ private IEclipsePreferences getDefaultPreferences() {
+ return defaultContext.getNode(defaultQualifier);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
+ */
+ public void addPropertyChangeListener(IPropertyChangeListener listener) {
+ initializePreferencesListener();// Create the preferences listener if it
+ // does not exist
+ addListenerObject(listener);
+ }
+
+ /**
+ * Return the preference path to search preferences on. This is the list of
+ * preference nodes based on the scope contexts for this store. If there are
+ * no search contexts set, then return this store's context.
+ *
+ * Whether or not the default context should be included in the resulting
+ * list is specified by the includeDefault
parameter.
+ *
true
if the default context should be included
+ * and false
otherwise
+ * @return IEclipsePreferences[]
+ */
+ private IEclipsePreferences[] getPreferenceNodes(boolean includeDefault) {
+ // if the user didn't specify a search order, then return the scope that
+ // this store was created on. (and optionally the default)
+ if (searchContexts == null) {
+ if (includeDefault) {
+ return new IEclipsePreferences[] { getStorePreferences(),
+ getDefaultPreferences() };
+ }
+ return new IEclipsePreferences[] { getStorePreferences() };
+ }
+ // otherwise the user specified a search order so return the appropriate
+ // nodes based on it
+ int length = searchContexts.length;
+ if (includeDefault) {
+ length++;
+ }
+ IEclipsePreferences[] preferences = new IEclipsePreferences[length];
+ for (int i = 0; i < searchContexts.length; i++) {
+ preferences[i] = searchContexts[i].getNode(nodeQualifier);
+ }
+ if (includeDefault) {
+ preferences[length - 1] = getDefaultPreferences();
+ }
+ return preferences;
+ }
+
+ /**
+ * Set the search contexts to scopes. When searching for a value the seach
+ * will be done in the order of scope contexts and will not search the
+ * storeContext unless it is in this list.
+ *
+ * If the given list is null
, then clear this store's search
+ * contexts. This means that only this store's scope context and default
+ * scope will be used during preference value searching.
+ *
+ * The defaultContext will be added to the end of this list automatically + * and MUST NOT be included by the user. + *
+ * + * @param scopes + * a list of scope contexts to use when searching, or + *null
+ */
+ public void setSearchContexts(IScopeContext[] scopes) {
+ this.searchContexts = scopes;
+ if (scopes == null) {
+ return;
+ }
+
+ // Assert that the default was not included (we automatically add it to
+ // the end)
+ for (int i = 0; i < scopes.length; i++) {
+ if (scopes[i].equals(defaultContext)) {
+ Assert
+ .isTrue(
+ false,
+ WorkbenchMessages.get().ScopedPreferenceStore_DefaultAddedError);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#contains(java.lang.String)
+ */
+ public boolean contains(String name) {
+ if (name == null) {
+ return false;
+ }
+ return (Platform.getPreferencesService().get(name, null,
+ getPreferenceNodes(true))) != null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#firePropertyChangeEvent(java.lang.String,
+ * java.lang.Object, java.lang.Object)
+ */
+ public void firePropertyChangeEvent(String name, Object oldValue,
+ Object newValue) {
+ // important: create intermediate array to protect against listeners
+ // being added/removed during the notification
+ final Object[] list = getListeners();
+ if (list.length == 0) {
+ return;
+ }
+ final PropertyChangeEvent event = new PropertyChangeEvent(this, name,
+ oldValue, newValue);
+ for (int i = 0; i < list.length; i++) {
+ final IPropertyChangeListener listener = (IPropertyChangeListener) list[i];
+ SafeRunner.run(new SafeRunnable(JFaceResources
+ .getString("PreferenceStore.changeError")) { //$NON-NLS-1$
+ public void run() {
+ listener.propertyChange(event);
+ }
+ });
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getBoolean(java.lang.String)
+ */
+ public boolean getBoolean(String name) {
+ String value = internalGet(name);
+ return value == null ? BOOLEAN_DEFAULT_DEFAULT : Boolean.valueOf(value)
+ .booleanValue();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultBoolean(java.lang.String)
+ */
+ public boolean getDefaultBoolean(String name) {
+ return getDefaultPreferences()
+ .getBoolean(name, BOOLEAN_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultDouble(java.lang.String)
+ */
+ public double getDefaultDouble(String name) {
+ return getDefaultPreferences().getDouble(name, DOUBLE_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultFloat(java.lang.String)
+ */
+ public float getDefaultFloat(String name) {
+ return getDefaultPreferences().getFloat(name, FLOAT_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultInt(java.lang.String)
+ */
+ public int getDefaultInt(String name) {
+ return getDefaultPreferences().getInt(name, INT_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultLong(java.lang.String)
+ */
+ public long getDefaultLong(String name) {
+ return getDefaultPreferences().getLong(name, LONG_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultString(java.lang.String)
+ */
+ public String getDefaultString(String name) {
+ return getDefaultPreferences().get(name, STRING_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDouble(java.lang.String)
+ */
+ public double getDouble(String name) {
+ String value = internalGet(name);
+ if (value == null) {
+ return DOUBLE_DEFAULT_DEFAULT;
+ }
+ try {
+ return Double.parseDouble(value);
+ } catch (NumberFormatException e) {
+ return DOUBLE_DEFAULT_DEFAULT;
+ }
+ }
+
+ /**
+ * Return the string value for the specified key. Look in the nodes which
+ * are specified by this object's list of search scopes. If the value does
+ * not exist then return null
.
+ *
+ * @param key
+ * the key to search with
+ * @return String or null
if the value does not exist.
+ */
+ private String internalGet(String key) {
+ return Platform.getPreferencesService().get(key, null,
+ getPreferenceNodes(true));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getFloat(java.lang.String)
+ */
+ public float getFloat(String name) {
+ String value = internalGet(name);
+ if (value == null) {
+ return FLOAT_DEFAULT_DEFAULT;
+ }
+ try {
+ return Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ return FLOAT_DEFAULT_DEFAULT;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getInt(java.lang.String)
+ */
+ public int getInt(String name) {
+ String value = internalGet(name);
+ if (value == null) {
+ return INT_DEFAULT_DEFAULT;
+ }
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return INT_DEFAULT_DEFAULT;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getLong(java.lang.String)
+ */
+ public long getLong(String name) {
+ String value = internalGet(name);
+ if (value == null) {
+ return LONG_DEFAULT_DEFAULT;
+ }
+ try {
+ return Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ return LONG_DEFAULT_DEFAULT;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getString(java.lang.String)
+ */
+ public String getString(String name) {
+ String value = internalGet(name);
+ return value == null ? STRING_DEFAULT_DEFAULT : value;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#isDefault(java.lang.String)
+ */
+ public boolean isDefault(String name) {
+ if (name == null) {
+ return false;
+ }
+ return (Platform.getPreferencesService().get(name, null,
+ getPreferenceNodes(false))) == null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#needsSaving()
+ */
+ public boolean needsSaving() {
+ return dirty;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#putValue(java.lang.String,
+ * java.lang.String)
+ */
+ public void putValue(String name, String value) {
+ try {
+ // Do not notify listeners
+ silentRunning = true;
+ getStorePreferences().put(name, value);
+ } finally {
+ // Be sure that an exception does not stop property updates
+ silentRunning = false;
+ dirty = true;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
+ */
+ public void removePropertyChangeListener(IPropertyChangeListener listener) {
+ removeListenerObject(listener);
+ if (!isListenerAttached()) {
+ disposePreferenceStoreListener();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * double)
+ */
+ public void setDefault(String name, double value) {
+ getDefaultPreferences().putDouble(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * float)
+ */
+ public void setDefault(String name, float value) {
+ getDefaultPreferences().putFloat(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * int)
+ */
+ public void setDefault(String name, int value) {
+ getDefaultPreferences().putInt(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * long)
+ */
+ public void setDefault(String name, long value) {
+ getDefaultPreferences().putLong(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * java.lang.String)
+ */
+ public void setDefault(String name, String defaultObject) {
+ getDefaultPreferences().put(name, defaultObject);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * boolean)
+ */
+ public void setDefault(String name, boolean value) {
+ getDefaultPreferences().putBoolean(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setToDefault(java.lang.String)
+ */
+ public void setToDefault(String name) {
+
+ String oldValue = getString(name);
+ String defaultValue = getDefaultString(name);
+ try {
+ silentRunning = true;// Turn off updates from the store
+ // removing a non-existing preference is a no-op so call the Core
+ // API directly
+ getStorePreferences().remove(name);
+ dirty = true;
+ firePropertyChangeEvent(name, oldValue, defaultValue);
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * double)
+ */
+ public void setValue(String name, double value) {
+ double oldValue = getDouble(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultDouble(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putDouble(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, new Double(oldValue), new Double(
+ value));
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * float)
+ */
+ public void setValue(String name, float value) {
+ float oldValue = getFloat(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultFloat(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putFloat(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, new Float(oldValue), new Float(value));
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * int)
+ */
+ public void setValue(String name, int value) {
+ int oldValue = getInt(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultInt(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putInt(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, new Integer(oldValue), new Integer(
+ value));
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * long)
+ */
+ public void setValue(String name, long value) {
+ long oldValue = getLong(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultLong(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putLong(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, new Long(oldValue), new Long(value));
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * java.lang.String)
+ */
+ public void setValue(String name, String value) {
+ // Do not turn on silent running here as Strings are propagated
+ if (getDefaultString(name).equals(value)) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().put(name, value);
+ }
+ dirty = true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * boolean)
+ */
+ public void setValue(String name, boolean value) {
+ boolean oldValue = getBoolean(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultBoolean(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putBoolean(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, oldValue ? Boolean.TRUE : Boolean.FALSE,
+ value ? Boolean.TRUE : Boolean.FALSE);
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPersistentPreferenceStore#save()
+ */
+ public void save() throws IOException {
+ try {
+ getStorePreferences().flush();
+ dirty = false;
+ } catch (BackingStoreException e) {
+ throw new IOException(e.getMessage());
+ }
+
+ }
+
+ /**
+ * Dispose the receiver.
+ */
+ private void disposePreferenceStoreListener() {
+
+ IEclipsePreferences root = (IEclipsePreferences) Platform
+ .getPreferencesService().getRootNode().node(
+ Plugin.PLUGIN_PREFERENCE_SCOPE);
+ try {
+ if (!(root.nodeExists(nodeQualifier))) {
+ return;
+ }
+ } catch (BackingStoreException e) {
+ return;// No need to report here as the node won't have the
+ // listener
+ }
+
+ IEclipsePreferences preferences = getStorePreferences();
+ if (preferences == null) {
+ return;
+ }
+ if (preferencesListener != null) {
+ preferences.removePreferenceChangeListener(preferencesListener);
+ preferencesListener = null;
+ }
+ }
+
+}
Index: src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesFactory.java
===================================================================
RCS file: src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesFactory.java
diff -N src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesFactory.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesFactory.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2002-2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rap.ui.internal.preferences;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScope;
+
+/**
+ * Creates "session" scoped preference nodes.
+ */
+public final class SessionPreferencesFactory implements IScope {
+
+ public IEclipsePreferences create( final IEclipsePreferences parent,
+ final String name ) {
+ return new SessionPreferencesNode( parent, name );
+ }
+
+}
Index: src/org/eclipse/rap/ui/preferences/SessionScope.java
===================================================================
RCS file: src/org/eclipse/rap/ui/preferences/SessionScope.java
diff -N src/org/eclipse/rap/ui/preferences/SessionScope.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/rap/ui/preferences/SessionScope.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2002-2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rap.ui.preferences;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.rwt.RWT;
+import org.eclipse.rwt.internal.util.ParamCheck;
+import org.eclipse.rwt.service.FileSettingStore;
+
+/**
+ * Object representing the session scope in the Eclipse preferences
+ * hierarchy. Can be used as a context for searching for preference
+ * values (in the IPreferenceService APIs) or for determining the
+ * corrent preference node to set values in the store.
+ * + * Session preferences are stored on a per-session basis using + * the underlying RWT SettingStore (see {@link RWT#getSettingStore()}. + * Preferences saved during a previous session will be retrieved, as long as + * the user can identify himself with the setting store cookie. Session + * preferences are persisted using the setting store implementation + * that is configured for the application (see {@link FileSettingStore}. + *
+ * The path for preferences defined in the session scope hierarchy is:
+ * /session/<qualifier>
+ *
+ * This class is not intented to be subclassed. It may be instantiated.
+ *
+ * @since 1.1
+ */
+public final class SessionScope implements IScopeContext {
+
+ /**
+ * String constant (value of "session"
) used for the
+ * scope name for the session preference scope.
+ */
+ public static final String SCOPE = "session"; //$NON-NLS-1$
+
+ /**
+ * Create and return a new session scope instance.
+ */
+ public SessionScope() {
+ super();
+ }
+
+ public IPath getLocation() {
+ return null;
+ }
+
+ public String getName() {
+ return SCOPE;
+ }
+
+ public IEclipsePreferences getNode( String qualifier ) {
+ ParamCheck.notNull( qualifier, "qualifier" );
+ IEclipsePreferences root = Platform.getPreferencesService().getRootNode();
+ return ( IEclipsePreferences ) root.node( SCOPE ).node( qualifier );
+ }
+}
Index: src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesNode.java
===================================================================
RCS file: src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesNode.java
diff -N src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesNode.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesNode.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,531 @@
+/*******************************************************************************
+ * Copyright (c) 2002-2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.preferences;
+
+import java.util.*;
+
+import org.eclipse.core.internal.preferences.Base64;
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IPreferenceNodeVisitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.rwt.RWT;
+import org.eclipse.rwt.internal.util.ParamCheck;
+import org.eclipse.rwt.service.ISettingStore;
+import org.eclipse.rwt.service.SettingStoreException;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+
+/**
+ * This node use the RWT setting store to persist its preferences.
+ */
+final class SessionPreferencesNode
+ implements IEclipsePreferences
+{
+
+ private static final String PATH_SEPARATOR = "/";
+ private static final String DOUBLE_PATH_SEPARATOR = "//";
+ private static final String TRUE = "true";
+ private static final String FALSE = "false";
+
+ private final String name;
+ private final IEclipsePreferences parent;
+ private boolean isRemoved;
+ /* cache the absolutePath once it has been computed */
+ private String absolutePath;
+
+ private final Map children = new HashMap(); // !thread safe
+ private final ListenerList nodeListeners
+ = new ListenerList( ListenerList.IDENTITY ); // thread safe
+
+ SessionPreferencesNode( final IEclipsePreferences parent,
+ final String name ) {
+ ParamCheck.notNull( parent, "parent" );
+ ParamCheck.notNull( name, "name" );
+ checkName( name );
+ this.parent = parent;
+ this.name = name;
+ }
+
+ public void accept( final IPreferenceNodeVisitor visitor )
+ throws BackingStoreException
+ {
+ boolean withChildren = visitor.visit( this );
+ if( withChildren ) {
+ Object[] childrenArray;
+ synchronized( this ) {
+ childrenArray = children.values().toArray();
+ }
+ for( int i = 0; i < childrenArray.length; i++ ) {
+ IEclipsePreferences child = ( IEclipsePreferences )childrenArray[ i ];
+ child.accept( visitor );
+ }
+ }
+ }
+
+ public void addNodeChangeListener( final INodeChangeListener listener ) {
+ checkRemoved();
+ if( listener != null ) {
+ nodeListeners.add( listener );
+ }
+ }
+
+ public void addPreferenceChangeListener(
+ final IPreferenceChangeListener listener )
+ {
+ checkRemoved();
+ getNodeCore().addPreferenceChangeListener( listener );
+ }
+
+ public Preferences node( final String path ) {
+ checkPath( path );
+ checkRemoved();
+ Preferences result;
+ if( "".equals( path ) ) { // ""
+ result = this;
+ } else if( path.startsWith( PATH_SEPARATOR ) ) { // "/absolute/path"
+ result = findRoot().node( path.substring( 1 ) );
+ } else if( path.indexOf( PATH_SEPARATOR ) > 0 ) { // "foo/bar/baz"
+ int index = path.indexOf( PATH_SEPARATOR );
+ String nodeName = path.substring( 0, index );
+ String rest = path.substring( index + 1, path.length() );
+ result = getChild( nodeName, true ).node( rest );
+ } else { // "foo"
+ result = getChild( path, true );
+ }
+ return result;
+ }
+
+ public synchronized void removeNode() throws BackingStoreException {
+ checkRemoved();
+ // remove all preferences
+ clear();
+ // remove all children
+ Object[] childNodes = children.values().toArray();
+ for( int i = 0; i < childNodes.length; i++ ) {
+ Preferences child = ( Preferences )childNodes[ i ];
+ if( child.nodeExists( "" ) ) { // if !removed
+ child.removeNode();
+ }
+ }
+ // remove from parent; this is ugly, because the interface
+ // Preference has no API for removing oneself from the parent.
+ // In general the parent will be a SessionPreferencesNode.
+ // The only case in the workbench where this is not true, is one level
+ // below the root (i.e. at /session ), but the scope root must not
+ // be removable (see IEclipsePreferences#removeNode())
+ if( parent instanceof SessionPreferencesNode ) {
+ // this means:
+ // (a) we know what kind of parent we have, and
+ // (b) we are not the scope root, since that has a
+ /// RootPreference as a parent
+ SessionPreferencesNode spnParent
+ = ( ( SessionPreferencesNode ) parent );
+ spnParent.children.remove( name );
+ spnParent.fireNodeEvent( this, false );
+
+ // the listeners are not needed anymore
+ getNodeCore().clear();
+ nodeListeners.clear();
+ children.clear();
+ isRemoved = true;
+ }
+ }
+
+ public void removeNodeChangeListener( final INodeChangeListener listener ) {
+ checkRemoved();
+ if( listener != null ) {
+ nodeListeners.remove( listener );
+ }
+ }
+
+ public void removePreferenceChangeListener(
+ final IPreferenceChangeListener listener )
+ {
+ checkRemoved();
+ getNodeCore().removePreferenceChangeListener( listener );
+ }
+
+ public String absolutePath() {
+ if( absolutePath == null ) {
+ if( parent == null ) {
+ absolutePath = name;
+ } else {
+ String parentPath = parent.absolutePath();
+ absolutePath = parentPath.endsWith( PATH_SEPARATOR )
+ ? parentPath + name
+ : parentPath + PATH_SEPARATOR + name;
+ }
+ }
+ return absolutePath;
+ }
+
+ public synchronized String[] childrenNames() throws BackingStoreException {
+ checkRemoved();
+ Set names = children.keySet();
+ return ( String[] )names.toArray( new String[ names.size() ] );
+ }
+
+ public void clear() throws BackingStoreException {
+ checkRemoved();
+ String[] keys = internalGetKeys();
+ for( int i = 0; i < keys.length; i++ ) {
+ remove( keys[ i ] );
+ }
+ }
+
+ public void flush() throws BackingStoreException {
+ checkRemoved();
+ // the current implementation persists everytime the preferences
+ // are modified, so there's nothing to do here
+ }
+
+ public String get( final String key, final String def ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String result = internalGet( key );
+ return result == null ? def : result;
+ }
+
+ public boolean getBoolean( final String key, final boolean def ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String value = internalGet( key );
+ return value == null ? def : Boolean.parseBoolean( value );
+ }
+
+ public byte[] getByteArray( final String key, final byte[] def ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String value = internalGet( key );
+ return value == null ? def : Base64.decode( value.getBytes() );
+ }
+
+ public double getDouble( final String key, final double def ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String value = internalGet( key );
+ double result = def;
+ if( value != null ) {
+ try {
+ result = Double.parseDouble( value );
+ } catch( NumberFormatException nfe ) {
+ // returns def
+ }
+ }
+ return result;
+ }
+
+ public float getFloat( final String key, final float def ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String value = internalGet( key );
+ float result = def;
+ if( value != null ) {
+ try {
+ result = Float.parseFloat( value );
+ } catch( NumberFormatException nfe ) {
+ // returns def
+ }
+ }
+ return result;
+ }
+
+ public int getInt( final String key, final int def ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String value = internalGet( key );
+ int result = def;
+ if( value != null ) {
+ try {
+ result = Integer.parseInt( value );
+ } catch( NumberFormatException nfe ) {
+ // returns def
+ }
+ }
+ return result;
+ }
+
+ public long getLong( final String key, final long def ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String value = internalGet( key );
+ long result = def;
+ if( value != null ) {
+ try {
+ result = Long.parseLong( value );
+ } catch( NumberFormatException nfe ) {
+ // returns def
+ }
+ }
+ return result;
+ }
+
+ public String[] keys() throws BackingStoreException {
+ checkRemoved();
+ return internalGetKeys();
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public synchronized boolean nodeExists( final String path )
+ throws BackingStoreException
+ {
+ boolean result;
+ if( "".equals( path ) ) {
+ result = !isRemoved;
+ } else {
+ checkRemoved();
+ checkPath( path );
+ if( path.startsWith( PATH_SEPARATOR ) ) { // "/absolute/path"
+ result = findRoot().nodeExists( path.substring( 1 ) );
+ } else if( path.indexOf( PATH_SEPARATOR ) > 0 ) { // "foo/bar/baz"
+ int index = path.indexOf( PATH_SEPARATOR );
+ String nodeName = path.substring( 0, index );
+ String rest = path.substring( index + 1, path.length() );
+ SessionPreferencesNode child = getChild( nodeName, false );
+ result = child == null ? false : child.nodeExists( rest );
+ } else { // "foo"
+ result = children.containsKey( path );
+ }
+ }
+ return result;
+ }
+
+ public Preferences parent() {
+ checkRemoved();
+ return parent;
+ }
+
+ public void put( final String key, final String newValue ) {
+ ParamCheck.notNull( key, "key" );
+ ParamCheck.notNull( newValue, "newValue" );
+ checkRemoved();
+ String oldValue = internalPut( key, newValue );
+ if( !newValue.equals( oldValue ) ) {
+ getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+ }
+ }
+
+ public void putBoolean( final String key, final boolean value ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String newValue = value ? TRUE : FALSE;
+ String oldValue = internalPut( key, newValue );
+ if( !newValue.equals( oldValue ) ) {
+ getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+ }
+ }
+
+ public void putByteArray( final String key, final byte[] value ) {
+ ParamCheck.notNull( key, "key" );
+ ParamCheck.notNull( value, "newValue" );
+ checkRemoved();
+ String newValue = new String( Base64.encode( value ) );
+ String oldValue = internalPut( key, newValue );
+ if( !newValue.equals( oldValue) ) {
+ getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+ }
+ }
+
+ public void putDouble( final String key, final double value ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String newValue = String.valueOf( value );
+ String oldValue = internalPut( key, newValue );
+ if( !newValue.equals( oldValue ) ) {
+ getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+ }
+ }
+
+ public void putFloat( final String key, final float value ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String newValue = String.valueOf( value );
+ String oldValue = internalPut( key, newValue );
+ if( !newValue.equals( oldValue ) ) {
+ getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+ }
+ }
+
+ public void putInt( final String key, final int value ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String newValue = String.valueOf( value );
+ String oldValue = internalPut( key, newValue );
+ if( !newValue.equals( oldValue ) ) {
+ getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+ }
+ }
+
+ public void putLong( final String key, final long value ) {
+ ParamCheck.notNull( key, "key" );
+ checkRemoved();
+ String newValue = String.valueOf( value );
+ String oldValue = internalPut( key, newValue );
+ if( !newValue.equals( oldValue ) ) {
+ getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+ }
+ }
+
+ public void remove( final String key ) {
+ checkRemoved();
+ String oldValue = internalGet( key );
+ if( oldValue != null ) {
+ internalPut( key, null );
+ getNodeCore().firePreferenceEvent( key, oldValue, null );
+ }
+ }
+
+ public void sync() throws BackingStoreException {
+ checkRemoved();
+ ISettingStore store = RWT.getSettingStore();
+ String id = store.getId();
+ try {
+ store.loadById( id );
+ } catch( SettingStoreException sse ) {
+ throw new BackingStoreException( "Failed to sync() node", sse );
+ }
+ }
+
+ public String toString() {
+ return absolutePath() + "@" + hashCode();
+ }
+
+ //////////////////
+ // helping methods
+
+ private void checkName( final String nodeName ) {
+ if( nodeName.indexOf( PATH_SEPARATOR ) != -1 ) {
+ String unboundMsg = "Name ''{0}'' cannot contain or end with ''{1}''";
+ String msg = NLS.bind( unboundMsg, nodeName, PATH_SEPARATOR );
+ throw new IllegalArgumentException( msg );
+ }
+ }
+
+ private void checkPath( final String path ) {
+ if( path.indexOf( DOUBLE_PATH_SEPARATOR ) != -1 ) {
+ String unboundMsg = "''{0}'' is not allowed in path ''{1}''";
+ String msg = NLS.bind( unboundMsg, DOUBLE_PATH_SEPARATOR, path );
+ throw new IllegalArgumentException( msg );
+ }
+ if( path.length() > 1 && path.endsWith( PATH_SEPARATOR ) ) {
+ String unboundMsg = "path ''{0}'' cannot end with ''{1}''";
+ String msg = NLS.bind( unboundMsg, path, PATH_SEPARATOR );
+ throw new IllegalArgumentException( msg );
+ }
+ }
+
+ private synchronized void checkRemoved() {
+ if( isRemoved ) {
+ String msg = "node ''{0}'' has been removed";
+ throw new IllegalStateException( NLS.bind( msg, this.absolutePath() ) );
+ }
+ }
+
+ private synchronized SessionPreferencesNode createChild(
+ final String childName )
+ {
+ SessionPreferencesNode result
+ = new SessionPreferencesNode( this, childName );
+ children.put( childName, result );
+ fireNodeEvent( result, true );
+ return result;
+ }
+
+ private synchronized SessionPreferencesNode getChild(
+ final String childName,
+ final boolean doCreate )
+ {
+ SessionPreferencesNode result
+ = ( SessionPreferencesNode )children.get( childName );
+ if( result == null && doCreate ) {
+ result = createChild( childName );
+ }
+ return result;
+ }
+
+ private String[] internalGetKeys() {
+ List result = new ArrayList();
+
+ String prefix = absolutePath() + PATH_SEPARATOR;
+ int prefixLength = prefix.length();
+
+ Enumeration attrNames = RWT.getSettingStore().getAttributeNames();
+ while( attrNames.hasMoreElements() ) {
+ String attr = ( String )attrNames.nextElement();
+ if( attr.startsWith( prefix ) ) {
+ String key = attr.substring( prefixLength );
+ result.add( key );
+ }
+ }
+ return ( String[] )result.toArray( new String[ result.size() ] );
+ }
+
+ private Preferences findRoot() {
+ Preferences result = this;
+ while( result.parent() != null ) {
+ result = result.parent();
+ }
+ return result;
+ }
+
+ private String internalGet( final String key ) {
+ ISettingStore store = RWT.getSettingStore();
+ String uniqueKey = absolutePath() + PATH_SEPARATOR + key;
+ return store.getAttribute( uniqueKey );
+ }
+
+ private synchronized String internalPut( final String key,
+ final String value ) {
+ String uniqueKey = absolutePath() + PATH_SEPARATOR + key;
+ return getNodeCore().put( uniqueKey, value );
+ }
+
+ private void fireNodeEvent( final Preferences child,
+ final boolean wasAdded ) {
+ final NodeChangeEvent event = new NodeChangeEvent( this, child );
+ Object[] listeners = nodeListeners.getListeners();
+ for( int i = 0; i < listeners.length; i++ ) {
+ final INodeChangeListener listener
+ = ( INodeChangeListener )listeners[ i ];
+ ISafeRunnable op = new ISafeRunnable() {
+ public void handleException( final Throwable exception ) {
+ // logged by SafeRunner
+ }
+ public void run() throws Exception {
+ if( wasAdded ) {
+ listener.added( event );
+ } else {
+ listener.removed( event );
+ }
+ }
+ };
+ SafeRunner.run( op );
+ }
+ }
+
+ private SessionPreferenceNodeCore getNodeCore() {
+ SessionPreferenceNodeCore result;
+ final String key = absolutePath();
+ Object object = RWT.getSessionStore().getAttribute( key );
+ if( object instanceof SessionPreferenceNodeCore ) {
+ result = ( SessionPreferenceNodeCore )object;
+ } else {
+ result = new SessionPreferenceNodeCore( this );
+ RWT.getSessionStore().setAttribute( key, result );
+ }
+ return result;
+ }
+
+}