| <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| <meta name="GENERATOR" content="Mozilla/4.76 [en] (Windows NT 5.0; U) [Netscape]"> |
| <meta name="Author" content="Balaji Krish-Sampath"> |
| <title>Understanding Decorators in Eclipse</title> |
| <link rel="stylesheet" href="../../default_style.css"> |
| </head> |
| <body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080"> |
| |
| <div align=right><font face="Times New Roman, Times, serif"><font size=-1>Copyright |
| © 2003 International Business Machines Corp.</font></font></div> |
| <table border=0 cellspacing=0 cellpadding=2 width="100%"> |
| <tr> |
| <td align=LEFT valign=TOP colspan="2" bgcolor="#0080C0"><b><font face="Arial,Helvetica" color="#FFFFFF"> Eclipse |
| Corner Article</font></b></td> |
| </tr> |
| </table> |
| </div> |
| <div align="left"> |
| <h1><img src="Idea.jpg" height=86 width=120 align=CENTER></h1> |
| </div> |
| <p> </p> |
| |
| <h1 ALIGN="CENTER">Understanding Decorators in Eclipse</h1> |
| <blockquote> |
| <b>Summary</b> |
| |
| <br> |
| Decorators, as the name suggests, are used for adorning/annotating resources |
| with useful information. Decorators can be used by plug-ins to convey more information |
| about a resource and other objects displayed in different workbench views. |
| This article, with the help of a simple plug-in example, will illustrate the |
| steps involved in decorating resources, along with some best practice approaches |
| for decorating resources. Finally, we will discuss performance issues that may |
| arise when enabling decorators, and briefly go over the new <a href="#New">Lightweight |
| decorators</a> found in Eclipse 2.1. |
| <p>We assume the reader already has a basic understanding |
| of Eclipse and knows how to create simple plug-ins. |
| <p><b>Balaji Krish-Sampath, IBM</b> |
| <br> |
| <font size=-1>January 16, 2003</font></blockquote> |
| </blockquote> |
| <hr width="100%"/> |
| <h2> |
| What are Decorators?</h2> |
| Decorators are visual cues that convey useful state information associated |
| with objects or resources displayed in Eclipse views. Many of the standard |
| workbench views participate in showing decorations, <font color="#000000">for |
| example, the navigator view, the package explorer view and the outline |
| view.</font> With decorators, users can get valuable information about |
| the resources in a particular view. The following figure illustrates a |
| simple custom decoration. |
| <center> |
| <p><img SRC="SimpleDecoration.gif" height=224 width=375> |
| <br><b><font size=-1>Fig. 1: Simple Decorator Example</font></b></center> |
| |
| <p>In the Fig. 1, a lock icon is superimposed on the Java icon image (<img SRC="tag_1.gif" height=13 width=24 align=CENTER>) |
| of the file ImageDecoration.java. A prefix and a suffix label are added for |
| the file TextDecoration.java (<img SRC="tag_3.gif" height=13 width=24 align=CENTER>). |
| The file NoDecoration.java does not have any custom decoration (<img SRC="tag_2.gif" height=13 width=24 align=CENTER>). |
| <p>With the help of a simple example, this article will provide a step by step |
| approach to decorating resources. Since the performance of the UI is affected |
| by the speed with which decorations are performed, we will concentrate on the |
| approaches that should be followed to make decoration efficient. Decoration |
| can be performed on resources and other objects displayed in Eclipse views. |
| Although the article illustrates most of the concepts with reference to decorating |
| a resource, decorations are not limited to resources and same technique can |
| be applied to decorate all the objects displayed in Eclipse views. <br> |
| |
| <h2> |
| Decorators are Everywhere</h2> |
| To better understand decorators, it is important<font color="#000000"> |
| to be able to spot some of the ba</font>sic decorations provided by Eclipse. |
| The introductory sentences about decorators and figure shown above (Fig. 1) might have given you the impression that decorators are just the |
| custom images annotating the resources with more valuable information. |
| However, some of the basic images that users see, like the problem marker |
| that is shown to alert the user about compilation errors is a good example |
| of basic decoration provided by Eclipse. |
| <p>Now that we know some of the basic decorations provided by Eclipse, |
| let's revisit the package explorer view. |
| <center> |
| <p><img SRC="BasicDecorations.gif" height=283 width=372> |
| <br><b><font size=-1>Fig. 2: Basic Decorations</font></b></center> |
| |
| <p>The figure shown above clearly illustrates the wealth of information that Eclipse |
| provides on resources and other objects contained in the workspace. This |
| ranges from information regarding the type of resource (a file or a folder or |
| a project), type of file (a Java file or a text file) and various Java elements. |
| In the figure shown above, a problem marker is superimposed on the compilation |
| unit (<img SRC="tag_1.gif" height=13 width=24 align=CENTER>), Java class element |
| (<img SRC="tag_2.gif" height=13 width=24 align=CENTER>) and method (<img SRC="tag_3.gif" height=13 width=24 align=CENTER>). |
| The problem marker decoration on the compilation unit indicates that the compilation |
| unit named ProblemMarkerDecoration.java has compilation errors. The problem |
| marker decoration on the compilationErrorMethod() method (<img SRC="tag_3.gif" height=13 width=24 align=CENTER>) |
| indicates the method failed to compile. <font color="#000000">By viewing the |
| Package Explorer view with basic decorations provided by Eclipse, users can |
| get details like reasons for compilation errors in a Java file.</font> |
| <h2> |
| <b><font size=+2>Types of Decorations</font></b></h2> |
| The display of a resource in a view has two components, the label (the |
| name of the resource) and an image denoting the type of resource and possibly |
| other state information. Using the Eclipse extension mechanism, we can |
| <font color="#000000">change |
| the label of the resource and the image of the resource. Hence, we have |
| two different types of decorations:</font> |
| <ul> |
| <li> |
| Text Label Decorators</li> |
| |
| <li> |
| Image Decorators</li> |
| </ul> |
| As the name suggests, text label decorators are decorations on resource labels |
| and image decorators are decorations on icon images. The resource name is the |
| base label provided by Eclipse. This is important because this is the base value |
| to be decorated and the decorator developer can assume that it will at least be |
| part of the input. Plug-in developers can augment the base resource label |
| with additional information. |
| <p>Let's revisit the Package Explorer view to understand more on text and |
| label decorators. |
| <center> |
| <p><img SRC="ImageAndTextDecorations.gif" height=271 width=417> |
| <br><b><font size=-1>Fig. 3: Image and Text Decorators</font></b></center> |
| |
| <p><font color="#000000">In the figure shown above, custom decorations are applied |
| to the base decorations provided by Eclipse</font><font color="#FF6666">.</font><font color="#000000"> |
| The file NoDecoration.java does not contain any contain any decoration (<img SRC="tag_1.gif" height=13 width=24>). |
| The file ImageDecoration.java has a lock icon (image decoration) superimposed |
| on the Java icon image (<img SRC="tag_2.gif" height=13 width=24>). The files |
| PrefixAdded.java and PrefixAndSuffixAdded.java have text decorations added to |
| their labels (<img SRC="tag_3.gif" height=13 width=24><img SRC="tag_4.gif" height=13 width=24>). |
| The file ImageAndTextDecorations.java has both image decoration (a lock icon |
| superimposed on the compilation unit) and text decorations (a prefix and a suffix |
| added to base label) (<img SRC="tag_5.gif" height=13 width=24>). The CustomDecorationsWithProblemMarker.java |
| has a problem marker decoration (basic decoration provided by Eclipse) as well |
| as custom image and text decorations (<img SRC="tag_6.gif" height=13 width=24>)</font> |
| <p><font color="#000000">So, how did these decorations get there? Let's |
| start our quest for creating custom decorators.</font> |
| <br> |
| <h2> |
| <b><font color="#000000"><font size=+2>Defining Decorators in plugin.xml</font></font></b></h2> |
| <font color="#000000">The first step in providing custom decoration is |
| to contribute to the org.eclipse.ui.decorators extension point.</font><a NAME="pluginXmlFile"></a> |
| <br> |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt><font color="#000000"><extension point="org.eclipse.ui.decorators"></font></tt> |
| <br><tt><font color="#000000"><decorator</font></tt> |
| <br><tt><font color="#000000"> id="com.ibm.decoratordemo.ui.decorator.demodecorator"</font></tt> |
| <br><tt><font color="#000000"> label="Decorator Example"</font></tt> |
| <br><tt><font color="#000000"> state="false"</font></tt> |
| <br><tt><font color="#000000"> class= "com.ibm.DecoratorDemo.ui.decorators.DemoDecorator"</font></tt> |
| <br><img SRC="tag_1.gif" height=13 width=24><tt><font color="#000000"> |
| objectClass="org.eclipse.core.resources.IResource"</font></tt> |
| <br><tt><font color="#000000"> adaptable="true"></font></tt> |
| <br><tt><font color="#000000"> <description></font></tt> |
| <br><tt><font color="#000000"> This is an |
| example to illustrate the use of decorators</font></tt> |
| <br><tt><font color="#000000"> </description></font></tt> |
| <br><tt><font color="#000000"> </decorator></font></tt> |
| <br><tt><font color="#000000"></extension></font></tt></td> |
| </tr> |
| </table> |
| |
| <center> |
| <b><font size=-1>Fig. 4: Plug-in manifest info</font></b> (<b><font size=-1>plugin.xml)</font></b> |
| </center> |
| |
| <ul> |
| <li> |
| id - defines the id of our decorator. There may be many decorators contributed |
| via the decorator extension point. The decorator id must be unique.</li> |
| |
| <li> |
| label - defines the label of the decorator for the workbench Label Decorations |
| Preference Page (shown in Fig. 5).</li> |
| |
| <li> |
| state - defines the default state of the decorator. The decorator can be |
| enabled or disabled by default.</li> |
| |
| <li> |
| class - class that implements the decorator. The class must implement org.eclipse.jface.viewers.ILabelDecorator |
| and is responsible for decorating the original label's image and text with |
| our own annotations.</li> |
| |
| <li> |
| objectClass - objectClass indicates the class of resources that need to |
| be decorated. If the user requires decoration only on files, the objectClass |
| element can be changed to denote that the decoration should be performed |
| only on files. <font color="#000000">To provide decoration only on files, <img SRC="tag_1.gif" height=13 width=24> |
| should be changed as objectClass="org.eclipse.core.resources.IFile"</font></li> |
| |
| <li> |
| adaptable - <font color="#000000">Indicates whether classes that |
| adapt to the resources should also be decorated. The adaptable flag holds |
| significance when decorations need to be performed on different elements |
| that conform to IResource. A detailed discussion on the use of adaptable |
| flag is provided later.</font></li> |
| |
| <li> description - an optional sub-element which contains text providing a short |
| description of the decorator. This will be shown in the Label Decorations |
| preference page as the description of the custom decorator.</li> |
| </ul> |
| |
| <p><br><b><font size=+2>Enabling / Disabling Custom Decorators</font></b> |
| <p>Individual decorators can be turned on and off from the Label Decorations preference |
| page. Users can access this page by selecting Window->Preferences->Workbench->Label |
| Decorations (<img SRC="tag_1.gif" height=13 width=24>). |
| <center> |
| <p><img SRC="LabelDecorationsPage.gif" height=360 width=533> |
| <br><b><font size=-1>Fig. 5: Label Decorations Preference Page</font></b></center> |
| |
| <p>The name of the decorator is the value of the <i>label attribute </i>of the |
| decorator extension (Fig. 4) while the description is the text contained in |
| the <i>description</i> sub-element. In the figure shown above, the "Decorator |
| Example"<i> </i>decorator is turned on (<img SRC="tag_2.gif" height=13 width=24 align=CENTER>), |
| while the other decorations are turned off. Although the above-mentioned scenario |
| might be typical when the project is not shared with CVS repository, enabling |
| and disabling the decorators are extremely useful when the decorations performed |
| by two or more decorators conflict with each other. For example, the CVS plug-in |
| might decorate the base image by superimposing the base image with a custom |
| image while the "Decorate Example" plug-in might superimpose a different custom |
| image at the same position thereby conflicting with the CVS plug-in decoration. |
| <font color="#000000">If the decoration performed by two different decorators |
| on the same resource conflict, users should appropriately enable / disable different |
| decorators to get the required decoration.</font> |
| <p><img SRC="tip.gif" height=11 width=56> It is very important to design |
| custom decorators that don't conflict with basic decorations provided by |
| different Eclipse views. For example, the package explorer view decorates |
| Java files with problem markers (a problem marker is placed at the bottom |
| left hand corner) if there are compilation errors. It is a bad practice |
| to decorate resources with custom decoration exactly at the position of |
| a problem marker and developers should avoid this. <font color="#000000">If |
| the custom decoration is performed at the bottom left corner, then custom |
| decoration and the problem marker decoration, if any, conflict each other |
| and hence users will not be able to view the decorations. The solution |
| to the above mentioned problem is to provide a custom image decoration |
| at the bottom right corner which does not conflict with the basic image |
| decoration provided by Eclipse. The top left corner is the second best |
| place although it conflicts with the binary project decorator. The bottom |
| left and top right should be avoided as they are decorated outside of the |
| decorator mechanism.</font><font color="#000000"></font> |
| <p>Before we proceed further, let's take a closer look at the class that |
| provides custom decoration. As mentioned earlier, the name of the class |
| should be same as the value specified in the class attribute. The class |
| must implement ILabelDecorator. |
| <br> |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt>// Class extends LabelProvider because LabelProvider</tt> |
| <br><tt>// provides methods for getting images and text labels from objects </tt> |
| <br><tt>public class DemoDecorator extends LabelProvider </tt> |
| <br><tt> implements ILabelDecorator</tt> |
| <br><tt>{</tt> |
| <br><tt> public DemoDecorator()</tt> |
| <br><tt> {</tt> |
| <br><tt> super();</tt> |
| <br><tt> }</tt> |
| <br><tt> // Method to decorate Image </tt> |
| <br><tt> public Image decorateImage(Image image, Object object)</tt> |
| <br><tt> {</tt> |
| <br><tt> // Return null to specify no decoration</tt> |
| <br><tt> return null;</tt> |
| <br><tt> }</tt> |
| <br><tt> // Method to decorate Text</tt> |
| <br><tt> public String decorateText(String label, Object object)</tt> |
| <br><tt> {</tt> |
| <br><tt> // return null to specify no decoration</tt> |
| <br><tt> return null;</tt> |
| <br><tt> }</tt> |
| <br><tt>}</tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 6: Decorator Implementation class</font></b></center> |
| |
| <p>The default implementation can be used as a template to get started. |
| The decorateImage() and decorateText() methods are used to decorate the |
| image and text respectively. A detailed discussion on how to decorate a |
| resource using these two methods is provided later. |
| <p><img SRC="tryit.gif" height=13 width=61> Contribute your custom decoration |
| via the decorator extension point in a plugin.xml manifest file (<a href="#pluginXmlFile">use |
| the example shown in previous section</a> ). Create a class to implement |
| custom decoration (Fig. 6). Note that the Java class name should be |
| the same as the text value of the <i>"class"</i> attribute of the decorator |
| tag |
| in plugin.xml. Compile and run. You should be able to see your custom |
| decoration appear inside Window->Preferences->Workbench->Label Decorations |
| as shown in Fig. 5. |
| <br> |
| <h2> |
| <font size=+2>Individual Preference Pages for Label Decoration</font></h2> |
| The label decorations preference page<font color="#000000"> provides the user |
| with only two options, eith</font>er to use a decorator or not. To provide users |
| more control over the decoration contents and use of a subset of decorations out |
| of a pool of decorations provided by a particular decorator, a plug-ins can provide |
| an individual preference page for its label decorators. For example, the CVS plug-in |
| provides a preference page (Window->Preferences->Team->CVS-> Label Decorations) |
| that allows users to control the presentation and content of CVS decorators. |
| <center> |
| <p><img SRC="CVSLabelDecorations.gif" height=437 width=665> |
| <br> |
| <b><font size=-1>Fig. 7: CVS Decoration Preference Page</font></b> |
| </center> |
| |
| <p>The figure shown above illustrates how plug-ins can use the individual label |
| decorator preference page to provide users the ultimate control over the decorations. |
| <font color="#000000">The CVS plug-in gives a user the control over the choice |
| of decorations, the richness in decorating different resources and the choice |
| of types of resources that need to be decorated. They can even control the look |
| and feel of decoration (<img SRC="tag_1.gif" height=13 width=24 align=CENTER><img SRC="tag_2.gif" height=13 width=24 align=CENTER>).</font> |
| <p>One of the important considerations while providing custom decorations |
| is the performance of UI with and without decorators. Users can effectively |
| use the individual decorator preference page to avoid decorations that |
| are expensive to compute and thus enhance the performance. |
| <p><img SRC="tip.gif" height=11 width=56> An individual decoration preference |
| page is extremely useful when resources are decorated on receiving external |
| events / notification. For example, a repository provider plug-in (e.g. org.eclipse.team.cvs.ui) |
| might be collaborating with an external server to decorate resources with a |
| lock icon, whenever resources are checked out by some other user. The repository |
| provider plug-in might be listening to thousands of events and it would be better |
| if the user has ultimate control on what to decorate (and what not to). |
| <p>Since individual decoration preference pages are preference pages that are |
| used to provide control to the users on decorations, they should be contributed |
| via the preference pages extension point. Users can refer to the articles <i><a href="../Article-Preferences/preferences.htm">Preferences |
| in the Eclipse Workbench UI</a></i> by Tod Creasey and <i><a href="../Article-Field-Editors/field_editors.html">Simplifying |
| Preference Pages with Field Editors</a></i> by <font color="#000000">Ryan Cooper |
| to learn more about preference pages and ways to create them.</font> |
| <h2> |
| <b>Example Plug-in Introduction</b></h2> |
| Now that we know how to declare a custom label decoration, and contribute |
| individual label decoration preference pages,<font color="#000000"> let's |
| dive into our Example Plug-in.</font> |
| <p>The basic idea behind providing this example is to illustrate how to |
| decorate images and text. To keep it as simple as possible, users are pro<font color="#000000">vided |
| with a custom File Property page. The file property page has a custom page |
| "DecoratorDemo File Property page" that provides a control for the users |
| to set the "Busy" property (The "Busy" property indicates that the resource |
| is busy and hence should not be modified)</font>. The page also provides |
| controls for users to set the prefix and suffix values for the resource. |
| <center> |
| <p><img SRC="CustomFilePropertyPage.gif" height=330 width=537> |
| <br><b><font size=-1>Fig. 8: Example Plug-in's File Property Page</font></b></center> |
| |
| <p>Using <font color="#000000">the file property page (Fig. 8) (a file property |
| page can be opened by right-clicking the file and selecting properties in the |
| context menu)</font>, users can set the busy state for the file. The busy state |
| when set is indicated by a lock icon superimposed on the base image provided |
| by Eclipse. Users can set the prefix and suffix values of resource labels (<img SRC="tag_2.gif" height=13 width=24 align=CENTER><img SRC="tag_3.gif" height=13 width=24 align=CENTER>). |
| <p>An individual label decoration preference page is provided for users to manage |
| the decorations (Fig. 9). They provide users control over prefix/suffix text |
| decoration <img SRC="tag_2.gif" height=13 width=24 align=CENTER>) and project |
| label decoration (<img SRC="tag_3.gif" height=13 width=24 align=CENTER>). The |
| project is decorated with a default text label decoration. |
| <center> |
| <p><img SRC="IndividualLabelDecorationPreferencePage.gif" height=280 width=524> |
| <br><b><font size=-1>Fig. 9: Example Plug-in's Label Decoration Preference |
| Page</font></b></center> |
| |
| <p>Now that we have been introduced to the example plug-in, let's go into |
| details. |
| <h2> |
| <b><font color="#000000">Beyond the Basics</font></b></h2> |
| <p><font color="#000000">Before delving deep into actual methods that provide |
| decorations, it is important to understand the concepts needed while decorating |
| a resource.</font></p> |
| |
| <h3>Persistent Resource Properties</h3> |
| Decorators, as we mentioned before, are used to visually annotate resources with |
| state information. The state information of a resource used for decoration should |
| be persistent across sessions. In our example plug-in, the prefix, the suffix |
| and the busy state of the resource should be persisted across sessions. There |
| are two ways to persist resource properties. One is the traditional way of associating |
| resources names with their corresponding properties, and storing them in a property |
| file. The second preferred method is to use Eclipse API to store persistent resource |
| properties. </p> |
| <p>Resources can have properties that hold state information. The properties of |
| a resource are declared, accessed and maintained by various plug-ins and are |
| not interpreted by the platform. There are two types of properties associated |
| with a resource: persistent properties and session properties. Persistent properties, |
| as the name suggests, are persistent across sessions while session properties |
| are maintained in memory and are lost when the project or workspace is closed. |
| Resource properties are deleted when the resources are deleted. |
| <p>Depending on the utility of the plug-in, plug-in developers can use |
| persistent or session properties. Persistent properties are stored on disk |
| and hence are accessible across platform sessions. The example plug-in |
| requires the busy state of the resource to be persisted across sessions. |
| The persistent property resource API is used to store and retrieve property |
| values by key. The following figure shows how to set and get the persistent |
| properties. |
| <br> |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt>// Create a qualified Name for Busy state of the resource</tt> |
| <br><tt>QualifiedName q1 = new QualifiedName </tt> |
| <br><tt> ("com.ibm.Decorator.DecoratorDemo", "Busy");</tt> |
| <p><tt>// Create a qualified Name for Prefix </tt> |
| <br><tt>QualifiedName q2 = new QualifiedName</tt> |
| <br><tt> ("com.ibm.Decorator.DecoratorDemo", "Prefix");</tt> |
| <p><tt>// Set the persistent properties</tt> |
| <br><tt>resource.setPersistentProperty (q1, "true");</tt> |
| <br><tt>resource.setPersistentProperty (q2, "Prefix Value");</tt> |
| <p><tt>// Get the value of persistent property q1... The value </tt> |
| <br><tt>// retrieved is "true"</tt> |
| <br><tt>String busyNature = resource.getPersistentProperty (q1);</tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 10: Sample code to manage Resource properties</font></b></center> |
| |
| <p>The code snippet (shown above) explains how to set / get persistent |
| property of resources using <i>qualified name</i>s. A qualified name |
| is analogous to a key used for accessing / storing property values. Qualified |
| names are composed of two-part names, a qualifier and a local name. The |
| local name (in the example shown above, the local names are "Busy" and |
| "Prefix") could be used by any decorator. So it is extremely important |
| to provide a unique URI value for the qualifier part. The simplest way |
| to ensure a unique qualifier value is to use the id of your plug-in as |
| the qualifier name. |
| <p><img SRC="tip.gif" height=13 width=62> Where does Eclipse store resource persistent |
| properties? Eclipse stores resource persistent properties in an internal database |
| at "<em>Workspace Location</em>/.metadata/.plugins/org.eclipse.core.resources/.projects/<em>Project |
| Name</em>/.properties". |
| <p><img SRC="tip.gif" height=13 width=62> Eclipse provides a mechanism |
| to store the sync information associated with a resource. Associating "sync |
| info" with a resource and decorating a resource using the sync information |
| is also an option plug-in developers might want to consider before proceeding |
| with use of persistent properties. Sync info maintains all the information |
| in memory and writes to disk only on save or a snapshot. Another advantage |
| of using sync info is that changes to sync information are reported in |
| the subsequent delta while it is difficult to keep track of the persistent |
| property resource changes. Readers can refer to "org.eclipse.core.resources.ISynchronizer" |
| to know more about sync info and ways to store sync information for a resource. |
| <h3>Overlay Images</h3> |
| In order to provide our custom decorations on a resource in addition to the basic |
| decorations provided by Eclipse, we superimpose custom images on the base image.<font color="#000000"> |
| Eclipse provides utility methods to help with overlaying an image over another.</font> |
| <p><img SRC="tip.gif" height=13 width=62> It<font color="#000000"> |
| is a good idea to design your decorators so that they do not overlap or |
| conflict with the existing platform SDK decorators.</font> For example, |
| Eclipse provides the problem marker decorator to alert users of compilation |
| problems. The custom decoration should not superimpose images at the same |
| position as the problem marker. <font color="#000000">The custom decoration |
| also should not lose the problem marker information. </font>Since different |
| custom decorator providers don't have prior knowledge about one another, |
| there is a good chance that custom decoration from two different plug-in |
| providers will conflict each other. The Workbench label decoration page |
| and the individual preference page provided by different custom decorators |
| provide users the control over the choice of different decorations. |
| <p>Eclipse provides an API for overlaying one image over other. The following |
| code snippet explains how to overlay an icon image over another image. |
| <ul> |
| <li> Create a class that extends org.eclipse.jface.resource.CompositeImageDescriptor. |
| CompositeImageDescriptor is an abstract base class that should be used by |
| image descriptors that synthesize an image from other images.</li> |
| |
| <li> |
| Implement drawCompositeImage() method to superimpose a custom image on |
| the base image.</li> |
| </ul> |
| |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt>protected void drawCompositeImage(int width, int height) </tt> |
| <br><tt>{ </tt> |
| <br><tt> // To draw a composite image, the base image should |
| be </tt> |
| <br><tt> // drawn first (first layer) and then the overlay |
| image </tt> |
| <br><tt> // (second layer) </tt> |
| <p><tt> // Draw the base image using the base image's image |
| data</tt> |
| <br><img SRC="tag_1.gif" height=13 width=24><tt> drawImage(baseImage_.getImageData(), |
| 0, 0); </tt> |
| <p><tt> // Method to create the overlay image data </tt> <br> |
| <tt> // Get the image data from the Image store or by other |
| means</tt> <br> |
| <tt> ImageData overlayImageData = demoImages.getLockImageData();</tt> |
| <br> |
| <tt><br> |
| </tt> <tt> // Overlaying the icon in the top left corner i.e. |
| x and y </tt> <br> |
| <tt> // coordinates are both zero</tt> <br> |
| <tt> int xValue = 0;</tt> <br> |
| <tt> int yValue = 0;</tt> <br> |
| <img SRC="tag_2.gif" height=11 width=24><tt> drawImage (overlayimageData, |
| xValue, yValue) </tt> <br> |
| <tt>}</tt> |
| </td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 11: Overlay Custom Image on the base Image</font></b></center> |
| |
| <p>The base image is drawn (<img SRC="tag_1.gif" height=13 width=24>) and then |
| the image that needs to be superimposed is drawn at the top left corner of the |
| base image (see <img SRC="tag_2.gif" height=11 width=24>). |
| <font color="#000000">The |
| example plug-in code "OverlayImageIcon.java" implements superimposing |
| the custom images on the base image at different locations.</font> |
| <p><img SRC="tip.gif" height=13 width=62> It is always good to create the overlay |
| image icons (that need to be superimposed on the base image) once and share |
| the same image across different views. In the example shown below (Fig. 12), |
| an image descriptor for a lock icon is created and the image data is returned |
| when requested by the drawImage() method of OverlayImageIcon (Fig. 11). In this |
| way, custom images are shared among objects across different views. The <a href="#best_practice_approaches">best |
| practice approaches</a> section also talks about the image registry and how |
| it can be best used to efficiently decorate resources with custom images. <br> |
| |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt>public class DemoImages</tt> |
| <br><tt>{</tt> |
| <br><tt> private static final ImageDescriptor lockDescriptor = </tt> |
| <br><tt> ImageDescriptor.createFromFile (DemoDecorator.class, |
| "lock.gif");</tt> |
| <p><tt> public ImageData getLockImageData()</tt> |
| <br><tt> {</tt> |
| <br><tt> return lockDescriptor.getImageData();</tt> |
| <br><tt> }</tt> |
| <br><tt>}</tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 12: Illustration on how images can be shared |
| among objects across views</font></b></center> |
| |
| <p>In our example plug-in, a lock icon is superimposed on the base image if the |
| file has its "busy" property set. The figure shown below shows how a resource's |
| image icon would look in the package explorer view (Fig. 13). The lock icon |
| is superimposed on the compilation unit and the runtime class instance of ImageDecoration.java |
| (<img SRC="tag_1.gif" height=13 width=24 align=CENTER><img SRC="tag_2.gif" height=11 width=24 align=CENTER>) |
| <center> |
| <p><img SRC="ImageDecoration.gif" height=203 width=373> |
| <br><b><font size=-1>Fig. 13: Superimpose a lock decorator</font></b></center> |
| |
| <p> |
| |
| <h3>Re-Decorate</h3> |
| When the workbench starts, the decorator manager checks for enabled decorators |
| (decorators are enabled using the Workbench > Label Decorations page) and decorates |
| the resources inside different views using the custom decorations provided by |
| these decorators. |
| <p>The properties of a resource might change at runtime, which will trigger the |
| need for redecoration. For example, users might change a file's busy attribute |
| using the file property page - and therefore the image decoration must be changed |
| to reflect the change. To re-decorate the resources, we fire a LabelProviderChangedEvent. |
| The fired event notifies the different workbench views that the label provider |
| for the resource has changed.<font color="#000000"> Eclipse calls the decorateImage() |
| and decorateText() methods for the resources whose label provider has changed. |
| A LabelProviderChangedEvent should only be fired when some aspect of the element |
| used to do the decoration changes. They can also be fired when the labels need |
| to be updated due to a change in decoration presentation (e.g. due to a change |
| in a preference page for the decorator). Sending these events will update all |
| affected views.</font> <br> |
| |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt><font color="#000000">public void refresh(List resourcesToBeUpdated)</font></tt> |
| <br><tt><font color="#000000">{</font></tt> |
| <br><tt><font color="#000000"> // resourcesToBeUpdated is a list |
| of resources whose decorators</font></tt> |
| <br><tt><font color="#000000"> // need to be changed. The persistent |
| property of the resources </font></tt> |
| <br><tt><font color="#000000"> // has been changed and hence its |
| decorators should change</font></tt> |
| <p><tt> // Check to see whether the custom decoration is enabled </tt> |
| <br><tt> DemoDecorator demoDecorator = getDemoDecorator();</tt> |
| <br><tt> if (demoDecorator == null)</tt> |
| <br><tt> {</tt> |
| <br><tt> // Decorator is not enabled.. Don't decorate |
| the resources.</tt> |
| <br><tt> return;</tt> |
| <br><tt> }</tt> |
| <p><tt><font color="#000000"> // Fire a label provider changed event |
| to decorate the </font></tt> |
| <br><tt><font color="#000000"> // resources whose image needs to |
| be updated</font></tt> |
| <br> |
| <img SRC="tag_1.gif" height=13 width=24 align=CENTER><tt><font color="#000000">fireLabelEvent(new |
| LabelProviderChangedEvent(demoDecorator,</font></tt> <br> |
| <tt><font color="#000000"> resourcesToBeUpdated.toArray()));</font></tt> |
| <br> |
| <tt><font color="#000000">}</font></tt> |
| <p><tt><font color="#000000">private void fireLabelEvent(final LabelProviderChangedEvent |
| event)</font></tt> |
| <br><tt><font color="#000000">{ </font></tt> |
| <br><tt><font color="#000000"> // Decorate using current UI thread</font></tt> |
| <br><img SRC="tag_2.gif" height=11 width=24 align=CENTER><tt><font color="#000000">Display.getDefault().asyncExec(new |
| Runnable()</font></tt> |
| <br><tt><font color="#000000"> {</font></tt> |
| <br><tt><font color="#000000"> public void run()</font></tt> |
| <br><tt><font color="#000000"> {</font></tt> |
| <br><tt><font color="#000000"> // Fire a |
| LabelProviderChangedEvent to notify eclipse views</font></tt> |
| <br><tt><font color="#000000"> // that label |
| provider has been changed for the resources</font></tt> |
| <br><img SRC="tag_3.gif" height=13 width=24 align=CENTER><tt><font color="#000000"> |
| fireLabelProviderChanged(event);</font></tt> |
| <br><tt><font color="#000000"> }</font></tt> |
| <br><tt><font color="#000000"> });</font></tt> |
| <br><tt><font color="#000000">}</font></tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font color="#000000"><font size=-1>Fig. 14: Re-Decorate Resources</font></font></b></center> |
| |
| <p>A LabelProviderChangedEvent is triggered (<img SRC="tag_3.gif" height=13 width=24>) |
| to notify different views that the label provider for the resources (in the |
| figure shown above, the resources list is stored in resourcesToBeUpdated) has |
| been changed and hence they need to be re-decorated. The plug-in developers |
| must provide a Runnable that fires a labelProviderChanged event (<img SRC="tag_2.gif" height=11 width=24 align=CENTER>). |
| <p><font color="#000000">If users choose to change the decoration preference |
| using the individual decoration preference page, </font>all the resources |
| in the workspace need to be re-decorated. This could be done easily by |
| changing line <img SRC="tag_1.gif" height=13 width=24 align=CENTER> |
| in Fig. 14 to <i>fireLabelEvent (new LabelProviderChangedEvent (demoDecorator)).</i> |
| <h3>IDecoratorManager Interface</h3> |
| IDecoratorManager manages custom decorators contributed |
| via the decorator's extension point. Some of the utility methods provided |
| by IDecoratorManager are:</font> |
| <ul> |
| <li> |
| <font color="#000000"><b>ILabelDecorator getLabelDecorator(String decoratorID)</b>- |
| Returns the label decorator for the specified decorator if it is enabled</font></li> |
| |
| <li> |
| <font color="#000000"><b>boolean getEnabled(String decoratorID)</b> - Returns |
| whether the specified custom decorator is enabled or not</font></li> |
| |
| <li> |
| <font color="#000000"><b>void setEnabled (String decoratorID, boolean enabled)</b> |
| - Enable/disable the custom decorator</font></li> |
| </ul> |
| There could be many custom decorators contributed via the decorator's extension |
| point. The id associated with the custom decorator is unique and should be used |
| to<font color="#FF6666"> </font><font color="#000000">distinguish between different |
| custom decorators. Views that allow decoration of their elements should use the |
| label decorator returned by the getLabelDecorator() method (<img SRC="tag_1.gif" height=13 width=24>). |
| The custom decorator objects (instance of the class used for decorating resources) |
| can be found using the decorator id (<img SRC="tag_1.gif" height=13 width=24>). |
| A custom decorator can be enabled or disabled by default using the state sub-element |
| in the plugin.xml manifest file.</font> <br> |
| |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt>/**</tt> |
| <br> |
| <tt> * Gets the custom decorator object. This method should be called |
| to get</tt> <br> |
| <tt> * the custom decorator object by all methods that try to |
| decorate resources</tt> |
| <br><tt> * @return Custom Decorator Instance if the custom decorator |
| is enabled</tt> |
| <br><tt> * null if |
| the custom decorator is not enabled </tt> |
| <br><tt> */</tt> |
| <br><tt>public static DemoDecorator getDemoDecorator()</tt> |
| <br><tt>{</tt> |
| <p><tt> // In Eclipse 3.5, use: PlatformUI.getWorkbench().getDecoratorManager();</tt></p> |
| <tt> IDecoratorManager decoratorManager =</tt> |
| <br><tt> DecoratorPlugin.getDefault().getWorkbench().getDecoratorManager();</tt> |
| <p><tt> // com.ibm.decoratordemo.ui.decorator.demodecorator is the |
| id of the </tt> |
| <br><tt> // custom decorator</tt> |
| <p><tt> // If the decorator is disabled, a null value is returned </tt> |
| <br><img SRC="tag_1.gif" height=13 width=24 align=CENTER><tt>return (DemoDecorator) |
| decoratorManager.getLabelDecorator(</tt> |
| <br><tt> "com.ibm.decoratordemo.ui.decorator.demodecorator");</tt> |
| <p><tt>}</tt></td> |
| </tr> |
| </table> |
| |
| <center> |
| <b><font color="#000000"><font size=-1>Fig. 15: How to get custom Decorator |
| instance using DecoratorManager Interface</font></font></b> |
| </center> |
| |
| <p><font color="#000000">The custom decorator class used for decorating resources |
| is a singleton. The decorator developers should not use the decorator object |
| (instance of the class used for decorating resources) when the decorator is |
| disabled. The decorator developers should never cache the decorator object. |
| The decorator object is disposed when the decorator is disabled and is recreated |
| when the decorator is re-enabled. The utility method getLabelDecorator() returns |
| a null value if the custom decorator is disabled or a custom decorator with |
| the given decoratorId does not exist (<img SRC="tag_1.gif" height=13 width=24 align=CENTER>).</font> |
| <h2> |
| <a NAME="best_practice_approaches"></a>Best Practice Approaches</h2> |
| The time taken for decoration should be as small as possible because the |
| performance of the UI will be adversely affected by slow decorator code. |
| Some of the best practice approaches that should be followed to reduce |
| the time involved in decorations are as follows: |
| <br> |
| <li> |
| <b>Use image descriptors to store descriptors of image rather than storing |
| the images</b></li> |
| |
| <br> |
| The org.eclipse.jface.resources.ImageDescriptor class, as the name suggests, is |
| a lightweight descriptor for an image. It contains all the information required |
| to create an image. Image Descriptors do not allocate an actual platform image |
| unless specifically requested using the createImage() method. Use of image descriptors |
| is one of the best strategies that should be used when your code is structured |
| such that it defines all the icons in one place and allocates them when needed. |
| <br> |
| |
| <li> <b>Use org.eclipse.jface.ImageRegistry to share images across different views</b></li> |
| |
| <br> |
| The ImageRegistry class is used to keep a list of named images. Clients can add |
| image descriptors or SWT images directly to the list. When an image is requested |
| by name from the registry, the registry will return the image if it has been created, |
| or create one from the descriptor. This allows clients of the registry to share |
| images. A well-written article on images <a href="../Article-Using%20Images%20In%20Eclipse/Using%20Images%20In%20Eclipse.html"><em>Using |
| Images in the Eclipse UI</em></a> by John Arthorne is a good reference for learning |
| how to manage images in Eclipse. |
| <p>Images that are added to or retrieved from the registry must not be |
| disposed by any client. The registry is responsible for disposing of the |
| image since the images are shared by multiple clients. The registry will |
| dispose of the images when the platform GUI system shuts down. Appropriate |
| use of image descriptors and the image registry is important while performing |
| decorations. Since many views participate in decoration, it is important |
| to share the images using the caching mechanism rather than creating images |
| from scratch. |
| <br> |
| <li> |
| <b>Use Lightweight Decorators when possible</b></li> |
| |
| <br> |
| Eclipse 2.1 introduces a lightweight decorator that will handle the image management |
| issues associated with decoration. Changes to the decorator mechanism in Eclipse |
| 2.1 and ways to create custom decorations using <a href="#New">Lightweight decorator</a> |
| mechanism are discussed later. <br> |
| |
| <h2> |
| Decorate Resources</h2> |
| Let us look at the actual methods that decorate the image or the text of |
| resource labels. As mentioned before, the <font color="#000000">class that |
| is responsible for decoration should implement the ILabelDecorator interface.</font> |
| <p><font color="#000000">The interface provides two utility methods to |
| decorate the text and image.</font> |
| <ul> |
| <li> |
| <b><font color="#000000">Image decorateImage(Image baseImage, Object element)</font></b></li> |
| |
| <li> |
| <b><font color="#000000">String decorateText(String initialText, Object |
| element)</font></b></li> |
| </ul> |
| <font color="#000000">The decorateImage method is used to decorate the object |
| image with additional state information of the resource. The current image of |
| the object can be obtained using the getImage() method of LabelProvider. The method |
| returns an annotated image or a null image if the object need not be decorated.</font> |
| The decorateText method is used to decorate the object label. <br> |
| |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt>public Image decorateImage(Image baseImage, Object object)</tt> |
| <br><tt>{</tt> |
| <br><tt> // This method returns an annotated image or null |
| if the </tt> |
| <br><tt> // image need not be decorated. Returning a null image</tt> |
| <br><tt> // decorates resource icon with basic decorations |
| provided</tt> |
| <br><tt> // by Eclipse</tt> |
| <p><tt> IResource objectResource;</tt> |
| <br><img SRC="tag_1.gif" height=13 width=24 align=CENTER><tt> objectResource |
| = (IResource) object;</tt> |
| <br><tt> if (objectResource == null)</tt> |
| <br><tt> {</tt> |
| <br><tt> return null;</tt> |
| <br><tt> }</tt> |
| <br> |
| <img SRC="tag_2.gif" height=13 width=24 align=CENTER><tt> if (objectResource.getType() |
| != IResource.FILE</tt><tt>)</tt> <br> |
| <tt> {</tt> |
| <br> |
| <tt> // Only files are decorated</tt> <br> |
| <tt> return null;</tt> |
| <br><tt> }</tt> |
| <br><tt> // Overlay custom image over base image </tt> |
| <br><tt> Image image;</tt> |
| <br><tt> OverlayImageIcon overlayIcon = new </tt> |
| <br><tt> OverlayImageIcon(baseImage, "Lock");</tt> |
| <br><img SRC="tag_3.gif" height=13 width=24><tt> image = overlayIcon.getImage();</tt> |
| <br><tt> return image;</tt> |
| <p><tt> // The image should be disposed when the plug-in is </tt> |
| <br><tt> // disabled or on shutdown</tt> |
| <br><tt>}</tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 16: DecorateImage Method to decorate images |
| icons</font></b></center> |
| |
| <p>The decorateImage() method (shown above) decorates only a file object and does |
| not decorate a project or a folder (<img SRC="tag_2.gif" height=13 width=24>). |
| The IResource object (<img SRC="tag_1.gif" height=13 width=24>) is used for |
| determining whether the object under consideration is a project / folder / file. |
| Using the OverlayImageIcon class (not shown), a lock decorator is superimposed |
| on the base image (<img SRC="tag_3.gif" height=13 width=24>) <br> |
| |
| <br> |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt>public String decorateText(String label, Object obj)</tt> |
| <br><tt>{</tt> |
| <br><tt> IResource objectResource;</tt> |
| <br><tt> objectResource = (IResource) object;</tt> |
| <p><tt> if (objectResource.getType() != IResource.FILE)</tt><br> |
| <tt> {</tt> |
| <br> |
| <tt> // Only files are decorated in this example</tt> |
| <br> |
| <tt> return null;</tt> |
| <br><tt> }</tt> |
| <p><tt> // Decorate the label of the resource with the admin name </tt> |
| <br><tt> String ownerName = System.getProperties().getProperty("user.name");</tt> |
| <br><img SRC="tag_1.gif" height=13 width=24 align=CENTER><tt>return label |
| + " ( " + ownerName + " )";</tt> |
| <br><tt>} </tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 17: DecorateText method to annotate the label |
| of resource</font></b></center> |
| |
| <p>The decorateText() method returns null (no decoration) for non-files. It decorates |
| the label of a file with owner information. Returning a null value signifies |
| that the decorator is ignored - it does not clear out any existing decorations. |
| <br> |
| |
| <h2> |
| When to Decorate</h2> |
| Just because you know how to decorate does not mean you know when to decorate. |
| There are no strict rules that could be followed to find out when to decorate |
| and when not to. Human intuition is the best way to proceed, although there |
| are various factors that could be taken into consideration. Factors that |
| could affect the decision on decoration are as follows: |
| <ul> |
| <li> The amount of time to perform the decoration.</li> |
| |
| <li> The benefit to the user of seeing this particular state information.</li> |
| |
| <li> |
| Is it possible to provide the state information in a different way?</li> |
| |
| <li> Is the decoration in any way interfering with the basic decorations provided |
| by Eclipse.</li> |
| |
| <li> |
| The frequency with which the state information changes.</li> |
| </ul> |
| Let us try to understand the above mentioned factors with an example. Let |
| us assume an example plug-in which tries to emulate CVS behavior - i.e. |
| trying to provide functionality for the developers to checkin / checkout |
| files from repository. The plug-in collaborates with an external server |
| to receive notification when resources are checked out by other users (checking |
| out a file means someone has extracted the file and is making changes to |
| the file). Let us assume the time spent on computing image decoration is |
| 0.5 seconds. The number of times the plug-in receives notification from |
| the external server would be huge since there are many files in the repository |
| and many users are working concurrently. |
| <p>In our example, it is advantageous for the users to know about the files |
| that are changed by others. But can they afford to lose 0.5 seconds for |
| every decoration? No. So the plug-in developers, rather than |
| decorating the image icon, can present the information to the user in a |
| different way, for example, the file properties view. Improper use of decorators |
| can lead to poor performance and will ultimately lead to plug-in decorators |
| becoming useless. |
| <br> |
| <h2> |
| <a NAME="Caveat"></a>Caveat Lector (Reader Beware)</h2> |
| We saw some of the best practice approaches that could be used to reduce |
| the time taken to decorate image icons. Every image in Eclipse uses operating |
| system resources. We don't want to create 1,000 copies of the same image. |
| It would be nice to use some of the features in Eclipse to cache decorated |
| images and use them for generating similar images. Let us assume we want |
| to superimpose a lock icon on three text files. There are two different |
| ways to do this using the methods described earlier to superimpose a lock |
| icon on the base image. The lock icon should be superimposed on the base |
| image for all three text files. It would be better to decorate the first |
| text file, cache the resultant image in the image registry and use the |
| cached image to decorate the remaining files. In this way, image caching |
| can be used to avoid superimposing the same custom image over the same |
| base image every time you perform decoration. Image caching would be advantageous |
| when the frequency of decoration is huge and the amount of time spent on |
| calculating the superimposed image is high. Image caching should be used |
| if the developers have a prior knowledge about images that might appear |
| multiple times. |
| <p><img SRC="tip.gif" height=13 width=62> Decorations are performed when |
| workbench starts initially. It is called when users open a resource, close |
| a resource, expand the resource tree etc. |
| <p>Image caching, although a good technique to reduce the time involved |
| in decorating resources is not without problems. Some of the inherent problems |
| associated with decoration using image caching approach are as follows: |
| <ul> |
| <li> |
| <b>Plug-in developers should know all the decoration on a resource: </b>To |
| understand the above mentioned problem, you should know how to generate |
| a key that would be used for retrieving images from the image cache. The |
| key is a string describing all the properties of the resource, for example, |
| the type of the resource (a file or a folder or a project), type of the |
| file (a Java file or a text file) and marker information associated with |
| the resource. There could be new decorations provided by other plug-ins |
| depending on a particular custom resource property. Decorators which do |
| not have knowledge about the custom resource property can't differentiate |
| between a resource that has the custom property set and resources that |
| do not have the custom property set. This could lead to wrong decoration.</li> |
| </ul> |
| |
| <ul> |
| <li> |
| <b>Decorating Java files: </b>To understand the problems associated with |
| using image caching to decorate Java files, let's revisit the plugin.xml |
| file.</li> |
| </ul> |
| |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt><extension point="org.eclipse.ui.decorators"></tt> |
| <br><tt> <decorator </tt> |
| <br><tt> id="YourDecorator" </tt> |
| <br><tt> label="Decorator Label" </tt> |
| <br><tt> state="false" </tt> |
| <br><tt> class="YourDecorator.class" </tt> |
| <br><tt> objectClass="org.eclipse.core.resources.IResource" </tt> |
| <br><tt> adaptable="true"> </tt> |
| <br><tt> </decorator> </tt> |
| <br><tt></extension></tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 18: Sample plugin.xml manifest file to contribute |
| decorators</font></b></center> |
| |
| <p>The attributes that are of interest are: objectClass and adaptable. |
| ObjectClass indicates the class of resources that need to be decorated. |
| The adaptable flag indicates whether the classes that adapt to the IResource |
| object should also be decorated. |
| <p><img SRC="tip.gif" height=13 width=62> If a user tries to decorate a Java file |
| in a navigator view, the decorateImage() and decorateText() methods are called |
| on the IFile object. If the user tries to decorate the Java file in a package |
| explorer, the decorateImage() and decorateText() methods are called on all the |
| Java elements (because all Java elements are adaptable to IFile objects). |
| <p>Let's see what happens when a user decorates a Java file and the adaptable |
| attribute is set to true. The decorateImage() method is called on all the |
| Java elements for the resource (JavaProject, PackageFragmentRoot, |
| PackageFragment, CompilationUnit (Java file), and runtime class). If the |
| adaptable flag is true, the object parameter passed to the decorateImage() |
| and decorateText() methods is an IResource object for compilationUnit and |
| runtime class while a null is passed for all the other Java elements. |
| <p>So what's the problem? Let us assume we cache the image (lock icon superimposed |
| on a Java (Compilation Unit) icon) with the property "Java Lock" to denote |
| that it is Java file with a lock icon superimposed on the base image. You |
| might have cached the image when decorateImage method was called on the |
| compilation unit. When decorateImage() method is called on a class file, |
| we get the same property information using the IResource object (Fig. |
| 16) and hence we decorate the class file with the cached copy. So instead |
| of getting a lock icon on top of a class icon, the class file image icon |
| is represented by a custom lock decorator on top of a Java icon image. |
| The following diagrams illustrate the aforesaid behavior. |
| <center> |
| <p><img SRC="ImageDecorationWithoutImageCaching.gif" height=202 width=371> |
| <br><b><font size=-1>Fig. 19: Overlaying Image without Image cache</font></b> |
| <br> |
| <p><img SRC="ImageDecorationWithImageCaching.gif" height=200 width=371> |
| <br><b><font size=-1>Fig. 20: Overlay Image using Image Caching</font></b></center> |
| |
| <p>From Fig. 19 and Fig. 20, it is clear that users should be careful while using |
| image caching with non-resource files. When image caching is used, the runtime |
| class is represented by a lock icon on top of the Java icon (<img SRC="tag_2.gif" height=13 width=24> |
| in Fig. 20) instead of a lock icon on top of the runtime class icon. Image caching |
| can't be used because there was no way to distinguish between the different |
| Java elements using the IResource object and its associated properties. To distinguish |
| between the Java elements, one has to depend on JDT core and write specific |
| adapters for Java elements. |
| <p><img SRC="tryit.gif" height=13 width=61> Change plugin.xml provided |
| with the example plug-in such that the class that implements decoration |
| is DemoDecoratorWithImageCaching rather than DemoDecorator. The DemoDecorator |
| object instance used in the "file property page" and "individual label |
| decorations preference page" should be replaced with an instance of DemoDecoratorWithImageCaching. |
| You should be able to see decoration like the one shown in Fig. 20. |
| <p>Due to the above mentioned problems, image caching, although a good |
| technique to reduce the time involved in decorating resources should not |
| be used. |
| <br> |
| <p><a NAME="New"></a><b><font size=+2>What's new in Eclipse 2.1?</font></b> |
| <p>In Eclipse 2.0, plug-in developers had to programmatically overlay the |
| custom images on top of the base image of the objects displayed in the |
| Eclipse views. Eclipse 2.1 introduces a lightweight decorator that will |
| handle the image management issues associated with decoration. It is also |
| possible to declare a lightweight decorator that simply overlays an icon |
| when enabled that requires no implementation from the plug-in. Lightweight |
| decorators performs decorations in a background thread and hence the UI |
| thread is not blocked when the decorations are performed. |
| <p>Let's look at the configuration markup for decorators in Eclipse 2.1. |
| <br> |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt>!ELEMENT decorator > </tt> |
| <br><tt> <!ATTLIST decorator </tt> |
| <br><tt> id |
| CDATA #REQUIRED </tt> |
| <br><tt> label CDATA #REQUIRED </tt> |
| <br><img SRC="tag_1.gif" height=13 width=24 align=CENTER><tt> |
| class CDATA #OPTIONAL // #REQUIRED if lightweight = false </tt> |
| <br><img SRC="tag_2.gif" height=11 width=24 align=CENTER><tt> |
| objectClass CDATA #REQUIRED </tt> |
| <br><tt> |
| //deprecated. Make this part of the enablement </tt> |
| <br><img SRC="tag_3.gif" height=13 width=24 align=CENTER><tt> |
| icon CDATA #OPTIONAL // required if there is no class </tt> |
| <br> |
| <img SRC="tag_4.gif" height=13 width=24><tt> location |
| ("TOP_LEFT" | "TOP_RIGHT" | "BOTTOM_LEFT" | "BOTTOM_RIGHT"| </tt> <br> |
| <tt> |
| "UNDERLAY") #OPTIONAL </tt> |
| <br> |
| <img SRC="tag_5.gif" height=13 width=24><tt> lightweight |
| (true | false) #IMPLIED </tt> <br> |
| <tt> adaptable |
| (true | false) #IMPLIED </tt> |
| <br><tt> state |
| (true | false) #IMPLIED </tt> |
| <br><tt> > </tt> |
| <br><tt> <!ELEMENT description (#PCDATA)> </tt> |
| <br> |
| <img SRC="tag_6.gif" height=13 width=24><tt> <!ELEMENT enablement (#PCDATA)> </tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 21: Configuration Markup for decorators in |
| Eclipse 2.1</font></b></center> |
| |
| <p>As you can see from Fig. 21, there are quite a few changes in the configuration |
| markup for decorators in Eclipse 2.1. The class which was a required field in |
| Eclipse 2.0 is an optional field in Eclipse 2.1(<img SRC="tag_1.gif" height=13 width=24 align=CENTER>). |
| The class attribute represents a fully qualified name of a class which implements |
| org.eclipse.jface.viewers.ILabelDecorator if lightweight is false or org.eclipse.jface.viewers.ILightweightLabelDecorator |
| if lightweight is true. The default value is false. If there is no class element |
| it is assumed to be true. The objectClass attribute is deprecated in Eclipse |
| 2.1 and is part of the enablement element (<img SRC="tag_2.gif" height=11 width=24 align=CENTER>). |
| The icon attribute is a new attribute in Eclipse 2.1 and it represents the path |
| to the overlay image to apply if the decorator is lightweight (<img SRC="tag_3.gif" height=13 width=24 align=CENTER>). |
| Location attribute represents the location to apply the decorator if the decorator |
| is lightweight (<img SRC="tag_4.gif" height=13 width=24>). The default value |
| of location is BOTTOM_RIGHT. Lightweight attribute can be used to signify whether |
| the decorator is lightweight or not (<img SRC="tag_5.gif" height=13 width=24>). |
| Enablement sub-elements represent the actionExpression used to determine enabled |
| state (<img SRC="tag_6.gif" height=13 width=24>). |
| <p>Let's look at an example to understand lightweight decorators. |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><tt><extension point="org.eclipse.ui.decorators"> </tt> |
| <br><tt> <decorator</tt> |
| <br><tt> id="com.ibm.DemoLightweightDecorator" </tt> |
| <br><tt> label="DemoLightweightDecorator" </tt> |
| <br><tt> state="false" </tt> |
| <br><img SRC="tag_1.gif" height=13 width=24><tt> class="com.ibm.Demo.LightweightDecorator" </tt> |
| <br><img SRC="tag_2.gif" height=11 width=24><tt> lightweight="true" </tt> |
| <br><tt> location="TOP_LEFT"</tt> |
| <p><tt> <enablement></tt> |
| <br><img SRC="tag_3.gif" height=13 width=24><tt> |
| <objectClass="org.eclipse.core.resources.IResource"/> </tt> |
| <br><tt> </enablement> </tt> |
| <br><tt> </decorator </tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 22: Decorator Extension using Lightweight |
| Decorator</font></b></center> |
| |
| <p>Since the lightweight attribute has a true value (<img SRC="tag_2.gif" height=11 width=24>), |
| the class com.ibm.Demo.LightweightDecorator (<img SRC="tag_1.gif" height=13 width=24>) |
| should implement org.eclipse.jface.viewers.ILightweightLabelDecorator. The class |
| com.ibm.Demo.LightweightDecorator should provide the text decoration labels |
| and the image descriptor and need not be concerned with the resource handling. |
| Another advantage of using Lightweight decorators is that the decoration work |
| is done in a background thread. |
| <p>Let's look at the ILightweightLabelDecorator interface to see how easy decorations |
| can be performed in Eclipse 2.1. |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><b><tt>org.eclipse.jface.viewers.ILightweightLabelDecorator interface:</tt></b> |
| <br><tt>The ILightweightLabelDecorator is a decorator that decorates using |
| a prefix, suffix and overlay image rather than doing all of the image and |
| text management itself like an ILabelDecorator. </tt> |
| <p><img SRC="tag_1.gif" height=13 width=24><tt> void <b>decorate</b>(Object |
| element, IDecoration decoration) </tt> |
| <br><tt> calculates decorations |
| based on element.</tt></td> |
| </tr> |
| </table> |
| |
| <center><b><font size=-1>Fig. 23: ILightweightLabelDecorator interface</font></b></center> |
| |
| <p>From Fig. 23, it is clear that plug-in developers should implement decorate() |
| method (<img SRC="tag_1.gif" height=13 width=24>) to perform both text and image |
| decorations. This is a big difference from Eclipse 2.0 where plug-in developers |
| had to implement decorateText() for performing text decorations and decorateImage() |
| method for performing image decorations. One added advantage of the Eclipse |
| 2.1 lightweight decorator mechanism is that plug-in developers need not be concerned |
| with resource handling and need only to provide the text and image descriptors. |
| When a plug-in developer tries to redecorate a resource by firing a LabelProviderChanged |
| event, Eclipse calls the decorate() method for the object. The plug-in developers |
| should appropriately set the overlay image descriptors, prefix label and the |
| suffix label using the IDecoration object instance. |
| <table BORDER COLS=1 WIDTH="100%" BGCOLOR="#CCCCCC" > |
| <tr> |
| <td><b><tt>org.eclipse.jface.viewers.IDecoration interface: </tt></b> |
| <br><tt>Defines the result of decorating an element. This interface is |
| not meant to be implemented and will be provided to instances of ILightweightLabelDecorator. </tt> |
| <p><img SRC="tag_1.gif" height=13 width=24><tt> void <b>addOverlay </b>(ImageDescriptor |
| overlay)</tt> |
| <br><tt> Adds an overlay to the |
| element's image. </tt> |
| <p><img SRC="tag_2.gif" height=11 width=24><tt> void <b>addPrefix </b>(String |
| prefix) </tt> |
| <br><tt> Adds a prefix |
| to the element's label. </tt> |
| <p><img SRC="tag_3.gif" height=13 width=24><tt> void <b>addSuffix</b> (String |
| suffix)</tt> |
| <br><tt> Adds a suffix |
| to the element's label. </tt></td> |
| </tr> |
| </table> |
| |
| <center> |
| <b><font size=-1>Fig. 24: IDecoration interface</font></b> |
| </center> |
| |
| <p>For the Example Plug-in, the lock image descriptor (to signify the busy state |
| of a resource) can be set using the addOverlay() method (<img SRC="tag_1.gif" height=13 width=24>). |
| The prefix and suffix labels for an object element can be set using the addPrefix() |
| and addSuffix() methods (<img SRC="tag_2.gif" height=11 width=24><img SRC="tag_3.gif" height=13 width=24>). |
| <p>If a plug-in requires a developer to provide only image decoration and |
| no text decorations, then the plug-in developer could make use of a declarative |
| LightweightDecorator. This means that plug-in developer need not provide |
| a class to implement ILightweightLabelDecorator but instead provide the |
| path for the icon image and location where the icon needs to be placed |
| (TOP_LEFT | BOTTOM_LEFT | TOP_RIGHT | BOTTOM_RIGHT | UNDERLAY). Eclipse |
| LightweightDecorator mechanism takes care of resource handling and image |
| decoration. |
| <p>As we have seen, the new LightweightDecorator mechanism is quite powerful |
| and makes it easy for developers to decorate resources. The source code |
| for the Example Plug-in implemented using lightweight decorators (Eclipse |
| M4 stable version) is provided below. |
| <h2> |
| Source Code</h2> |
| The example plug-in uses most of the best practice approaches that should |
| be followed while decorating a resource. Some of the classes are as follows: |
| <ul> |
| <li> DemoDecorator - Decorates the label and image icon of the resources.</li> |
| |
| <li> |
| DemoImages - Maintains the image descriptors of the custom decorator image |
| icons.</li> |
| |
| <li> |
| DemoStore - Stores user decoration preferences.</li> |
| |
| <li> DemoImageRegistry - Accesses the image registry to get the images from registry.</li> |
| |
| <li> DemoLabelDecoratorPreferencePage - Individual label decoration preference |
| page provided by DecoratorDemo plug-in.</li> |
| |
| <li> |
| DemoFilePropertyPage - Custom file property page.</li> |
| |
| <li> OverlayImageIcon - Class to overlay images.</li> |
| </ul> |
| To run the example or view the source code for this article, unzip <a href="sourceOfDecoratorPlugin.zip">sourceCodeOfDecoratorPlugin.zip</a> |
| into your <i>plug-ins/ </i>subdirectory. To run view the source code for |
| the Example plug-in using lightweight decorators, unzip <a href="sourceOfLightweightDecorator.zip">sourceCodeOfDecoratorPluginUsingLightweightDecorators.zip</a> |
| into your plug-ins/ subdirectory. |
| <h2> |
| Summary</h2> |
| Decorators are visual cues that convey useful state information associated |
| with objects or resources displayed in Eclipse views. Eclipse provides |
| ways for users to change the image and label decorators. The performance |
| of the Eclipse UI can be affected by the efficiency with which decorations |
| are performed. The best practice approaches mentioned in this article can |
| be used to reduce the time involved in decoration. An old saying, "<i>Pictures |
| are worth 1000 words - but only if you know the words</i>" aptly describes |
| the use of decorators. |
| <p><b><font color="#000000"><font size=+2>Acknowledgements</font></font></b> |
| <p>The author would like to thank Jan J. Kratky, Patrick McCarthy, Tod Creasey, |
| and Nick Edgar (all at IBM) for providing constructive comments on the article.</p> |
| <p><small>Java and all Java-based trademarks and logos are trademarks or registered |
| trademarks of Sun Microsystems, Inc. in the United States, other countries, or |
| both.</small></p> |
| </body> |
| </html> |