9.2. Processing Change EventsThe POST_CHANGE resource change event is expressed not as a single change, but as a hierarchy describing one or more changes that have occurred. Events are batched in this manner for efficiency; reporting each change as it occurs to every interested object would dramatically slow down the system and reduce responsiveness to the user. To see this hierarchy of changes, add the following code to the FavoritesManager. public void resourceChanged(IResourceChangeEvent e) { System.out.println( "FavoritesManager - resource change event"); try { event.getDelta().accept(new IResourceDeltaVisitor() { public boolean visit(IResourceDelta delta) throws CoreException { StringBuffer buf = new StringBuffer(80); switch (delta.getKind()) { case IResourceDelta.ADDED: buf.append("ADDED"); break; case IResourceDelta.REMOVED: buf.append("REMOVED"); break; case IResourceDelta.CHANGED: buf.append("CHANGED"); break; default: buf.append("["); buf.append(delta.getKind()); buf.append("]"); break; } buf.append(" "); buf.append(delta.getResource()); System.out.println(buf); return true; } }); } catch (CoreException ex) { FavoritesLog.logError(ex); } } The preceding code will generate a textual representation of the hierarchical structure describing the resource changes in the system. To see this code in action, launch the Runtime Workbench (see Section 2.6, Debugging the Product, on page 88) and open the Favorites view. In the Runtime Workbench, create a simple project and then add folders and files as shown here (see Figure 9-1). Figure 9-1. Navigator view.
During the creation process, you will see output generated to the Console view describing the resource change events that were sent by Eclipse. The FavoritesManager is specifically interested in the deletion of resources, and when you delete these two files, you'll see the following in the Console view: FavoritesManager - resource change event CHANGED R/ CHANGED P/Test CHANGED F/Test/folder1 CHANGED F/Test/folder1/folder2 REMOVED L/Test/folder1/folder2/file1.txt REMOVED L/Test/folder1/folder2/file2.txt The next step is to modify the FavoritesManager methods to do something with this information. The modifications will enable the FavoritesManager to remove Favorites items that reference resources that have been removed from the system. public void resourceChanged(IResourceChangeEvent e) { Collection itemsToRemove = new HashSet(); try { event.getDelta().accept(new IResourceDeltaVisitor() { public boolean visit(IResourceDelta delta) throws CoreException { if (delta.getKind() == IResourceDelta.REMOVED) { IFavoriteItem item = existingFavoriteFor(delta.getResource()); if (item != null) itemsToRemove.add(item); } return true; } }); } catch (CoreException ex) { FavoritesLog.logError(ex); } if (itemsToRemove.size() > 0) removeFavorites( (IFavoriteItem[]) itemsToRemove.toArray( new IFavoriteItem[itemsToRemove.size()])); } When the preceding code is in place, launch the Runtime Workbench to test this modification by creating a file in a project, adding that file as a Favorites item to the Favorites view, and then deleting the file from the project. The file is removed, but the Favorites item is not removed as it should be. Looking in the .log file (see Section 3.6.2, The Error Log view, on page 124) reveals the following exception: org.eclipse.swt.SWTException: Invalid thread access This indicates that an SWT component, such as the table in the Favorites view, is being accessed from a thread other than the UI thread (see Section 4.2.5.1, Display, on page 140 for more about Display.getDefault() and the UI thread). To alleviate this problem, modify the FavoritesViewContentProvider favoritesChanged() method as shown below to ensure that the viewer is accessed on the UI thread. public void favoritesChanged(final FavoritesManagerEvent event) { // If this is the UI thread, then make the change. if (Display.getCurrent() != null) { updateViewer(event); return; } // otherwise, redirect to execute on the UI thread. Display.getDefault().asyncExec(new Runnable() { public void run() { updateViewer(event); } }); } private void updateViewer(final FavoritesManagerEvent event) { // Use the setRedraw method to reduce flicker // when adding or removing multiple items in a table. viewer.getTable().setRedraw(false); try { viewer.remove(event.getItemsRemoved()); viewer.add(event.getItemsAdded()); } finally { viewer.getTable().setRedraw(true); } } |