Previous Page
Next Page

20.7. Label Decorators

Label decorators visually indicate specific attributes of an object. For example, if a project is stored in a repository, then it has a small cylinder below and to the right of its folder icon in the Navigator view. The Navigator's label provider (see Section 7.2.5, Label provider, on page 277) returns a folder image, which is then decorated by the repository's label decorator with a small cylinder. The final composite image is then rendered in the Navigator view. Label decorators are not restricted to decorating images only; an object's text can be enhanced by adding characters to the beginning or end.

The org.eclipse.ui.decorators extension point provides a mechanism for adding new label decorators. Label decorators appear in the General > Appearance > Label Decorations preference page (see Figure 20-3) and can be enabled or disabled by the user. Behavior for a label decorator is supplied by implementing ILabelDecorator, and optionally IFontDecorator and/or IColorDecorator. If the information to decorate an object is not immediately available, for example the type of decoration depends on a network query, then implement IDelayedLabelDecorator.

Figure 20-3. The Label Decorations preference page.


20.7.1. Declaring a label decorator

In the Favorites product, you want to decorate objects in other views that also appear in the Favorites view. To accomplish this, create a new org.eclipse.ui.decorators extension (see Section 6.2.1, Defining a workbench window menu, on page 209 for an example of creating extensions) with the following values.

adaptable "true"

A flag that indicates whether types that adapt to IResource should use this object contribution. This flag is used only if objectClass adapts to IResource. The default value is false.

class "com.qualityeclipse.favorites.views.FavoritesLightweightDecorator"

A fully qualified name of a class that implements org.eclipse.jface.viewers.ILightweightLabelDecorator (see the next section) or is unspecified if this decorator has only an icon and no behavior (see Section 20.7.3, Decorative label decorators, on page 736).

icon Leave blank

If the decorator is lightweight and the class is not specified, this is the path to the overlay image to apply (see the next section).

id "com.qualityeclipse.favorites.favoritesLightweightDecorator"

A unique name that will be used to identify this decorator.

label "Favorites"

A translatable name that will be used in the General > Appearance > Label Decorations preference page to represent this decorator.

lightweight "true"

Must be TRue. Heavyweight label decorators are deprecated.

location "TOP_LEFT"

The location at which to apply the decorator image. Defaults to BOTTOM_RIGHT. Valid values include TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, and UNDERLAY.

objectClass "org.eclipse.core.resources.IResource"

A fully qualified name of a class to which this decorator will be applied. Deprecated in Eclipse 2.1 in favor of the enablement nested element (see Section 6.3.2.5, The enablement element, on page 231).

state "true"

A flag that indicates whether the decorator is on by default. The default value is false.

Use this description nested element to provide a brief description of what the label decorator does:

<description>
Indicates whether an object appears in the Favorites view.
</description>

You can add the enablement (see Section 6.3.2.5, The enablement element, on page 231), the and, the or, and the not subelements (see Section 6.3.2.2, The visibility element, on page 228) if you want to more exactly specify when this label decorator is to be used (see Section 20.7.3, Decorative label decorators, on page 736 for an example).

20.7.2. ILightweightLabelDecorator

Instances of ILightweightLabelDecorator can modify the image, text, font, and color displayed for an object. Create the class that contains the decorative behavior when you specify the class attribute by clicking the class label to the left of the class attribute's value. In the Java Attribute Editor, select Generate a new Java class, enter the package name and class name, and click the Finish button.

When the initial class has been generated, make sure that the decorator implements ILightweightLabelDecorator and not ILabelDecorator. The decorate() method appends "[favorite]" and overlays a small green F to any resource that has been added to the Favorites view.

package com.qualityeclipse.favorites.views;

import ...

public class FavoritesLightweightDecorator
   implements ILightweightLabelDecorator, FavoritesManagerListener
{
   private static final String SUFFIX = " [favorite]";
   private final ImageDescriptor OVERLAY =
      FavoritesPlugin.imageDescriptorFromPlugin(
         FavoritesPlugin.ID, "icons/favorites_overlay.gif");

   private final FavoritesManager manager =
      FavoritesManager.getManager();

   public void decorate(Object element, IDecoration decoration) {
      if (manager.existingFavoriteFor(element) != null) {
         decoration.addOverlay(OVERLAY);
         decoration.addSuffix(SUFFIX);
      }
   }
}

The decorator must also notify label listeners when the decoration for an element has changed. In this case, whenever an element has been added to or removed from the Favorites view, notify listeners that the state of associated resources has changed. This entails registering for change events from the FavoritesManager and then rebroadcasting those events to all registered ILabelProviderListener instances.

private final List listenerList = new ArrayList();

