Previous Page
Next Page

7.2. View Part

The code defining a view's behavior is found in a class implementing the org.eclipse.ui.IViewPart interface, typically by subclassing the org.eclipse.ui.part.ViewPart abstract class.

Section 2.3.3, The Favorites view, on page 78 reviewed the Favorites view in its simplest form.

7.2.1. View methods

IViewPart and its supertypes define the following methods.

createPartControl(Composite) This method is required because it creates the controls comprising the view. Typically, this method simply calls more finely grained methods such as createTable, createSortActions, createFilters, and so on (see the next section).

dispose() Cleans up any platform resources, such as images, clipboard, and so on, that were created by this class. This follows the if you create it, you destroy it theme that runs throughout Eclipse.

getAdapter(Class) Returns the adapter associated with the specified interface so that the view can participate in various workbench actions. Adapters returned by views include IShowInSource, IShowInTarget, and IContributedContentsView, among others (see Section 20.3, Adapters, on page 714).

saveState(IMemento) Saves the local state of this view, such as the current selection, current sorting, current filter, and so on (see Section 7.5.1, Saving local view information, on page 308).

setFocus() This method is required because it sets focus to the appropriate control within the view (see the next section).

7.2.2. View controls

Views can contain any type and number of controls, but typically, a view such as the Favorites view contains a single table or tree control. The Favorites view could use the SWT table widget directly (org.eclipse.swt.widgets.Table see Section 4.2.6.6, Table, on page 154); however, the higher-level JFace table viewer (org.eclipse.jface.viewers.TableViewersee Section 5.1.7, Table Viewer class, on page 195) wraps the SWT table widget and is easier to use. It handles much of the underlying grunt work, allowing you to add, select, and remove model objects directly rather than dealing with the underlying instances of TableItem.

With this in mind, let's start by adding three new fields to the FavoritesView class:

private TableColumn typeColumn;
private TableColumn nameColumn;
private TableColumn locationColumn;

You should continue to enhance the createPartControl() method that was generated as part of building the Favorites plug-in (see Section 2.3.3, The Favorites view, on page 78) so that the table has three columns. The SWT.FULL_SELECTION style bit causes the entire row to be highlighted when the user makes a selection.

viewer = new TableViewer(parent,
   SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION);
final Table table = viewer.getTable();

typeColumn = new TableColumn(table, SWT.LEFT);
typeColumn.setText("");
typeColumn.setWidth(18);

nameColumn = new TableColumn(table, SWT.LEFT);
nameColumn.setText("Name");
nameColumn.setWidth(200);

locationColumn = new TableColumn(table, SWT.LEFT);
locationColumn.setText("Location");
locationColumn.setWidth(450);

table.setHeaderVisible(true);
table.setLinesVisible(false);

viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setInput(getViewSite());

Later, when you want to get more involved, auto-size the columns in the table (see Section 7.8, Auto-sizing Table Columns, on page 316).

7.2.3. View model

A view can have its own internal model such as the Favorites view, it can use existing model objects such as an IResource and its subtypes, or it may not have a model at all. In this case, create:

  • IFavoriteItem An interface used to abstract the differences between different types of Favorites objects.

  • FavoritesManager Holds Favorites model objects.

  • FavoriteResource A class adapting a resource to the IFavoriteItem interface.

  • FavoriteJavaElement A class adapting a Java element to the IFavoriteItem interface.

The IFavoriteItem interface hides the differences between various types of Favorites objects. This enables the FavoritesManager and FavoritesView to deal with all Favorites items in a uniform manner. The naming convention followed, which is used in many places throughout Eclipse, is to prefix an interface with a capital "I" so that the interface name is IFavoriteItem rather than FavoriteItem, as one would expect (see Section 7.4.2, Adaptable objects, on page 306 for more on IAdaptable).

package com.qualityeclipse.favorites.model;

public interface IFavoriteItem
   extends IAdaptable
{
   String getName();
   void setName(String newName);
   String getLocation();
   boolean isFavoriteFor(Object obj);
   FavoriteItemType getType();
   String getInfo();

   static IFavoriteItem[] NONE = new IFavoriteItem[] {};
}

