View | Details | Raw Unified | Return to bug 220477
Collapse All | Expand All

(-)META-INF/MANIFEST.MF (-1 / +5 lines)
Lines 17-23 Link Here
17
 org.eclipse.core.expressions
17
 org.eclipse.core.expressions
18
Import-Package: javax.servlet;version="[2.3.0,2.5.0]",
18
Import-Package: javax.servlet;version="[2.3.0,2.5.0]",
19
 javax.servlet.http;version="[2.3.0,2.5.0]"
19
 javax.servlet.http;version="[2.3.0,2.5.0]"
20
Export-Package: org.eclipse.ui;
20
Export-Package: org.eclipse.rap.ui.internal.preferences;x-internal:=true,
21
 org.eclipse.rap.ui.preferences,
22
 org.eclipse.rap.ui.service,
23
 org.eclipse.ui;
21
  uses:="org.eclipse.jface.util,
24
  uses:="org.eclipse.jface.util,
22
   org.eclipse.jface.viewers,
25
   org.eclipse.jface.viewers,
23
   org.eclipse.ui.views,
26
   org.eclipse.ui.views,
Lines 99-104 Link Here
99
   org.eclipse.jface.resource,
102
   org.eclipse.jface.resource,
100
   org.eclipse.core.runtime,
103
   org.eclipse.core.runtime,
101
   org.eclipse.ui",
104
   org.eclipse.ui",
105
 org.eclipse.ui.preferences,
102
 org.eclipse.ui.presentations;
106
 org.eclipse.ui.presentations;
103
  uses:="org.eclipse.jface.util,
107
  uses:="org.eclipse.jface.util,
104
   org.eclipse.swt.graphics,
108
   org.eclipse.swt.graphics,
(-)plugin.xml (+5 lines)
Lines 31-35 Link Here
31
     <listener class="org.eclipse.rwt.internal.lifecycle.CurrentPhase$Listener"/>
31
     <listener class="org.eclipse.rwt.internal.lifecycle.CurrentPhase$Listener"/>
32
  </extension>
32
  </extension>
33
  
33
  
34
  <extension id="preferences" 
35
             point="org.eclipse.core.runtime.preferences">
36
    <scope name="session" 
37
           class="org.eclipse.rap.ui.internal.preferences.SessionPreferencesFactory"/>
38
  </extension>
34
  
39
  
35
</plugin>
40
</plugin>
(-)src/org/eclipse/ui/plugin/AbstractUIPlugin.java (-10 / +14 lines)
Lines 19-28 Link Here
19
import org.eclipse.jface.dialogs.IDialogSettings;
19
import org.eclipse.jface.dialogs.IDialogSettings;
20
import org.eclipse.jface.preference.IPreferenceStore;
20
import org.eclipse.jface.preference.IPreferenceStore;
21
import org.eclipse.jface.resource.*;
21
import org.eclipse.jface.resource.*;
22
import org.eclipse.rap.ui.preferences.SessionScope;
22
import org.eclipse.ui.IWorkbench;
23
import org.eclipse.ui.IWorkbench;
23
import org.eclipse.ui.PlatformUI;
24
import org.eclipse.ui.PlatformUI;
24
import org.eclipse.ui.internal.WWinPluginAction;
25
import org.eclipse.ui.internal.WWinPluginAction;
25
import org.eclipse.ui.internal.util.BundleUtility;
26
import org.eclipse.ui.internal.util.BundleUtility;
27
import org.eclipse.ui.preferences.ScopedPreferenceStore;
26
import org.osgi.framework.*;
28
import org.osgi.framework.*;
27
29
28
/**
30
/**
Lines 113-119 Link Here
113
    /**
115
    /**
114
     * Storage for preferences.
116
     * Storage for preferences.
115
     */
117
     */
116
//    private ScopedPreferenceStore preferenceStore;
118
    private ScopedPreferenceStore preferenceStore;
117
119
118
    /**
120
    /**
119
     * The registry for all graphic images; <code>null</code> if not yet
121
     * The registry for all graphic images; <code>null</code> if not yet
Lines 260-275 Link Here
260
     * will have to access the compatibility layer themselves.
262
     * will have to access the compatibility layer themselves.
261
     * </p>
263
     * </p>
262
     *
264
     *
263
     * @return the preference store 
265
     * @return the preference store
266
     * @since 1.1  
264
     */
267
     */
265
//    public IPreferenceStore getPreferenceStore() {
268
    public IPreferenceStore getPreferenceStore() {
266
//        // Create the preference store lazily.
269
      // Create the preference store lazily.
267
//        if (preferenceStore == null) {
270
      if (preferenceStore == null) {
268
//            preferenceStore = new ScopedPreferenceStore(new InstanceScope(),getBundle().getSymbolicName());
271
        String pluginId = getBundle().getSymbolicName();
269
//
272
        preferenceStore 
270
//        }
273
          = new ScopedPreferenceStore( new SessionScope(), pluginId );
271
//        return preferenceStore;
274
      }
272
//    }
275
      return preferenceStore;
276
    }
273
277
274
    /**
278
    /**
275
     * Returns the Platform UI workbench.  
279
     * Returns the Platform UI workbench.  
(-)src/org/eclipse/rap/ui/internal/preferences/SessionPreferenceNodeCore.java (+146 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2002-2008 Innoopract Informationssysteme GmbH.
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
 *     Innoopract Informationssysteme GmbH - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.rap.ui.internal.preferences;
13
14
import org.eclipse.core.runtime.*;
15
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
16
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
17
import org.eclipse.rwt.RWT;
18
import org.eclipse.rwt.internal.util.ParamCheck;
19
import org.eclipse.rwt.service.*;
20
import org.eclipse.ui.internal.WorkbenchPlugin;
21
22
/**
23
 * This class is the link between the SessionPreferenceNode hierarchy 
24
 * (application global) the RWT setting store (session specific).
25
 */