public FavoritesLightweightDecorator() {
   // Make sure that the Favorites are loaded.
   manager.getFavorites();
   manager.addFavoritesManagerListener(this);
}

public void dispose() {
   manager.removeFavoritesManagerListener(this);
}

public void addListener(ILabelProviderListener listener) {
   if (!listenerList.contains(listener))
      listenerList.add(listener);
}

public void removeListener(ILabelProviderListener listener) {
   listenerList.remove(listener);
}

public void favoritesChanged(FavoritesManagerEvent favoritesEvent) {
   Collection elements = new HashSet();
   addResourcesTo(favoritesEvent.getItemsAdded(), elements);
   addResourcesTo(favoritesEvent.getItemsRemoved(), elements);

   LabelProviderChangedEvent labelEvent =
      new LabelProviderChangedEvent(this, elements.toArray());

   Iterator iter = listenerList.iterator();
   while (iter.hasNext()) {
      ((ILabelProviderListener) iter.next())
         .labelProviderChanged(labelEvent);
   }
}

private void addResourcesTo(
   IFavoriteItem[] items, Collection elements)
{
   for (int i = 0; i < items.length; i++) {
      IFavoriteItem item = items[i];
      Object res = item.getAdapter(IResource.class);
      if (res != null) {
         elements.add(res);
      }
   }
}

public boolean isLabelProperty(Object element, String property) {
   return false;
}

When this behavior is in place, any elements added to the Favorites view will have a small "F" overlay and the suffix [favorite] in the Navigator view (see Figure 20-4).

Figure 20-4. Navigator view with Favorites and locked decoration.


20.7.3. Decorative label decorators

If you simply want to decorate a label by adding a static image in one of the quadrants without any text modifications, then you can specify the icon attribute instead of the class attribute. If the class attribute is not specified, Eclipse places the image specified by the icon attribute in the quadrant specified by the location attribute.

In this case, there is no need to create a class that implements ILightweightLabelDecorator because Eclipse provides this behavior for you. A read-only file decorator is one example of a decorative label decorator.

<decorator
   lightweight="true"
   location="BOTTOM_LEFT"
   label="Locked"
   icon="icons/locked_overlay.gif"
   state="true"
   id="com.qualityeclipse.favorites.locked">
   <description>
     Indicates whether a file is locked
   </description>
   <enablement>
      <and>
         <objectClass
            name="org.eclipse.core.resources.IResource"/>
         <objectState name="readOnly" value="true"/>
      </and>
   </enablement>
</decorator>

With this declaration in the plug-in manifest, a small lock icon appears in the lower left corner of the icon associated with any locked resource (see Figure 20-4).

20.7.4. IDecoratorManager

Now that you have added decorations to other views, it is time to decorate your own view. Eclipse provides a DecoratingLabelProvider and an decorator manager via the getdecoratorManager() method in IWorkbench. If the view contained a simple list, then you could wrap the FavoritesViewLabelProvider with a DecoratingLabelProvider by modifying the FavoritesView createTableViewer() method something like this:

IWorkbench workbench =
   getSite().getWorkbenchWindow().getWorkbench();
viewer.setLabelProvider(new DecoratingLabelProvider(
   new FavoritesViewLabelProvider(),
   workbench.getDecoratorManager()));

Unfortunately, the Favorites view contains a table, so a bit more work is involved to add the decorator. Start by adding the workbench decorator to the FavoritesViewLabelProvider.

final IDecoratorManager decorator;

public FavoritesViewLabelProvider() {
   decorator = PlatformUI.getWorkbench().getDecoratorManager();
}

Next, override the listener methods so that your view is notified when the workbench decoration has changed.

public void addListener(ILabelProviderListener listener) {
   decorator.addListener(listener);
   super.addListener(listener);
}

public void removeListener(ILabelProviderListener listener) {
   decorator.removeListener(listener);
   super.removeListener(listener);
}

Finally, modify the getColumnText() and getColumnImage() methods to query the workbench decorator before returning the requested text or image, respectively.

public String getColumnText(Object obj, int index) {
   switch (index) {
   case 0: // Type column
      return "";
   case 1: // Name column
      String name;
      if (obj instanceof IFavoriteItem)
         name = ((IFavoriteItem) obj).getName();
      else if (obj != null)
         name = obj.toString();
      else
         name = "";
      String decorated = decorator.decorateText(name, obj);
      if (decorated != null)
         return decorated;
      return name;
   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)) {
      Image image = ((IFavoriteItem) obj).getType().getImage();
      Image decorated = decorator.decorateImage(image, obj);
      if (decorated != null)
         return decorated;
      return image;
   }
   return null;
}


Previous Page
Next Page