Later, Favorites items will be serialized so that they can be placed on the clipboard (see Section 7.3.7, Clipboard actions, on page 290) and saved to disk between Eclipse workbench sessions (see Section 7.5.2, Saving global view information, on page 311). To this end, the getInfo() method for each item must return enough state so that the item can be correctly reconstructed later.

The FavoriteItemType object returned by the getType() method is a type-safe enumeration that can be used for sorting and storing Favorites objects. It has a human-readable name associated with it for display purposes. Introducing the FavoriteItemType rather than a simple String or int allows the sort order to be separated from the human-readable name associated with a type of Favorites object.

package com.qualityeclipse.favorites.model;

import ...

public abstract class FavoriteItemType
   implements Comparable
{
   private static final ISharedImages PLATFORM_IMAGES =
      PlatformUI.getWorkbench().getSharedImages();

Next, you need to add a constructor plus some fields and accessors to the FavoriteItemType used by the Favorites view to sort and display Favorites items. Since the workbench already provides images for various types of resources, the FavoriteItemType object simply returns the appropriate shared image. To return custom images for other types of Favorites objects, you could cache those images during the life of the plug-in and dispose of them when the plug-in is shut down (see Section 7.7, Image Caching, on page 315).

private final String id;
private final String printName;
private final int ordinal;

private FavoriteItemType(String id, String name, int position) {
   this.id = id;
   this.ordinal = position;
   this.printName = name;
}

public String getId() {
   return id;
}

public String getName() {
   return printName;
}

public abstract Image getImage();
public abstract IFavoriteItem newFavorite(Object obj);
public abstract IFavoriteItem loadFavorite(String info);

The FavoriteItemType implements the Comparable interface, for sorting purposes, so must implement the compareTo method.

public int compareTo(Object arg) {
   return this.ordinal - ((FavoriteItemType) arg).ordinal;
}

Next, add public static fields for each of the known types of Favorites. For now, these instances are hard-coded; however, in the future, these instances will be defined by an extension point so that others can introduce new types of Favorites (see Section 17.3, Code Behind an Extension Point, on page 607). These new public static fields depend on the org.eclipse.core.resources, org.eclipse.ui.ide, and org.eclipse.jdt.core plug-ins, so use the Dependencies page of the plug-in manifest editor (see Figure 2-10 on page 73) to add these required plug-ins, and then save the changes.

public static final FavoriteItemType UNKNOWN
   = new FavoriteItemType("Unknown", "Unknown", 0)
{
   public Image getImage() {
      return null;
    }

   public IFavoriteItem newFavorite(Object obj) {
      return null;
    }

    public IFavoriteItem loadFavorite(String info) {
       return null;
    }
};

public static final FavoriteItemType WORKBENCH_FILE
   = new FavoriteItemType("WBFile", "Workbench File", 1)
{
   public Image getImage() {
      return PLATFORM_IMAGES
            .getImage(org.eclipse.ui.ISharedImages.IMG_OBJ_FILE);
   }

   public IFavoriteItem newFavorite(Object obj) {
      if (!(obj instanceof IFile))
         return null;
      return new FavoriteResource(this, (IFile) obj);
   }

   public IFavoriteItem loadFavorite(String info) {
      return FavoriteResource.loadFavorite(this, info);
   }
};

public static final FavoriteItemType WORKBENCH_FOLDER
   = new FavoriteItemType("WBFolder", "Workbench Folder", 2)
{
   public Image getImage() {
      return PLATFORM_IMAGES
            .getImage(org.eclipse.ui.ISharedImages.IMG_OBJ_FOLDER);
   }

   public IFavoriteItem newFavorite(Object obj) {
      if (!(obj instanceof IFolder))
         return null;
      return new FavoriteResource(this, (IFolder) obj);
   }

   public IFavoriteItem loadFavorite(String info) {
      return FavoriteResource.loadFavorite(this, info);
   }
};

... more of the same ...

Finally, create a static array containing all known types and a getTypes() method that will return all known types.

private static final FavoriteItemType[] TYPES = {
   UNKNOWN, WORKBENCH_FILE, WORKBENCH_FOLDER, WORKBENCH_PROJECT,
   JAVA_PROJECT, JAVA_PACKAGE_ROOT, JAVA_PACKAGE,
   JAVA_CLASS_FILE, JAVA_COMP_UNIT, JAVA_INTERFACE, JAVA_CLASS};

public static FavoriteItemType[] getTypes() {
   return TYPES;
}

All Favorites views should show the same collection of Favorites objects, so the FavoritesManager is a singleton responsible for maintaining this global collection.

package com.qualityeclipse.favorites.model;

import ...

public class FavoritesManager {
   private static FavoritesManager manager;
   private Collection favorites;

   private FavoritesManager() {}

   public static FavoritesManager getManager() {
      if (manager == null)
         manager = new FavoritesManager();
      return manager;
   }

   public IFavoriteItem[] getFavorites() {
      if (favorites == null)
         loadFavorites();
      return (IFavoriteItem[]) favorites.toArray(
         new IFavoriteItem[favorites.size()]);
   }

   private void loadFavorites() {
      // temporary implementation
      // to prepopulate list with projects
      IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
            .getProjects();
      favorites = new HashSet(projects.length);
      for (int i = 0; i   projects.length; i++)
         favorites.add(new FavoriteResource(
               FavoriteItemType.WORKBENCH_PROJECT, projects[i]));
   }

The manager needs to look up existing Favorites objects and create new ones.

public IFavoriteItem newFavoriteFor(Object obj) {
   FavoriteItemType[] types = FavoriteItemType.getTypes();
   for (int i = 0; i < types.length; i++) {
      IFavoriteItem item = types[i].newFavorite(obj);
      if (item != null)
         return item;
   }
   return null;
}

public IFavoriteItem[] newFavoritesFor(Iterator iter) {
   if (iter == null)
      return IFavoriteItem.NONE;
   Collection items = new HashSet(20);
   while (iter.hasNext()) {
      IFavoriteItem item = newFavoriteFor((Object) iter.next());
      if (item != null)
         items.add(item);
   }
   return (IFavoriteItem[]) items.toArray(new IFavoriteItem[items
         .size()]);
}

public IFavoriteItem[] newFavoritesFor(Object[] objects) {
   if (objects == null)
      return IFavoriteItem.NONE;
   return newFavoritesFor(Arrays.asList(objects).iterator());
}

public IFavoriteItem existingFavoriteFor(Object obj) {
   if (obj == null)
      return null;
   Iterator iter = favorites.iterator();
   while (iter.hasNext()) {
      IFavoriteItem item = (IFavoriteItem) iter.next();
       if (item.isFavoriteFor(obj))
          return item;
   }
   return null;
}

public IFavoriteItem[] existingFavoritesFor(Iterator iter) {
   List result = new ArrayList(10);
   while (iter.hasNext()) {
      IFavoriteItem item = existingFavoriteFor(iter.next());

      if (item != null)
         result.add(item);
   }
   return (IFavoriteItem[]) result
         .toArray(new IFavoriteItem[result.size()]);
}

public void addFavorites(IFavoriteItem[] items) {
   if (favorites == null)
      loadFavorites();
   if (favorites.addAll(Arrays.asList(items)))
      fireFavoritesChanged(items, IFavoriteItem.NONE);
}

public void removeFavorites(IFavoriteItem[] items) {
   if (favorites == null)
       loadFavorites();
   if (favorites.removeAll(Arrays.asList(items)))
      fireFavoritesChanged(IFavoriteItem.NONE, items);
}

Since more than one view will be accessing the information, the manager must be able to notify registered listeners when the information changes. The FavoritesManager will only be accessed from the UI thread, so you do not need to worry about thread safety (see Section 4.2.5.1, Display, on page 140 for more about the UI thread).

private List listeners = new ArrayList();

public void addFavoritesManagerListener(
   FavoritesManagerListener listener
) {
   if (!listeners.contains(listener))
      listeners.add(listener);
}

public void removeFavoritesManagerListener(
   FavoritesManagerListener listener
) {
   listeners.remove(listener);
}

private void fireFavoritesChanged(
   IFavoriteItem[] itemsAdded, IFavoriteItem[] itemsRemoved
) {
   FavoritesManagerEvent event = new FavoritesManagerEvent(
      this, itemsAdded, itemsRemoved);
   for (Iterator iter = listeners.iterator(); iter.hasNext();)
      ((FavoritesManagerListener) iter.next())
            .favoritesChanged(event);
}

The FavoritesManager uses the FavoritesManagerListener and FavoritesManagerEvent classes to notify interested objects of changes.

package com.qualityeclipse.favorites.model;

public interface FavoritesManagerListener
{
   public void favoritesChanged(FavoritesManagerEvent event);
}

package com.qualityeclipse.favorites.model;

import java.util.EventObject;

public class FavoritesManagerEvent extends EventObject
{
   private static final long serialVersionUID = 3697053173951102953L;

   private final IFavoriteItem[] added;
   private final IFavoriteItem[] removed;

   public FavoritesManagerEvent(
      FavoritesManager source,
      IFavoriteItem[] itemsAdded, IFavoriteItem[] itemsRemoved
   ) {
      super(source);
      added = itemsAdded;
      removed = itemsRemoved;
   }

   public IFavoriteItem[] getItemsAdded() {
      return added;
   }

   public IFavoriteItem[] getItemsRemoved() {
      return removed;
   }
}

In the future, the FavoritesManager will be enhanced to allow the list to persist between Eclipse sessions (see Section 7.5.2, Saving global view information, on page 311), but for now, the list will be initialized with current workspace projects every time Eclipse starts. In addition, the current implementation will be extended in future chapters to include Favorites types added by other plug-ins (see Section 17.3, Code Behind an Extension Point, on page 607).

The FavoriteResource wraps an IResource object, adapting it to the IFavoriteItem interface.

package com.qualityeclipse.favorites.model;

import ...

public class FavoriteResource
   implements IFavoriteItem
{
   private FavoriteItemType type;
   private IResource resource;
   private String name;

   FavoriteResource(FavoriteItemType type, IResource resource) {
      this.type = type;
      this.resource = resource;
   }

   public static FavoriteResource loadFavorite(
      FavoriteItemType type, String info)
   {
      IResource res = ResourcesPlugin.getWorkspace().getRoot()
            .findMember(new Path(info));
      if (res == null)
         return null;
      return new FavoriteResource(type, res);
   }
   public String getName() {
      if (name == null)
         name = resource.getName();
      return name;
   }

   public void setName(String newName) {
      name = newName;
   }

   public String getLocation() {
      IPath path = resource.getLocation().removeLastSegments(1);
      if (path.segmentCount() == 0)
         return "";
      return path.toString();
   }

   public boolean isFavoriteFor(Object obj) {
      return resource.equals(obj);
   }

   public FavoriteItemType getType() {
      return type;
   }

   public boolean equals(Object obj) {
      return this == obj || (
         (obj instanceof FavoriteResource)
         && resource.equals(((FavoriteResource) obj).resource));
   }

   public int hashCode() {
      return resource.hashCode();
   }

   public Object getAdapter(Class adapter) {
      if (adapter.isInstance(resource))
         return resource;
      return Platform.getAdapterManager().getAdapter(this, adapter);
   }

   public String getInfo() {
      return resource.getFullPath().toString();
   }
}

Similar to the FavoriteResource, the FavoriteJavaElement adapts an IJavaElement object to the IFavoriteItem interface. Before creating this class, you'll need to add the org.eclipse.jdt.ui plug-in to the Favorites plug-in's manifest (see Figure 7-5).

Figure 7-5. Plug-in manifest editor Dependencies page.


If the project is a plug-in project (see Section 2.2, Creating a Plug-in Project, on page 66), modifying the plug-in's manifest causes the project's Java build path to be automatically updated.

package com.qualityeclipse.favorites.model;

import ...

public class FavoriteJavaElement
   implements IFavoriteItem
{
   private FavoriteItemType type;
   private IJavaElement element;
   private String name;

   public FavoriteJavaElement(
      FavoriteItemType type, IJavaElement element
   ) {
      this.type = type;
      this.element = element;
   }

   public static FavoriteJavaElement loadFavorite(
      FavoriteItemType type, String info
   ) {
      IResource res = ResourcesPlugin.getWorkspace().getRoot()
            .findMember(new Path(info));
      if (res == null)
         return null;
      IJavaElement elem = JavaCore.create(res);
      if (elem == null)
         return null;
      return new FavoriteJavaElement(type, elem);
   }
   public String getName() {
      if (name == null)
         name = element.getElementName();
      return name;
   }

   public void setName(String newName) {
      name = newName;
   }

   public String getLocation() {
      try {
         IResource res = element.getUnderlyingResource();
         if (res != null) {
            IPath path = res.getLocation().removeLastSegments(1);
            if (path.segmentCount() == 0)
               return "";
            return path.toString();
         }
      }
      catch (JavaModelException e) {
         FavoritesLog.logError(e);
      }
      return "";
   }

   public boolean isFavoriteFor(Object obj) {
      return element.equals(obj);
   }

   public FavoriteItemType getType() {
      return type;
   }

   public boolean equals(Object obj) {
      return this == obj || (
         (obj instanceof FavoriteJavaElement)
         && element.equals(((FavoriteJavaElement) obj).element));
   }

   public int hashCode() {
      return element.hashCode();
   }

   public Object getAdapter(Class adapter) {
      if (adapter.isInstance(element))
         return element;
      IResource resource = element.getResource();
      if (adapter.isInstance(resource))
         return resource;
      return Platform.getAdapterManager().getAdapter(this, adapter);
   }

   public String getInfo() {
      try {
         return element.getUnderlyingResource().getFullPath()
               .toString();
      }
      catch (JavaModelException e) {
         FavoritesLog.logError(e);
         return null;
      }
   }
}

7.2.4. Content provider

When the model objects have been created, they need to be linked into the view. A content provider is responsible for extracting objects from an input objectin this case, the FavoritesManagerand handing them to the table viewer for displaying, one object in each row. Although the IStructuredContentProvider does not specify this, the content provider has also been made responsible for updating the viewer when the content of FavoritesManager changes.

After extracting the content provider that was automatically generated as part of the FavoritesView class (see Section 2.3.2, The Plug-in class, on page 77) and reworking it to use the newly created FavoritesManager, it looks something like the following code.

package com.qualityeclipse.favorites.views;

import ...

class FavoritesViewContentProvider
   implements IStructuredContentProvider, FavoritesManagerListener
{
   private TableViewer viewer;
   private FavoritesManager manager;

   public void inputChanged(
      Viewer viewer, Object oldInput, Object newInput
   ) {
      this.viewer = (TableViewer) viewer;
      if (manager != null)
         manager.removeFavoritesManagerListener(this);
      manager = (FavoritesManager) newInput;
      if (manager != null)
         manager.addFavoritesManagerListener(this);
    }

    public void dispose() {
    }

   public Object[] getElements(Object parent) {
      return manager.getFavorites();
   }

   public void favoritesChanged(FavoritesManagerEvent event) {
      viewer.getTable().setRedraw(false);
      try {
         viewer.remove(event.getItemsRemoved());
         viewer.add(event.getItemsAdded());
      }
      finally {
         viewer.getTable().setRedraw(true);
      }
   }
}

Tip

The preceding method uses the setRedraw method to reduce the flicker when adding and removing multiple items from the viewer.


Extracting and modifying the content provider means that the calls to setContentProvider and setInput in the createPartControl method have changed as follows:

viewer.setContentProvider(new FavoritesViewContentProvider());
viewer.setInput(FavoritesManager.getManager());

7.2.5. Label provider

The label provider takes a table row object returned by the content provider and extracts the value to be displayed in a column. After refactoring the FavoritesView.ViewLabelProvider inner class (see Section 2.3.3, The Favorites view, on page 78) into a top-level class and reworking it to extract values from the newly created model object, it looks something like the following code.

package com.qualityeclipse.favorites.views;

import ...

class FavoritesViewLabelProvider extends LabelProvider
   implements ITableLabelProvider
{
   public String getColumnText(Object obj, int index) {
      switch (index) {
      case 0: // Type column
         return "";

      case 1: // Name column
         if (obj instanceof IFavoriteItem)
            return ((IFavoriteItem) obj).getName();
         if (obj != null)
            return obj.toString();
         return "";
      case 2: // Location column
         if (obj instanceof IFavoriteItem)
            return ((IFavoriteItem) obj).getLocation();
         return "";
      default:
         return "";
     }
   }

   public Image getColumnImage(Object obj, int index) {
      if ((index == 0) && (obj instanceof IFavoriteItem))
         return ((IFavoriteItem) obj).getType().getImage();
      return null;
   }
}

Tip

If you are displaying workbench-related objects, WorkbenchLabelProvider and WorkbenchPartLabelProvider contain behavior for determining text and images for workbench resources implementing the IWorkbenchAdapter interface (see Section 20.3.4, IWorkbenchAdapter, on page 718). For lists and single-column trees and tables, implement IViewerLabelProvider to efficiently set text, image, font, and color by implementing a single updateLabel() method; otherwise, implement IFontProvider and IColorProvider to provide font and color information, respectively.


7.2.6. Viewer sorter

Although a content provider serves up row objects, it is the responsibility of the ViewerSorter to sort the row objects before they are displayed. In the Favorites view, there are currently three criteria by which items can be sorted in either ascending or descending order:

  • Name

  • Type

  • Location

The FavoritesViewSorter delegates sorting to three comparators, one for each of the criteria just listed. In addition, the FavoritesViewSorter listens for mouse clicks in the column headers and resorts the table content based on the column that was selected. Clicking on a column a second time toggles the sort order.

package com.qualityeclipse.favorites.views;
import ...

public class FavoritesViewSorter extends ViewerSorter
{
   // Simple data structure for grouping
   // sort information by column.
   private class SortInfo {
      int columnIndex;
      Comparator comparator;
      boolean descending;
   }

   private TableViewer viewer;
   private SortInfo[] infos;

   public FavoritesViewSorter(
      TableViewer viewer,
      TableColumn[] columns,
      Comparator[] comparators
   ) {
      this.viewer = viewer;
      infos = new SortInfo[columns.length];
      for (int i = 0; i < columns.length; i++) {
         infos[i] = new SortInfo();
         infos[i].columnIndex = i;
         infos[i].comparator = comparators[i];
         infos[i].descending = false;
         createSelectionListener(columns[i], infos[i]);
      }
   }

   public int compare(
      Viewer viewer, Object favorite1, Object favorite2
   ) {
      for (int i = 0; i < infos.length; i++) {
         int result = infos[i].comparator
            .compare(favorite1, favorite2);
         if (result != 0) {
            if (infos[i].descending)
               return -result;
            return result;
        }
      }
      return 0;
   }

   private void createSelectionListener(
      final TableColumn column, final SortInfo info
   ) {
      column.addSelectionListener(new SelectionAdapter() {
         public void widgetSelected(SelectionEvent e) {
            sortUsing(info);
         }
     });
   }

   protected void sortUsing(SortInfo info) {
      if (info == infos[0])
         info.descending = !info.descending;
      else {
         for (int i = 0; i < infos.length; i++) {
            if (info == infos[i]) {
               System.arraycopy(infos, 0, infos, 1, i);
               infos[0] = info;
               info.descending = false;
               break;
            }
         }
      }
      viewer.refresh();
   }
}

A new field in FavoritesView is introduced now to hold the sorter instance:

private FavoritesViewSorter sorter; and the Favorites view createPartControl(Composite) method is modified to call the new method shown below. Later, the current sort order, as chosen by the user, must be preserved between Eclipse sessions (see Section 7.5.1, Saving local view information, on page 308).

private void createTableSorter() {
   Comparator nameComparator = new Comparator() {
      public int compare(Object o1, Object o2) {
         return ((IFavoriteItem) o1)
            .getName()
            .compareTo(
            ((IFavoriteItem) o2).getName());
      }
   };
   Comparator locationComparator = new Comparator() {
      public int compare(Object o1, Object o2) {
         return ((IFavoriteItem) o1)
            .getLocation()
            .compareTo(
            ((IFavoriteItem) o2).getLocation());
      }
   };
   Comparator typeComparator = new Comparator() {
      public int compare(Object o1, Object o2) {
         return ((IFavoriteItem) o1)
            .getType()
            .compareTo(
            ((IFavoriteItem) o2).getType());
      }
   };

   sorter = new FavoritesViewSorter(
      viewer,
      new TableColumn[] {
         nameColumn, locationColumn, typeColumn },
      new Comparator[] {
         nameComparator, locationComparator, typeComparator
   });
   viewer.setSorter(sorter);
}

7.2.7. Viewer filters

ViewerFilter subclasses determine which of the row objects returned by a content provider will be displayed and which will not. While there can be only one content provider, only one label provider, and only one sorter, there can be any number of filters associated with a viewer. When multiple filters are applied, only those items that satisfy all the applied filters will be displayed.

Similar to the sorting just discussed, the Favorites view can be filtered by:

  • Name

  • Type

  • Location

Eclipse provides the org.eclipse.ui.internal.misc.StringMatcher type, which is ideal for wildcard filtering, but since the class is in an internal package, the first step is to copy the class into the com.qualityeclipse.favorites.util package. Although copying sounds horrid, there are already 10 copies of this particular class in various locations throughout Eclipse, all of them internal (see Section 20.2, Accessing Internal Code, on page 711 for more on internal packages and the issues that surround them).

After that is complete, the ViewerFilter class for filtering the Favorites view by name looks like this (see below). This viewer filter is hooked up to the Favorites view using an action delegate in Section 7.3.4, Pull-down menu, on page 287.

package com.qualityeclipse.favorites.views;

import ...

public class FavoritesViewNameFilter extends ViewerFilter
{
   private final StructuredViewer viewer;
   private String pattern = "";
   private StringMatcher matcher;

   public FavoritesViewNameFilter(StructuredViewer viewer) {
      this.viewer = viewer;
   }

   public String getPattern() {
      return pattern;
   }

   public void setPattern(String newPattern) {
      boolean filtering = matcher != null;
      if (newPattern != null && newPattern.trim().length() > 0) {
         pattern = newPattern;
         matcher = new StringMatcher(pattern, true, false);
         if (!filtering)
            viewer.addFilter(this);
         else
            viewer.refresh();
      }
      else {
         pattern = "";
         matcher = null;
         if (filtering)
            viewer.removeFilter(this);
      }
   }

   public boolean select(
      Viewer viewer,
      Object parentElement,
      Object element
   ) {
      return matcher.match(
         ((IFavoriteItem) element).getName());
   }
}

7.2.8. View selection

Now that the model objects and view controls are in place, other aspects of the view, specifically actions, need a way to determine which Favorites items are currently selected. Add the following method to the FavoritesView so that actions can perform operations on the selected items.

public IFavoriteItem[] getSelectedFavorites() {
   IStructuredSelection selection =
      (IStructuredSelection) viewer.getSelection();
   IFavoriteItem[] items = new IFavoriteItem[selection.size()];
   Iterator iter = selection.iterator();
   int index = 0;
   while (iter.hasNext())
      items[index++] = (IFavoriteItem) iter.next();
   return items;
}


Previous Page
Next Page