Community
Participate
Working Groups
I have a class called ProjectNavigatorContentProvider which extends org.eclipse.ui.model.WorkbenchContentProvider. In my constructor I register for POST_AUTO_BUILD using ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_AUTO_BUILD); However, when I step into org.eclipse.core.internal.events.NotificationManager.broadcastChanges(ElementTre e, int, booleab, boolean), listeners (the ResourceChangeListenerList) only had my object registered for mask = 1, i.e. for POST_CHANGED events. After putting a breakpoint in org.eclipse.core.internal.resources.Workspace.addResourceChangeListener(IResourc eChangeListener, int) and watching what was happening at start-up, I realised that some time after my ProjectNavigatorContentProvider constructor was registering for POST_AUTO_BUILD, org.eclipse.ui.model.WorkbenchContentProvider, my super-class, was registering for POST_CHANGED, and that somehow knocked out my registration for POST_AUTO_BUILD. My work around was to register for POST_AUTO_BUILD again in my Object[] getElements(Object arg0), which is called some time after org.eclipse.ui.model.WorkbenchContentProvider, did its registration but before the user sees my navigator. I have yet to determine if my registration has in turn knocked out the registration of my super class, and if that has any negative affects. It doesn't seem to so far.
Listeners are added/changed/removed from the list based on identity. Are you sure that your listener is being removed/replaced? A good place to step into in debug mode would be ResourceChangeListenerList.add(). Here is a little test that I wrote which work ok. Is there something obvious which I am overlooking? public void testMulti() { class Listener1 implements IResourceChangeListener { public boolean done = false; public void resourceChanged(IResourceChangeEvent event) { assertEquals("1.0", IResourceChangeEvent.POST_CHANGE, event.getType()); done = true; } } class Listener2 extends Listener1 implements IResourceChangeListener { public void resourceChanged(IResourceChangeEvent event) { assertEquals("2.0", IResourceChangeEvent.POST_AUTO_BUILD, event.getType()); done = true; } } Listener1 listener1 = new Listener1(); Listener2 listener2 = new Listener2(); getWorkspace().addResourceChangeListener(listener1, IResourceChangeEvent.POST_CHANGE); getWorkspace().addResourceChangeListener(listener2, IResourceChangeEvent.POST_AUTO_BUILD); try { project1.touch(getMonitor()); } catch (CoreException e) { handleCoreException(e); } assertTrue("3.0", listener1.done); assertTrue("3.1", listener2.done); getWorkspace().removeResourceChangeListener(listener1); getWorkspace().removeResourceChangeListener(listener2); }
your re-creation is a off on key points, but rather than address your example, let me point you to the exact place in the Eclipse code that is causing the problem. I just ran through one execution of my code in the debugger, and here is exactly what is happening: my class, an instace of ProjectNavigatorContentProvider whose ID = 87 on this run of the code, added itself with eventMask = 16 (i.e. POST_AUTO_BUILD). My class sub-classses org.eclipse.ui.model.WorkbenchContentProvider. Now, here is a snippet of code that appears in WorkbenchContentProvider (I cut out most of the method - just showing the relevant part): public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { if (newWorkspace != null) { newWorkspace.addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); } } } So, inside its inputChanged method, WorkbenchContentProvider registers itself with eventmask = 1. Since my sub-class, ProjectNavigatorContentProvider, doesn't have its own inputChanged method, the method in the super class is executed, and the debugger shows my instace, with ID = 87, registering itself with eventMask = 1 (i.e. POST_CHANGE), and I am no longer registered for POST_AUTO_BUILD (eventMask = 16). In short, the behavior of the code inside org.eclipse.core.internal.events.ResourceChangeListenerList.add(IResourceChangeL istener, int) is to replace the old mask of the given listener with the new one, so despite the fact that in my constructor I am registering with eventMask = 16, every time inputChanged is called, 1 *replaces* 16 instead of 1 being *added to* 16. Is that clearer?
Look at the javadoc for IWorkspace.addResourceChangeListener, here is a snippet from the first paragraph: * After completion of this method, the given listener will be * registered for exactly the specified events. If they were * previously registered for other events, they will be deregistered. So we're behaving as spec'ed. I suggest you override the inputChanged method from the superclass so that it doesn't override your previous listener registration.
John - I alrady made the change - my method is quite simple: /** * @see IContentProvider#inputChanged(Viewer, Object, Object) */ public void inputChanged(Viewer arg0, Object arg1, Object arg2) { super.inputChanged(arg0, arg1, arg2); ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_AUTO_BUILD); } the real queston is - is that spec the most logical choice, or would adding the new eventMask to the old one be better? I agree that the knee-jerk reaction is that the spec is good, but when you consider the super/sub class example, one wonders if it would make more sense to add the new to the old instead of deleting the old....
The problems in changing things are: - when you want to change the events that you are listening for you would have to de-register your listener and then re-register - changing the API is difficult at this point in time because there are a lot of people out there depending on the behaviour as documented
OK - just a thought for consideration in version 3, I guess. Minimally, you could add a new call - some like "changeListener" instead of "addListener" - which would allow people to update the eventMask instead of blowing it away.
Closing for now. Will consider adding new API for merging resource change listener events post 2.0.
Renamed from: super-class IResourceChangeListener registration kills sub-class registration Reopening for consideration.
Closing bugs we don't plan to fix.