26
final class SessionPreferenceNodeCore {
27
  
28
  private final SessionPreferencesNode node;
29
  private ListenerList prefListeners; // ListenerList is thread safe
30
31
  /* tracks changes in RWT setting store and notifies the prefListeners */
32
  private ISettingStoreListener rwtListener;
33
  /* true to track RWT changes */
34
  private boolean trackChanges = true;
35
  /* ignore changes to this key for a short time */
36
  private String ignoreKey;
37
  
38
  SessionPreferenceNodeCore( final SessionPreferencesNode node ) {
39
    ParamCheck.notNull( node, "node" );
40
    this.node = node;
41
  }
42
  
43
  void addPreferenceChangeListener( IPreferenceChangeListener listener ) {
44
    if( listener != null ) {
45
      getListenerList().add( listener );
46
      setTrackRWTChanges( true );
47
    }
48
  }
49
50
  void removePreferenceChangeListener( IPreferenceChangeListener listener ) {
51
    if( listener != null ) {
52
      ListenerList list = getListenerList();
53
      list.remove( listener );
54
      if( list.isEmpty() ) {
55
        setTrackRWTChanges( false );
56
      }
57
    }
58
  }
59
  
60
  void firePreferenceEvent( final String key, 
61
                            final String oldValue, 
62
                            final String newValue )
63
  {
64
    if( prefListeners != null ) {
65
      final PreferenceChangeEvent event 
66
        = new PreferenceChangeEvent( node, key, oldValue, newValue );
67
      Object[] listeners = prefListeners.getListeners();
68
      for( int i = 0; i < listeners.length; i++ ) {
69
        final IPreferenceChangeListener listener 
70
          = ( IPreferenceChangeListener )listeners[ i ];
71
        ISafeRunnable op = new ISafeRunnable() {
72
          public void handleException( final Throwable exception ) {
73
            // logged by SafeRunner
74
          }
75
          public void run() throws Exception {
76
            listener.preferenceChange( event );
77
          }
78
        };
79
        SafeRunner.run( op );
80
      }
81
    }
82
  }
83
  
84
  void clear() {
85
    if( prefListeners != null ) {
86
      prefListeners.clear();
87
      prefListeners = null;
88
      setTrackRWTChanges( false );
89
    }
90
  }
91
  
92
  synchronized String put( final String uniqueKey,
93
                           final String value ) {
94
    ISettingStore store = RWT.getSettingStore();
95
    String result = store.getAttribute( uniqueKey );
96
    try {
97
      ignoreKey = uniqueKey;
98
      store.setAttribute( uniqueKey, value );
99
      ignoreKey = null;
100
    } catch( SettingStoreException exc ) {
101
      String msg = "Could not persist preference: " + uniqueKey;
102
      WorkbenchPlugin.log( msg, exc );
103
    }
104
    return result;
105
  }
106
  
107
  // helping methods
108
  //////////////////
109
  
110
  private synchronized ListenerList getListenerList() {
111
    if( prefListeners == null ) {
112
      prefListeners = new ListenerList( ListenerList.IDENTITY );
113
    }
114
    return prefListeners;
115
  }
116
  
117
  private synchronized void setTrackRWTChanges( final boolean doTrack ) {
118
    this.trackChanges = doTrack;
119
    if( trackChanges ) {
120
      if( rwtListener == null ) {
121
       rwtListener = new ISettingStoreListener() {
122
        public void settingChanged( ISettingStoreEvent event ) {
123
          if( trackChanges ) {
124
            String fullKey = event.getAtributeName();
125
            if( !fullKey.equals( ignoreKey ) ) {
126
              String absPath = node.absolutePath();
127
              if( fullKey.startsWith( absPath ) ) {
128
                String key = fullKey.substring( absPath.length() + 1 );
129
                String oldValue = event.getOldValue();
130
                String newValue = event.getNewValue();
131
                firePreferenceEvent( key, oldValue, newValue );
132
              }
133
            }
134
          }
135
        }
136
       };
137
     }
138
     RWT.getSettingStore().addSettingStoreListener( rwtListener );
139
   } else { // !trackChanges
140
     if( rwtListener != null ) {
141
       RWT.getSettingStore().removeSettingStoreListener( rwtListener );
142
     }
143
   }
144
  }
145
  
146
}
(-)src/org/eclipse/ui/preferences/ScopedPreferenceStore.java (+855 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004, 2006 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
 *******************************************************************************/
11
package org.eclipse.ui.preferences;
12
13
import java.io.IOException;
14
15
import org.eclipse.core.commands.common.EventManager;
16
import org.eclipse.core.runtime.Assert;
17
import org.eclipse.core.runtime.Platform;
18
import org.eclipse.core.runtime.Plugin;
19
import org.eclipse.core.runtime.SafeRunner;
20
import org.eclipse.core.runtime.preferences.DefaultScope;
21
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
22
import org.eclipse.core.runtime.preferences.IScopeContext;
23
import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
24
import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
25
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
26
import org.eclipse.jface.preference.IPersistentPreferenceStore;
27
import org.eclipse.jface.preference.IPreferenceStore;
28
import org.eclipse.jface.resource.JFaceResources;
29
import org.eclipse.jface.util.IPropertyChangeListener;
30
import org.eclipse.jface.util.PropertyChangeEvent;
31
import org.eclipse.jface.util.SafeRunnable;
32
import org.eclipse.ui.internal.WorkbenchMessages;
33
import org.osgi.service.prefs.BackingStoreException;
34
35
/**
36
 * The ScopedPreferenceStore is an IPreferenceStore that uses the scopes
37
 * provided in org.eclipse.core.runtime.preferences.
38
 * <p>
39
 * A ScopedPreferenceStore does the lookup of a preference based on it's search
40
 * scopes and sets the value of the preference based on its store scope.
41
 * </p>
42
 * <p>
43
 * The default scope is always included in the search scopes when searching for
44
 * preference values.
45
 * </p>
46
 * 
47
 * @see org.eclipse.core.runtime.preferences
48
 * @since 1.1
49
 */
50
public class ScopedPreferenceStore extends EventManager implements
51
		IPreferenceStore, IPersistentPreferenceStore {
52
53
	/**
54
	 * The storeContext is the context where values will stored with the
55
	 * setValue methods. If there are no searchContexts this will be the search
56
	 * context. (along with the "default" context)
57
	 */
58
	private IScopeContext storeContext;
59
60
	/**
61
	 * The searchContext is the array of contexts that will be used by the get
62
	 * methods for searching for values.
63
	 */
64
	private IScopeContext[] searchContexts;
65
66
	/**
67
	 * A boolean to indicate the property changes should not be propagated.
68
	 */
69
	protected boolean silentRunning = false;
70
71
	/**
72
	 * The listener on the IEclipsePreferences. This is used to forward updates
73
	 * to the property change listeners on the preference store.
74
	 */
75
	IEclipsePreferences.IPreferenceChangeListener preferencesListener;
76
77
	/**
78
	 * The default context is the context where getDefault and setDefault
79
	 * methods will search. This context is also used in the search.
80
	 */
81
	private IScopeContext defaultContext = new DefaultScope();
82
83
	/**
84
	 * The nodeQualifer is the string used to look up the node in the contexts.
85
	 */
86
	String nodeQualifier;
87
88
	/**
89
	 * The defaultQualifier is the string used to look up the default node.
90
	 */
91
	String defaultQualifier;
92
93
	/**
94
	 * Boolean value indicating whether or not this store has changes to be
95
	 * saved.
96
	 */
97
	private boolean dirty;
98
99
	/**
100
	 * Create a new instance of the receiver. Store the values in context in the
101
	 * node looked up by qualifier. <strong>NOTE:</strong> Any instance of
102
	 * ScopedPreferenceStore should call
103
	 * 
104
	 * @param context
105
	 *            the scope to store to
106
	 * @param qualifier
107
	 *            the qualifier used to look up the preference node
108
	 * @param defaultQualifierPath
109
	 *            the qualifier used when looking up the defaults
110
	 */
111
	public ScopedPreferenceStore(IScopeContext context, String qualifier,
112
			String defaultQualifierPath) {
113
		this(context, qualifier);
114
		this.defaultQualifier = defaultQualifierPath;
115
	}
116
117
	/**
118
	 * Create a new instance of the receiver. Store the values in context in the
119
	 * node looked up by qualifier.
120
	 * 
121
	 * @param context
122
	 *            the scope to store to
123
	 * @param qualifier
124
	 *            the qualifer used to look up the preference node
125
	 */
126
	public ScopedPreferenceStore(IScopeContext context, String qualifier) {
127
		storeContext = context;
128
		this.nodeQualifier = qualifier;
129
		this.defaultQualifier = qualifier;
130
131
		((IEclipsePreferences) getStorePreferences().parent())
132
				.addNodeChangeListener(getNodeChangeListener());
133
	}
134
135
	/**
136
	 * Return a node change listener that adds a removes the receiver when nodes
137
	 * change.
138
	 * 
139
	 * @return INodeChangeListener
140
	 */
141
	private INodeChangeListener getNodeChangeListener() {
142
		return new IEclipsePreferences.INodeChangeListener() {
143
			/*
144
			 * (non-Javadoc)
145
			 * 
146
			 * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#added(org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent)
147
			 */
148
			public void added(NodeChangeEvent event) {
149
				if (nodeQualifier.equals(event.getChild().name())
150
						&& isListenerAttached()) {
151
					getStorePreferences().addPreferenceChangeListener(
152
							preferencesListener);
153
				}
154
			}
155
156
			/*
157
			 * (non-Javadoc)
158
			 * 
159
			 * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#removed(org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent)
160
			 */
161
			public void removed(NodeChangeEvent event) {
162
				// Do nothing as there are no events from removed node
163
			}
164
		};
165
	}
166
167
	/**
168
	 * Initialize the preferences listener.
169
	 */
170
	private void initializePreferencesListener() {
171
		if (preferencesListener == null) {
172
			preferencesListener = new IEclipsePreferences.IPreferenceChangeListener() {
173
				/*
174
				 * (non-Javadoc)
175
				 * 
176
				 * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent)
177
				 */
178
				public void preferenceChange(PreferenceChangeEvent event) {
179
180
					if (silentRunning) {
181
						return;
182
					}
183
184
					Object oldValue = event.getOldValue();
185
					Object newValue = event.getNewValue();
186
					String key = event.getKey();
187
					if (newValue == null) {
188
						newValue = getDefault(key, oldValue);
189
					} else if (oldValue == null) {
190
						oldValue = getDefault(key, newValue);
191
					}
192
					firePropertyChangeEvent(event.getKey(), oldValue, newValue);
193
				}
194
			};
195
			getStorePreferences().addPreferenceChangeListener(
196
					preferencesListener);
197
		}
198
199
	}
200
201
	/**
202
	 * Does its best at determining the default value for the given key. Checks
203
	 * the given object's type and then looks in the list of defaults to see if
204
	 * a value exists. If not or if there is a problem converting the value, the
205
	 * default default value for that type is returned.
206
	 * 
207
	 * @param key
208
	 *            the key to search
209
	 * @param obj
210
	 *            the object who default we are looking for
211
	 * @return Object or <code>null</code>
212
	 */
213
	Object getDefault(String key, Object obj) {
214
		IEclipsePreferences defaults = getDefaultPreferences();
215
		if (obj instanceof String) {
216
			return defaults.get(key, STRING_DEFAULT_DEFAULT);
217
		} else if (obj instanceof Integer) {
218
			return new Integer(defaults.getInt(key, INT_DEFAULT_DEFAULT));
219
		} else if (obj instanceof Double) {
220
			return new Double(defaults.getDouble(key, DOUBLE_DEFAULT_DEFAULT));
221
		} else if (obj instanceof Float) {
222
			return new Float(defaults.getFloat(key, FLOAT_DEFAULT_DEFAULT));
223
		} else if (obj instanceof Long) {
224
			return new Long(defaults.getLong(key, LONG_DEFAULT_DEFAULT));
225
		} else if (obj instanceof Boolean) {
226
			return defaults.getBoolean(key, BOOLEAN_DEFAULT_DEFAULT) ? Boolean.TRUE : Boolean.FALSE;
227
		} else {
228
			return null;
229
		}
230
	}
231
232
	/**
233
	 * Return the IEclipsePreferences node associated with this store.
234
	 * 
235
	 * @return the preference node for this store
236
	 */
237
	IEclipsePreferences getStorePreferences() {
238
		return storeContext.getNode(nodeQualifier);
239
	}
240
241
	/**
242
	 * Return the default IEclipsePreferences for this store.
243
	 * 
244
	 * @return this store's default preference node
245
	 */
246
	private IEclipsePreferences getDefaultPreferences() {
247
		return defaultContext.getNode(defaultQualifier);
248
	}
249
250
	/*
251
	 * (non-Javadoc)
252
	 * 
253
	 * @see org.eclipse.jface.preference.IPreferenceStore#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
254
	 */
255
	public void addPropertyChangeListener(IPropertyChangeListener listener) {
256
		initializePreferencesListener();// Create the preferences listener if it
257
		// does not exist
258
		addListenerObject(listener);
259
	}
260
261
	/**
262
	 * Return the preference path to search preferences on. This is the list of
263
	 * preference nodes based on the scope contexts for this store. If there are
264
	 * no search contexts set, then return this store's context.
265
	 * <p>
266
	 * Whether or not the default context should be included in the resulting
267
	 * list is specified by the <code>includeDefault</code> parameter.
268
	 * </p>
269
	 * 
270
	 * @param includeDefault
271
	 *            <code>true</code> if the default context should be included
272
	 *            and <code>false</code> otherwise
273
	 * @return IEclipsePreferences[]
274
	 */
275
	private IEclipsePreferences[] getPreferenceNodes(boolean includeDefault) {
276
		// if the user didn't specify a search order, then return the scope that
277
		// this store was created on. (and optionally the default)
278
		if (searchContexts == null) {
279
			if (includeDefault) {
280
				return new IEclipsePreferences[] { getStorePreferences(),
281
						getDefaultPreferences() };
282
			}
283
			return new IEclipsePreferences[] { getStorePreferences() };
284
		}
285
		// otherwise the user specified a search order so return the appropriate
286
		// nodes based on it
287
		int length = searchContexts.length;
288
		if (includeDefault) {
289
			length++;
290
		}
291
		IEclipsePreferences[] preferences = new IEclipsePreferences[length];
292
		for (int i = 0; i < searchContexts.length; i++) {
293
			preferences[i] = searchContexts[i].getNode(nodeQualifier);
294
		}
295
		if (includeDefault) {
296
			preferences[length - 1] = getDefaultPreferences();
297
		}
298
		return preferences;
299
	}
300
301
	/**
302
	 * Set the search contexts to scopes. When searching for a value the seach
303
	 * will be done in the order of scope contexts and will not search the
304
	 * storeContext unless it is in this list.
305
	 * <p>
306
	 * If the given list is <code>null</code>, then clear this store's search
307
	 * contexts. This means that only this store's scope context and default
308
	 * scope will be used during preference value searching.
309
	 * </p>
310
	 * <p>
311
	 * The defaultContext will be added to the end of this list automatically
312
	 * and <em>MUST NOT</em> be included by the user.
313
	 * </p>
314
	 * 
315
	 * @param scopes
316
	 *            a list of scope contexts to use when searching, or
317
	 *            <code>null</code>
318
	 */
319
	public void setSearchContexts(IScopeContext[] scopes) {
320
		this.searchContexts = scopes;
321
		if (scopes == null) {
322
			return;
323
		}
324
325
		// Assert that the default was not included (we automatically add it to
326
		// the end)
327
		for (int i = 0; i < scopes.length; i++) {
328
			if (scopes[i].equals(defaultContext)) {
329
				Assert
330
						.isTrue(
331
								false,
332
								WorkbenchMessages.get().ScopedPreferenceStore_DefaultAddedError);
333
			}
334
		}
335
	}
336
337
	/*
338
	 * (non-Javadoc)
339
	 * 
340
	 * @see org.eclipse.jface.preference.IPreferenceStore#contains(java.lang.String)
341
	 */
342
	public boolean contains(String name) {
343
		if (name == null) {
344
			return false;
345
		}
346
		return (Platform.getPreferencesService().get(name, null,
347
				getPreferenceNodes(true))) != null;
348
	}
349
350
	/*
351
	 * (non-Javadoc)
352
	 * 
353
	 * @see org.eclipse.jface.preference.IPreferenceStore#firePropertyChangeEvent(java.lang.String,
354
	 *      java.lang.Object, java.lang.Object)
355
	 */
356
	public void firePropertyChangeEvent(String name, Object oldValue,
357
			Object newValue) {
358
		// important: create intermediate array to protect against listeners
359
		// being added/removed during the notification
360
		final Object[] list = getListeners();
361
		if (list.length == 0) {
362
			return;
363
		}
364
		final PropertyChangeEvent event = new PropertyChangeEvent(this, name,
365
				oldValue, newValue);
366
		for (int i = 0; i < list.length; i++) {
367
			final IPropertyChangeListener listener = (IPropertyChangeListener) list[i];
368
			SafeRunner.run(new SafeRunnable(JFaceResources
369
					.getString("PreferenceStore.changeError")) { //$NON-NLS-1$
370
						public void run() {
371
							listener.propertyChange(event);
372
						}
373
					});
374
		}
375
	}
376
377
	/*
378
	 * (non-Javadoc)
379
	 * 
380
	 * @see org.eclipse.jface.preference.IPreferenceStore#getBoolean(java.lang.String)
381
	 */
382
	public boolean getBoolean(String name) {
383
		String value = internalGet(name);
384
		return value == null ? BOOLEAN_DEFAULT_DEFAULT : Boolean.valueOf(value)
385
				.booleanValue();
386
	}
387
388
	/*
389
	 * (non-Javadoc)
390
	 * 
391
	 * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultBoolean(java.lang.String)
392
	 */
393
	public boolean getDefaultBoolean(String name) {
394
		return getDefaultPreferences()
395
				.getBoolean(name, BOOLEAN_DEFAULT_DEFAULT);
396
	}
397
398
	/*
399
	 * (non-Javadoc)
400
	 * 
401
	 * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultDouble(java.lang.String)
402
	 */
403
	public double getDefaultDouble(String name) {
404
		return getDefaultPreferences().getDouble(name, DOUBLE_DEFAULT_DEFAULT);
405
	}
406
407
	/*
408
	 * (non-Javadoc)
409
	 * 
410
	 * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultFloat(java.lang.String)
411
	 */
412
	public float getDefaultFloat(String name) {
413
		return getDefaultPreferences().getFloat(name, FLOAT_DEFAULT_DEFAULT);
414
	}
415
416
	/*
417
	 * (non-Javadoc)
418
	 * 
419
	 * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultInt(java.lang.String)
420
	 */
421
	public int getDefaultInt(String name) {
422
		return getDefaultPreferences().getInt(name, INT_DEFAULT_DEFAULT);
423
	}
424
425
	/*
426
	 * (non-Javadoc)
427
	 * 
428
	 * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultLong(java.lang.String)
429
	 */
430
	public long getDefaultLong(String name) {
431
		return getDefaultPreferences().getLong(name, LONG_DEFAULT_DEFAULT);
432
	}
433
434
	/*
435
	 * (non-Javadoc)
436
	 * 
437
	 * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultString(java.lang.String)
438
	 */
439
	public String getDefaultString(String name) {
440
		return getDefaultPreferences().get(name, STRING_DEFAULT_DEFAULT);
441
	}
442
443
	/*
444
	 * (non-Javadoc)
445
	 * 
446
	 * @see org.eclipse.jface.preference.IPreferenceStore#getDouble(java.lang.String)
447
	 */
448
	public double getDouble(String name) {
449
		String value = internalGet(name);
450
		if (value == null) {
451
			return DOUBLE_DEFAULT_DEFAULT;
452
		}
453
		try {
454
			return Double.parseDouble(value);
455
		} catch (NumberFormatException e) {
456
			return DOUBLE_DEFAULT_DEFAULT;
457
		}
458
	}
459
460
	/**
461
	 * Return the string value for the specified key. Look in the nodes which
462
	 * are specified by this object's list of search scopes. If the value does
463
	 * not exist then return <code>null</code>.
464
	 * 
465
	 * @param key
466
	 *            the key to search with
467
	 * @return String or <code>null</code> if the value does not exist.
468
	 */
469
	private String internalGet(String key) {
470
		return Platform.getPreferencesService().get(key, null,
471
				getPreferenceNodes(true));
472
	}
473
474
	/*
475
	 * (non-Javadoc)
476
	 * 
477
	 * @see org.eclipse.jface.preference.IPreferenceStore#getFloat(java.lang.String)
478
	 */
479
	public float getFloat(String name) {
480
		String value = internalGet(name);
481
		if (value == null) {
482
			return FLOAT_DEFAULT_DEFAULT;
483
		}
484
		try {
485
			return Float.parseFloat(value);
486
		} catch (NumberFormatException e) {
487
			return FLOAT_DEFAULT_DEFAULT;
488
		}
489
	}
490
491
	/*
492
	 * (non-Javadoc)
493
	 * 
494
	 * @see org.eclipse.jface.preference.IPreferenceStore#getInt(java.lang.String)
495
	 */
496
	public int getInt(String name) {
497
		String value = internalGet(name);
498
		if (value == null) {
499
			return INT_DEFAULT_DEFAULT;
500
		}
501
		try {
502
			return Integer.parseInt(value);
503
		} catch (NumberFormatException e) {
504
			return INT_DEFAULT_DEFAULT;
505
		}
506
	}
507
508
	/*
509
	 * (non-Javadoc)
510
	 * 
511
	 * @see org.eclipse.jface.preference.IPreferenceStore#getLong(java.lang.String)
512
	 */
513
	public long getLong(String name) {
514
		String value = internalGet(name);
515
		if (value == null) {
516
			return LONG_DEFAULT_DEFAULT;
517
		}
518
		try {
519
			return Long.parseLong(value);
520
		} catch (NumberFormatException e) {
521
			return LONG_DEFAULT_DEFAULT;
522
		}
523
	}
524
525
	/*
526
	 * (non-Javadoc)
527
	 * 
528
	 * @see org.eclipse.jface.preference.IPreferenceStore#getString(java.lang.String)
529
	 */
530
	public String getString(String name) {
531
		String value = internalGet(name);
532
		return value == null ? STRING_DEFAULT_DEFAULT : value;
533
	}
534
535
	/*
536
	 * (non-Javadoc)
537
	 * 
538
	 * @see org.eclipse.jface.preference.IPreferenceStore#isDefault(java.lang.String)
539
	 */
540
	public boolean isDefault(String name) {
541
		if (name == null) {
542
			return false;
543
		}
544
		return (Platform.getPreferencesService().get(name, null,
545
				getPreferenceNodes(false))) == null;
546
	}
547
548
	/*
549
	 * (non-Javadoc)
550
	 * 
551
	 * @see org.eclipse.jface.preference.IPreferenceStore#needsSaving()
552
	 */
553
	public boolean needsSaving() {
554
		return dirty;
555
	}
556
557
	/*
558
	 * (non-Javadoc)
559
	 * 
560
	 * @see org.eclipse.jface.preference.IPreferenceStore#putValue(java.lang.String,
561
	 *      java.lang.String)
562
	 */
563
	public void putValue(String name, String value) {
564
		try {
565
			// Do not notify listeners
566
			silentRunning = true;
567
			getStorePreferences().put(name, value);
568
		} finally {
569
			// Be sure that an exception does not stop property updates
570
			silentRunning = false;
571
			dirty = true;
572
		}
573
	}
574
575
	/*
576
	 * (non-Javadoc)
577
	 * 
578
	 * @see org.eclipse.jface.preference.IPreferenceStore#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
579
	 */
580
	public void removePropertyChangeListener(IPropertyChangeListener listener) {
581
		removeListenerObject(listener);
582
		if (!isListenerAttached()) {
583
			disposePreferenceStoreListener();
584
		}
585
	}
586
587
	/*
588
	 * (non-Javadoc)
589
	 * 
590
	 * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
591
	 *      double)
592
	 */
593
	public void setDefault(String name, double value) {
594
		getDefaultPreferences().putDouble(name, value);
595
	}
596
597
	/*
598
	 * (non-Javadoc)
599
	 * 
600
	 * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
601
	 *      float)
602
	 */
603
	public void setDefault(String name, float value) {
604
		getDefaultPreferences().putFloat(name, value);
605
	}
606
607
	/*
608
	 * (non-Javadoc)
609
	 * 
610
	 * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
611
	 *      int)
612
	 */
613
	public void setDefault(String name, int value) {
614
		getDefaultPreferences().putInt(name, value);
615
	}
616
617
	/*
618
	 * (non-Javadoc)
619
	 * 
620
	 * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
621
	 *      long)
622
	 */
623
	public void setDefault(String name, long value) {
624
		getDefaultPreferences().putLong(name, value);
625
	}
626
627
	/*
628
	 * (non-Javadoc)
629
	 * 
630
	 * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
631
	 *      java.lang.String)
632
	 */
633
	public void setDefault(String name, String defaultObject) {
634
		getDefaultPreferences().put(name, defaultObject);
635
	}
636
637
	/*
638
	 * (non-Javadoc)
639
	 * 
640
	 * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
641
	 *      boolean)
642
	 */
643
	public void setDefault(String name, boolean value) {
644
		getDefaultPreferences().putBoolean(name, value);
645
	}
646
647
	/*
648
	 * (non-Javadoc)
649
	 * 
650
	 * @see org.eclipse.jface.preference.IPreferenceStore#setToDefault(java.lang.String)
651
	 */
652
	public void setToDefault(String name) {
653
654
		String oldValue = getString(name);
655
		String defaultValue = getDefaultString(name);
656
		try {
657
			silentRunning = true;// Turn off updates from the store
658
			// removing a non-existing preference is a no-op so call the Core
659
			// API directly
660
			getStorePreferences().remove(name);
661
			dirty = true;
662
			firePropertyChangeEvent(name, oldValue, defaultValue);
663
		} finally {
664
			silentRunning = false;// Restart listening to preferences
665
		}
666
667
	}
668
669
	/*
670
	 * (non-Javadoc)
671
	 * 
672
	 * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
673
	 *      double)
674
	 */
675
	public void setValue(String name, double value) {
676
		double oldValue = getDouble(name);
677
		if (oldValue == value) {
678
			return;
679
		}
680
		try {
681
			silentRunning = true;// Turn off updates from the store
682
			if (getDefaultDouble(name) == value) {
683
				getStorePreferences().remove(name);
684
			} else {
685
				getStorePreferences().putDouble(name, value);
686
			}
687
			dirty = true;
688
			firePropertyChangeEvent(name, new Double(oldValue), new Double(
689
					value));
690
		} finally {
691
			silentRunning = false;// Restart listening to preferences
692
		}
693
	}
694
695
	/*
696
	 * (non-Javadoc)
697
	 * 
698
	 * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
699
	 *      float)
700
	 */
701
	public void setValue(String name, float value) {
702
		float oldValue = getFloat(name);
703
		if (oldValue == value) {
704
			return;
705
		}
706
		try {
707
			silentRunning = true;// Turn off updates from the store
708
			if (getDefaultFloat(name) == value) {
709
				getStorePreferences().remove(name);
710
			} else {
711
				getStorePreferences().putFloat(name, value);
712
			}
713
			dirty = true;
714
			firePropertyChangeEvent(name, new Float(oldValue), new Float(value));
715
		} finally {
716
			silentRunning = false;// Restart listening to preferences
717
		}
718
	}
719
720
	/*
721
	 * (non-Javadoc)
722
	 * 
723
	 * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
724
	 *      int)
725
	 */
726
	public void setValue(String name, int value) {
727
		int oldValue = getInt(name);
728
		if (oldValue == value) {
729
			return;
730
		}
731
		try {
732
			silentRunning = true;// Turn off updates from the store
733
			if (getDefaultInt(name) == value) {
734
				getStorePreferences().remove(name);
735
			} else {
736
				getStorePreferences().putInt(name, value);
737
			}
738
			dirty = true;
739
			firePropertyChangeEvent(name, new Integer(oldValue), new Integer(
740
					value));
741
		} finally {
742
			silentRunning = false;// Restart listening to preferences
743
		}
744
	}
745
746
	/*
747
	 * (non-Javadoc)
748
	 * 
749
	 * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
750
	 *      long)
751
	 */
752
	public void setValue(String name, long value) {
753
		long oldValue = getLong(name);
754
		if (oldValue == value) {
755
			return;
756
		}
757
		try {
758
			silentRunning = true;// Turn off updates from the store
759
			if (getDefaultLong(name) == value) {
760
				getStorePreferences().remove(name);
761
			} else {
762
				getStorePreferences().putLong(name, value);
763
			}
764
			dirty = true;
765
			firePropertyChangeEvent(name, new Long(oldValue), new Long(value));
766
		} finally {
767
			silentRunning = false;// Restart listening to preferences
768
		}
769
	}
770
771
	/*
772
	 * (non-Javadoc)
773
	 * 
774
	 * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
775
	 *      java.lang.String)
776
	 */
777
	public void setValue(String name, String value) {
778
		// Do not turn on silent running here as Strings are propagated
779
		if (getDefaultString(name).equals(value)) {
780
			getStorePreferences().remove(name);
781
		} else {
782
			getStorePreferences().put(name, value);
783
		}
784
		dirty = true;
785
	}
786
787
	/*
788
	 * (non-Javadoc)
789
	 * 
790
	 * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
791
	 *      boolean)
792
	 */
793
	public void setValue(String name, boolean value) {
794
		boolean oldValue = getBoolean(name);
795
		if (oldValue == value) {
796
			return;
797
		}
798
		try {
799
			silentRunning = true;// Turn off updates from the store
800
			if (getDefaultBoolean(name) == value) {
801
				getStorePreferences().remove(name);
802
			} else {
803
				getStorePreferences().putBoolean(name, value);
804
			}
805
			dirty = true;
806
			firePropertyChangeEvent(name, oldValue ? Boolean.TRUE : Boolean.FALSE, 
807
				value ? Boolean.TRUE : Boolean.FALSE);
808
		} finally {
809
			silentRunning = false;// Restart listening to preferences
810
		}
811
	}
812
813
	/*
814
	 * (non-Javadoc)
815
	 * 
816
	 * @see org.eclipse.jface.preference.IPersistentPreferenceStore#save()
817
	 */
818
	public void save() throws IOException {
819
		try {
820
			getStorePreferences().flush();
821
			dirty = false;
822
		} catch (BackingStoreException e) {
823
			throw new IOException(e.getMessage());
824
		}
825
826
	}
827
828
	/**
829
	 * Dispose the receiver.
830
	 */
831
	private void disposePreferenceStoreListener() {
832
833
		IEclipsePreferences root = (IEclipsePreferences) Platform
834
				.getPreferencesService().getRootNode().node(
835
						Plugin.PLUGIN_PREFERENCE_SCOPE);
836
		try {
837
			if (!(root.nodeExists(nodeQualifier))) {
838
				return;
839
			}
840
		} catch (BackingStoreException e) {
841
			return;// No need to report here as the node won't have the
842
			// listener
843
		}
844
845
		IEclipsePreferences preferences = getStorePreferences();
846
		if (preferences == null) {
847
			return;
848
		}
849
		if (preferencesListener != null) {
850
			preferences.removePreferenceChangeListener(preferencesListener);
851
			preferencesListener = null;
852
		}
853
	}
854
855
}
(-)src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesFactory.java (+27 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2002-2008 Innoopract Informationssysteme GmbH.
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
 *     Innoopract Informationssysteme GmbH - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.rap.ui.internal.preferences;
13
14
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
15
import org.eclipse.core.runtime.preferences.IScope;
16
17
/**
18
 * Creates "session" scoped preference nodes.
19
 */
20
public final class SessionPreferencesFactory implements IScope {
21
22
  public IEclipsePreferences create( final IEclipsePreferences parent, 
23
                                     final String name ) {
24
    return new SessionPreferencesNode( parent, name );
25
  }
26
  
27
}
(-)src/org/eclipse/rap/ui/preferences/SessionScope.java (+70 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2002-2008 Innoopract Informationssysteme GmbH.
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
 *     Innoopract Informationssysteme GmbH - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.rap.ui.preferences;
13
14
import org.eclipse.core.runtime.IPath;
15
import org.eclipse.core.runtime.Platform;
16
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
17
import org.eclipse.core.runtime.preferences.IScopeContext;
18
import org.eclipse.rwt.RWT;
19
import org.eclipse.rwt.internal.util.ParamCheck;
20
import org.eclipse.rwt.service.FileSettingStore;
21
22
/**
23
 * Object representing the session scope in the Eclipse preferences
24
 * hierarchy. Can be used as a context for searching for preference
25
 * values (in the IPreferenceService APIs) or for determining the
26
 * corrent preference node to set values in the store.
27
 * <p>
28
 * Session preferences are stored on a <i>per-session</i> basis using
29
 * the underlying RWT SettingStore (see {@link RWT#getSettingStore()}. 
30
 * Preferences saved during a previous session will be retrieved, as long as
31
 * the user can identify himself with the setting store cookie. Session 
32
 * preferences are persisted using the setting store implementation
33
 * that is configured for the application (see {@link FileSettingStore}.
34
 * <p>
35
 * The path for preferences defined in the session scope hierarchy is: 
36
 * <code>/session/&lt;qualifier&gt;</code>
37
 * <p>
38
 * This class is not intented to be subclassed. It may be instantiated.
39
 *
40
 * @since 1.1
41
 */
42
public final class SessionScope implements IScopeContext {
43
44
  /**
45
   * String constant (value of <code>"session"</code>) used for the 
46
   * scope name for the session preference scope.
47
   */
48
  public static final String SCOPE = "session"; //$NON-NLS-1$
49
  
50
  /**
51
   * Create and return a new session scope instance.
52
   */
53
  public SessionScope() {
54
      super();
55
  }
56
57
  public IPath getLocation() {
58
    return null;
59
  }
60
61
  public String getName() {
62
    return SCOPE;
63
  }
64
65
  public IEclipsePreferences getNode( String qualifier ) {
66
    ParamCheck.notNull( qualifier, "qualifier" );
67
    IEclipsePreferences root = Platform.getPreferencesService().getRootNode();
68
    return ( IEclipsePreferences ) root.node( SCOPE ).node( qualifier );
69
  }
70
}
(-)src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesNode.java (+531 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2002-2008 Innoopract Informationssysteme GmbH.
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
 *     Innoopract Informationssysteme GmbH - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.rap.ui.internal.preferences;
12
13
import java.util.*;
14
15
import org.eclipse.core.internal.preferences.Base64;
16
import org.eclipse.core.runtime.*;
17
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
18
import org.eclipse.core.runtime.preferences.IPreferenceNodeVisitor;
19
import org.eclipse.osgi.util.NLS;
20
import org.eclipse.rwt.RWT;
21
import org.eclipse.rwt.internal.util.ParamCheck;
22
import org.eclipse.rwt.service.ISettingStore;
23
import org.eclipse.rwt.service.SettingStoreException;
24
import org.osgi.service.prefs.BackingStoreException;
25
import org.osgi.service.prefs.Preferences;
26
27
/**
28
 * This node use the RWT setting store to persist its preferences.
29
 */
30
final class SessionPreferencesNode 
31
  implements IEclipsePreferences 
32
{
33
34
  private static final String PATH_SEPARATOR = "/";
35
  private static final String DOUBLE_PATH_SEPARATOR = "//";
36
  private static final String TRUE  = "true";
37
  private static final String FALSE = "false";
38
  
39
  private final String name;
40
  private final IEclipsePreferences parent;
41
  private boolean isRemoved;
42
  /* cache the absolutePath once it has been computed */
43
  private String absolutePath;
44
  
45
  private final Map children = new HashMap();    // !thread safe
46
  private final ListenerList nodeListeners       
47
    = new ListenerList( ListenerList.IDENTITY ); // thread safe
48
  
49
  SessionPreferencesNode( final IEclipsePreferences parent, 
50
                          final String name ) {
51
    ParamCheck.notNull( parent, "parent" );
52
    ParamCheck.notNull( name, "name" );
53
    checkName( name );
54
    this.parent = parent;
55
    this.name = name;
56
  }
57
  
58
  public void accept( final IPreferenceNodeVisitor visitor )
59
    throws BackingStoreException
60
  {
61
    boolean withChildren = visitor.visit( this );
62
    if( withChildren ) {
63
      Object[] childrenArray;
64
      synchronized( this ) {
65
        childrenArray = children.values().toArray();
66
      }
67
      for( int i = 0; i < childrenArray.length; i++ ) {
68
        IEclipsePreferences child = ( IEclipsePreferences )childrenArray[ i ];
69
        child.accept( visitor );
70
      }
71
    }
72
  }
73
74
  public void addNodeChangeListener( final INodeChangeListener listener ) {
75
    checkRemoved();
76
    if( listener != null ) {
77
      nodeListeners.add( listener );
78
    }
79
  }
80
81
  public void addPreferenceChangeListener( 
82
    final IPreferenceChangeListener listener )
83
  {
84
    checkRemoved();
85
    getNodeCore().addPreferenceChangeListener( listener );
86
  }
87
88
  public Preferences node( final String path ) {
89
    checkPath( path );
90
    checkRemoved();
91
    Preferences result;
92
    if( "".equals( path ) ) { // ""
93
      result = this;
94
    } else if( path.startsWith( PATH_SEPARATOR ) ) { // "/absolute/path"
95
      result = findRoot().node( path.substring( 1 ) );
96
    } else if( path.indexOf( PATH_SEPARATOR ) > 0 ) { // "foo/bar/baz"
97
      int index = path.indexOf( PATH_SEPARATOR );
98
      String nodeName = path.substring( 0, index );
99
      String rest = path.substring( index + 1, path.length() ); 
100
      result = getChild( nodeName, true ).node( rest );
101
    } else { // "foo"
102
      result = getChild( path, true );
103
    }
104
    return result;
105
  }
106
107
  public synchronized void removeNode() throws BackingStoreException {
108
    checkRemoved();
109
    // remove all preferences
110
    clear(); 
111
    // remove all children
112
    Object[] childNodes = children.values().toArray();
113
    for( int i = 0; i < childNodes.length; i++ ) {
114
      Preferences child = ( Preferences )childNodes[ i ];
115
      if( child.nodeExists( "" ) ) { // if !removed
116
        child.removeNode();
117
      }
118
    }
119
    // remove from parent; this is ugly, because the interface 
120
    // Preference has no API for removing oneself from the parent.
121
    // In general the parent will be a SessionPreferencesNode.
122
    // The only case in the workbench where this is not true, is one level
123
    // below the root (i.e. at /session ), but the scope root must not
124
    // be removable (see IEclipsePreferences#removeNode())
125
    if( parent instanceof SessionPreferencesNode ) {
126
      // this means: 
127
      // (a) we know what kind of parent we have, and 
128
      // (b) we are not the scope root, since that has a 
129
      /// RootPreference as a parent
130
      SessionPreferencesNode spnParent 
131
        = ( ( SessionPreferencesNode ) parent );
132
      spnParent.children.remove( name );
133
      spnParent.fireNodeEvent( this, false );
134
135
      // the listeners are not needed anymore
136
      getNodeCore().clear();
137
      nodeListeners.clear();
138
      children.clear();
139
      isRemoved = true;
140
    }
141
  }
142
143
  public void removeNodeChangeListener( final INodeChangeListener listener ) {
144
    checkRemoved();
145
    if( listener != null ) {
146
      nodeListeners.remove( listener );
147
    }
148
  }
149
150
  public void removePreferenceChangeListener( 
151
    final IPreferenceChangeListener listener )
152
  {
153
    checkRemoved();
154
    getNodeCore().removePreferenceChangeListener( listener );
155
  }
156
157
  public String absolutePath() {
158
    if( absolutePath == null ) {
159
      if( parent == null ) {
160
        absolutePath = name;
161
      } else {
162
        String parentPath =  parent.absolutePath();
163
        absolutePath = parentPath.endsWith( PATH_SEPARATOR ) 
164
                     ? parentPath + name
165
                     : parentPath + PATH_SEPARATOR + name;
166
      }
167
    }
168
    return absolutePath;
169
  }
170
171
  public synchronized String[] childrenNames() throws BackingStoreException {
172
    checkRemoved();
173
    Set names = children.keySet();
174
    return ( String[] )names.toArray( new String[ names.size() ] );
175
  }
176
177
  public void clear() throws BackingStoreException {
178
    checkRemoved();
179
    String[] keys = internalGetKeys();
180
    for( int i = 0; i < keys.length; i++ ) {
181
      remove( keys[ i ] );
182
    }
183
  }
184
185
  public void flush() throws BackingStoreException {
186
    checkRemoved();
187
    // the current implementation persists everytime the preferences 
188
    // are modified, so there's nothing to do here
189
  }
190
191
  public String get( final String key, final String def ) {
192
    ParamCheck.notNull( key, "key" );
193
    checkRemoved();
194
    String result = internalGet( key );
195
    return result == null ? def : result;
196
  }
197
198
  public boolean getBoolean( final String key, final boolean def ) {
199
    ParamCheck.notNull( key, "key" );
200
    checkRemoved();
201
    String value = internalGet( key );
202
    return value == null ? def : Boolean.parseBoolean( value );
203
  }
204
205
  public byte[] getByteArray( final String key, final byte[] def ) {
206
    ParamCheck.notNull( key, "key" );
207
    checkRemoved();
208
    String value = internalGet( key );
209
    return value == null ? def : Base64.decode( value.getBytes() );
210
  }
211
212
  public double getDouble( final String key, final double def ) {
213
    ParamCheck.notNull( key, "key" );
214
    checkRemoved();
215
    String value = internalGet( key );
216
    double result = def;
217
    if( value != null ) {
218
      try {
219
        result = Double.parseDouble( value );
220
      } catch( NumberFormatException nfe ) {
221
        // returns def
222
      }
223
    }
224
    return result;
225
  }
226
227
  public float getFloat( final String key, final float def ) {
228
    ParamCheck.notNull( key, "key" );
229
    checkRemoved();
230
    String value = internalGet( key );
231
    float result = def;
232
    if( value != null ) {
233
      try {
234
        result = Float.parseFloat( value );
235
      } catch( NumberFormatException nfe ) {
236
        // returns def
237
      }
238
    }
239
    return result;
240
  }
241
242
  public int getInt( final String key, final int def ) {
243
    ParamCheck.notNull( key, "key" );
244
    checkRemoved();
245
    String value = internalGet( key );
246
    int result = def;
247
    if( value != null ) {
248
      try {
249
        result = Integer.parseInt( value );
250
      } catch( NumberFormatException nfe ) {
251
        // returns def
252
      }
253
    }
254
    return result;
255
  }
256
257
  public long getLong( final String key, final long def ) {
258
    ParamCheck.notNull( key, "key" );
259
    checkRemoved();
260
    String value = internalGet( key );
261
    long result = def;
262
    if( value != null ) {
263
      try {
264
        result = Long.parseLong( value );
265
      } catch( NumberFormatException nfe ) {
266
        // returns def
267
      }
268
    }
269
    return result;
270
  }
271
272
  public String[] keys() throws BackingStoreException {
273
    checkRemoved();
274
    return internalGetKeys();
275
  }
276
277
  public String name() {
278
    return name;
279
  }
280
281
  public synchronized boolean nodeExists( final String path ) 
282
    throws BackingStoreException 
283
  {
284
    boolean result;
285
    if( "".equals( path ) ) {
286
      result = !isRemoved;
287
    } else {
288
      checkRemoved();
289
      checkPath( path );
290
      if( path.startsWith( PATH_SEPARATOR ) ) { // "/absolute/path"
291
        result = findRoot().nodeExists( path.substring( 1 ) );
292
      } else if( path.indexOf( PATH_SEPARATOR ) > 0 ) { // "foo/bar/baz"
293
        int index = path.indexOf( PATH_SEPARATOR );
294
        String nodeName = path.substring( 0, index );
295
        String rest = path.substring( index + 1, path.length() ); 
296
        SessionPreferencesNode child = getChild( nodeName, false );
297
        result = child == null ? false : child.nodeExists( rest );
298
      } else { // "foo"
299
        result = children.containsKey( path );
300
      }
301
    }
302
    return result;
303
  }
304
305
  public Preferences parent() {
306
    checkRemoved();
307
    return parent;
308
  }
309
310
  public void put( final String key, final String newValue ) {
311
    ParamCheck.notNull( key, "key" );
312
    ParamCheck.notNull( newValue, "newValue" );
313
    checkRemoved();
314
    String oldValue = internalPut( key, newValue );
315
    if( !newValue.equals( oldValue ) ) {
316
      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
317
    }
318
  }
319
320
  public void putBoolean( final String key, final boolean value ) {
321
    ParamCheck.notNull( key, "key" );
322
    checkRemoved();
323
    String newValue = value ? TRUE : FALSE;
324
    String oldValue = internalPut( key, newValue );
325
    if( !newValue.equals( oldValue ) ) {
326
      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
327
    }
328
  }
329
330
  public void putByteArray( final String key, final byte[] value ) {
331
    ParamCheck.notNull( key, "key" );
332
    ParamCheck.notNull( value, "newValue" );
333
    checkRemoved();
334
    String newValue = new String( Base64.encode( value ) );
335
    String oldValue = internalPut( key, newValue );
336
    if( !newValue.equals( oldValue) ) {
337
      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
338
    }
339
  }
340
341
  public void putDouble( final String key, final double value ) {
342
    ParamCheck.notNull( key, "key" );
343
    checkRemoved();
344
    String newValue = String.valueOf( value );
345
    String oldValue = internalPut( key, newValue );
346
    if( !newValue.equals( oldValue ) ) {
347
      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
348
    }
349
  }
350
351
  public void putFloat( final String key, final float value ) {
352
    ParamCheck.notNull( key, "key" );
353
    checkRemoved();
354
    String newValue = String.valueOf( value );
355
    String oldValue = internalPut( key, newValue );
356
    if( !newValue.equals( oldValue ) ) {
357
      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
358
    }
359
  }
360
361
  public void putInt( final String key, final int value ) {
362
    ParamCheck.notNull( key, "key" );
363
    checkRemoved();
364
    String newValue = String.valueOf( value );
365
    String oldValue = internalPut( key, newValue );
366
    if( !newValue.equals( oldValue ) ) {
367
      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
368
    }
369
  }
370
371
  public void putLong( final String key, final long value ) {
372
    ParamCheck.notNull( key, "key" );
373
    checkRemoved();
374
    String newValue = String.valueOf( value );
375
    String oldValue = internalPut( key, newValue );
376
    if( !newValue.equals( oldValue ) ) {
377
      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
378
    }
379
  }
380
381
  public void remove( final String key ) {
382
    checkRemoved();
383
    String oldValue = internalGet( key );
384
    if( oldValue != null ) {
385
      internalPut( key, null );
386
      getNodeCore().firePreferenceEvent( key, oldValue, null );
387
    }
388
  }
389
390
  public void sync() throws BackingStoreException {
391
    checkRemoved();
392
    ISettingStore store = RWT.getSettingStore();
393
    String id = store.getId();
394
    try {
395
      store.loadById( id );
396
    } catch( SettingStoreException sse ) {
397
      throw new BackingStoreException( "Failed to sync() node", sse );
398
    }
399
  }
400
  
401
  public String toString() {
402
    return absolutePath() + "@" + hashCode();
403
  }
404
  
405
  //////////////////
406
  // helping methods
407
  
408
  private void checkName( final String nodeName ) {
409
    if( nodeName.indexOf( PATH_SEPARATOR ) != -1 ) {
410
      String unboundMsg = "Name ''{0}'' cannot contain or end with ''{1}''";
411
      String msg = NLS.bind( unboundMsg, nodeName, PATH_SEPARATOR );
412
      throw new IllegalArgumentException( msg );
413
    }
414
  }
415
416
  private void checkPath( final String path ) {
417
    if( path.indexOf( DOUBLE_PATH_SEPARATOR ) != -1 ) {
418
      String unboundMsg = "''{0}'' is not allowed in path ''{1}''";
419
      String msg = NLS.bind( unboundMsg, DOUBLE_PATH_SEPARATOR, path );
420
      throw new IllegalArgumentException( msg );
421
    }
422
    if( path.length() > 1 && path.endsWith( PATH_SEPARATOR ) ) {
423
      String unboundMsg = "path ''{0}'' cannot end with ''{1}''";
424
      String msg = NLS.bind( unboundMsg, path, PATH_SEPARATOR );
425
      throw new IllegalArgumentException( msg );
426
    }
427
  }
428
  
429
  private synchronized void checkRemoved() {
430
    if( isRemoved ) {
431
      String msg = "node ''{0}'' has been removed";
432
      throw new IllegalStateException( NLS.bind( msg, this.absolutePath() ) );
433
    }
434
  }
435
  
436
  private synchronized SessionPreferencesNode createChild( 
437
    final String childName )
438
  {
439
    SessionPreferencesNode result 
440
      = new SessionPreferencesNode( this, childName );
441
    children.put( childName, result );
442
    fireNodeEvent( result, true );
443
    return result;
444
  }
445
  
446
  private synchronized SessionPreferencesNode getChild( 
447
    final String childName, 
448
    final boolean doCreate ) 
449
  {
450
    SessionPreferencesNode result 
451
      = ( SessionPreferencesNode )children.get( childName );
452
    if( result == null && doCreate ) {
453
      result = createChild( childName );
454
    }
455
    return result;
456
  }
457
  
458
  private String[] internalGetKeys() {
459
    List result = new ArrayList();
460
461
    String prefix = absolutePath() + PATH_SEPARATOR;
462
    int prefixLength = prefix.length();
463
    
464
    Enumeration attrNames = RWT.getSettingStore().getAttributeNames();
465
    while( attrNames.hasMoreElements() ) {
466
      String attr = ( String )attrNames.nextElement();
467
      if( attr.startsWith( prefix ) ) {
468
        String key = attr.substring( prefixLength );
469
        result.add( key );
470
      }
471
    }
472
    return ( String[] )result.toArray( new String[ result.size() ] );
473
  }
474
475
  private Preferences findRoot() {
476
    Preferences result = this;
477
    while( result.parent() != null ) {
478
      result = result.parent();
479
    }
480
    return result;
481
  }
482
  
483
  private String internalGet( final String key ) {
484
    ISettingStore store = RWT.getSettingStore();
485
    String uniqueKey = absolutePath() + PATH_SEPARATOR + key;
486
    return store.getAttribute( uniqueKey );
487
  }
488
489
  private synchronized String internalPut( final String key, 
490
                                           final String value ) {
491
    String uniqueKey = absolutePath() + PATH_SEPARATOR + key;
492
    return getNodeCore().put( uniqueKey, value );
493
  }
494
  
495
  private void fireNodeEvent( final Preferences child,
496
                              final boolean wasAdded ) {
497
    final NodeChangeEvent event = new NodeChangeEvent( this, child );
498
    Object[] listeners = nodeListeners.getListeners();
499
    for( int i = 0; i < listeners.length; i++ ) {
500
      final INodeChangeListener listener 
501
        = ( INodeChangeListener )listeners[ i ];
502
      ISafeRunnable op = new ISafeRunnable() {
503
        public void handleException( final Throwable exception ) {
504
          // logged by SafeRunner
505
        }
506
        public void run() throws Exception {
507
          if( wasAdded ) {
508
            listener.added( event );
509
          } else {
510
            listener.removed( event );
511
          }
512
        }
513
      };
514
      SafeRunner.run( op );
515
    }
516
  }
517
  
518
  private SessionPreferenceNodeCore getNodeCore() {
519
    SessionPreferenceNodeCore result;
520
    final String key = absolutePath();
521
    Object object = RWT.getSessionStore().getAttribute( key );
522
    if( object instanceof SessionPreferenceNodeCore ) {
523
      result = ( SessionPreferenceNodeCore )object;
524
    } else {
525
      result = new SessionPreferenceNodeCore( this );
526
      RWT.getSessionStore().setAttribute( key, result );
527
    }
528
    return result;
529
  }
530
  
531
}

Return to bug 220477