Skip to content

Commit cae93a3

Browse files
committed
Ensure listeners are properly removed from the ScopedPreferenceStore
Currently the ScopedPreferenceStore adds two kind of listeners but only removes one. Even worse it determines the object from removing listeners by lookup the target again, so in some cases it is assumed that the listener was already removed. This now adds a composite listener that handles both cases and remember the objects where listener where added. These listeners are then removed on disposal.
1 parent 43cc4a0 commit cae93a3

File tree

1 file changed

+51
-56
lines changed

1 file changed

+51
-56
lines changed

bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/preferences/ScopedPreferenceStore.java

Lines changed: 51 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
import org.eclipse.core.commands.common.EventManager;
2121
import org.eclipse.core.runtime.Assert;
2222
import org.eclipse.core.runtime.Platform;
23-
import org.eclipse.core.runtime.Plugin;
2423
import org.eclipse.core.runtime.SafeRunner;
2524
import org.eclipse.core.runtime.preferences.DefaultScope;
2625
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
2726
import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
2827
import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
28+
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
2929
import org.eclipse.core.runtime.preferences.IScopeContext;
3030
import org.eclipse.jface.preference.IPersistentPreferenceStore;
3131
import org.eclipse.jface.preference.IPreferenceStore;
@@ -75,7 +75,7 @@ public class ScopedPreferenceStore extends EventManager implements IPreferenceSt
7575
* The listener on the IEclipsePreferences. This is used to forward updates to
7676
* the property change listeners on the preference store.
7777
*/
78-
IEclipsePreferences.IPreferenceChangeListener preferencesListener;
78+
private EclipsePreferencesListener preferencesListener;
7979

8080
/**
8181
* The default context is the context where getDefault and setDefault methods
@@ -123,54 +123,14 @@ public ScopedPreferenceStore(IScopeContext context, String qualifier) {
123123
storeContext = context;
124124
this.nodeQualifier = qualifier;
125125
this.defaultQualifier = qualifier;
126-
127-
((IEclipsePreferences) getStorePreferences().parent()).addNodeChangeListener(getNodeChangeListener());
128-
}
129-
130-
/**
131-
* Return a node change listener that adds a removes the receiver when nodes
132-
* change.
133-
*
134-
* @return INodeChangeListener
135-
*/
136-
private INodeChangeListener getNodeChangeListener() {
137-
return new IEclipsePreferences.INodeChangeListener() {
138-
@Override
139-
public void added(NodeChangeEvent event) {
140-
if (nodeQualifier.equals(event.getChild().name()) && isListenerAttached()) {
141-
getStorePreferences().addPreferenceChangeListener(preferencesListener);
142-
}
143-
}
144-
145-
@Override
146-
public void removed(NodeChangeEvent event) {
147-
// Do nothing as there are no events from removed node
148-
}
149-
};
150126
}
151127

152128
/**
153129
* Initialize the preferences listener.
154130
*/
155131
private void initializePreferencesListener() {
156132
if (preferencesListener == null) {
157-
preferencesListener = event -> {
158-
159-
if (silentRunning) {
160-
return;
161-
}
162-
163-
Object oldValue = event.getOldValue();
164-
Object newValue = event.getNewValue();
165-
String key = event.getKey();
166-
if (newValue == null) {
167-
newValue = getDefault(key, oldValue);
168-
} else if (oldValue == null) {
169-
oldValue = getDefault(key, newValue);
170-
}
171-
firePropertyChangeEvent(event.getKey(), oldValue, newValue);
172-
};
173-
getStorePreferences().addPreferenceChangeListener(preferencesListener);
133+
preferencesListener = new EclipsePreferencesListener(this);
174134
}
175135

176136
}
@@ -646,26 +606,61 @@ public void save() throws IOException {
646606
* Dispose the receiver.
647607
*/
648608
private void disposePreferenceStoreListener() {
609+
if (preferencesListener != null) {
610+
preferencesListener.dispose();
611+
preferencesListener = null;
612+
}
613+
}
649614

650-
IEclipsePreferences root = (IEclipsePreferences) Platform.getPreferencesService().getRootNode()
651-
.node(Plugin.PLUGIN_PREFERENCE_SCOPE);
652-
try {
653-
if (!(root.nodeExists(nodeQualifier))) {
615+
private static final class EclipsePreferencesListener
616+
implements IEclipsePreferences.IPreferenceChangeListener, INodeChangeListener {
617+
618+
private final ScopedPreferenceStore store;
619+
private final IEclipsePreferences preferences;
620+
private final IEclipsePreferences parent;
621+
622+
EclipsePreferencesListener(ScopedPreferenceStore store) {
623+
this.store = store;
624+
preferences = store.getStorePreferences();
625+
preferences.addPreferenceChangeListener(this);
626+
parent = (IEclipsePreferences) preferences.parent();
627+
parent.addNodeChangeListener(this);
628+
}
629+
630+
void dispose() {
631+
parent.removeNodeChangeListener(this);
632+
preferences.removePreferenceChangeListener(this);
633+
}
634+
635+
@Override
636+
public void preferenceChange(PreferenceChangeEvent event) {
637+
if (store.silentRunning) {
654638
return;
655639
}
656-
} catch (BackingStoreException e) {
657-
return;// No need to report here as the node won't have the
658-
// listener
640+
641+
Object oldValue = event.getOldValue();
642+
Object newValue = event.getNewValue();
643+
String key = event.getKey();
644+
if (newValue == null) {
645+
newValue = store.getDefault(key, oldValue);
646+
} else if (oldValue == null) {
647+
oldValue = store.getDefault(key, newValue);
648+
}
649+
store.firePropertyChangeEvent(event.getKey(), oldValue, newValue);
659650
}
660651

661-
IEclipsePreferences preferences = getStorePreferences();
662-
if (preferences == null) {
663-
return;
652+
@Override
653+
public void added(NodeChangeEvent event) {
654+
if (store.nodeQualifier.equals(event.getChild().name())) {
655+
store.getStorePreferences().addPreferenceChangeListener(this);
656+
}
664657
}
665-
if (preferencesListener != null) {
666-
preferences.removePreferenceChangeListener(preferencesListener);
667-
preferencesListener = null;
658+
659+
@Override
660+
public void removed(NodeChangeEvent event) {
661+
// Do nothing as there are no events from removed node
668662
}
663+
669664
}
670665

671666
}

0 commit comments

Comments
 (0)