blob: 5336577acf1508bceff089a16c6c51cdcba13b78 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org">
<title>Visual Editor Tutorial</title>
<link rel="stylesheet" type="text/css"
href="../default_style.css">
<style type="text/css">
.PictureParagraph { margin-left: 10% }
.PictureStyle { border-style: ridge; border-width: 1px; padding: 1px }
</style>
</head>
<body link="#0000ff" vlink="#800080">
<div align="right">
&nbsp; <font face="Times New Roman, Times, serif" size="2">Copyright
&copy; 2005 IBM and other contributors</font>
<table border="0" cellpadding="2" cellspacing="0" width="100%">
<tbody>
<tr>
<td colspan="2" align="left" bgcolor="#0080c0" valign="top">
<b><font face="Arial,Helvetica"><font color="#ffffff">&nbsp;Eclipse
Corner Article</font></font></b></td>
</tr>
</tbody>
</table>
</div>
<div align="left">
<h1><img src="../images/Idea.jpg" align="middle" height="86" width=
"120"></h1>
</div>
<p>&nbsp;</p>
<h1 align="center">Extending The Visual Editor:<br>
Enabling support for a custom widget</h1>
<blockquote>
<p><b>Summary</b><br>
This tutorial
shows how to extend the Visual Editor to support a custom widget.
It covers topics such as adding to the Visual Editor's palette,
building a BeanInfo class, and working with
EMF .override files to
introduce custom editor behavior.</p>
<p><b>Dave Orme, db4objects</b><br>
<b>Gili Mendel, IBM</b><br>
<b>Joe Winchester, IBM</b><br>
<font size="-1">June 20, 2005</font></p>
</blockquote>
<hr width="100%">
<h2><a name="Introduction"></a>Introduction</h2>
<p>The <a href="http://www.eclipse.org/vep">Visual Editor</a> project
provides reference implementations of a graphical user interface
builder for the JFC and SWT widget toolkits built around an extensible
framework.&nbsp; The motivation for this came from experience with
previous GUI builders that, while they provided high function end
points for particular toolkits, were unable to be adapted to support
custom behavior. This typically would be for areas of functionality
such as user defined widgets, new layout managers, or flexible code
generation patterns. A design goal of the Visual Editor is that is none
of its own custom behavior for any JFC or SWT classes is done with hard
coding and all logic that the VE employs to enable specific bespoke
function such dropping a control on a composite or showing feedback for
a particular layout manager is soft coded through extension points. The
intention is that the same techniques can be leveraged by anyone
wishing to employ similar techniques for their own scenario.</p>
<p>In this tutorial a 3.1 based Eclipse plugin&nbsp; <i>org.eclipse.ve.example.customwidget</i>
is created that illustrates some of the extension points of the visual
editor.&nbsp; To do this an SWT custom widget is built that combines a
Label, Text and Button in a single widget called <span
style="font-style: italic;">org.eclipse.ve.examples.customwidget.MyCustomPrompter</span>.&nbsp;</p>
<p><img style="width: 243px; height: 34px;" alt="CustomWidget"
src="images/CustomWidget.png"></p>
<p>MyCustomPrompter has two properties: <span
style="font-style: italic;">type</span> and <span
style="font-style: italic;">text</span>.&nbsp; These each have get and
set methods and can be used to configure the behavior of the Button and
the Text's text value.&nbsp; There is also a <span
style="font-style: italic;">ButtonSelectionEvent</span> event that is
raised when the prompter's button is pressed and listeners can register
for this callback using <span style="font-style: italic;">addButtonSelectionListener(ButtonSelectionListener
aListener);</span></p>
<p>In the absence of the plugin that this tutorial creates<span
style="font-family: monospace;">,</span> the <span
style="font-family: monospace;">MyCustomPrompter</span> widget can
still be used by a user who drops it onto an SWT composite by adding a
jar (or folder) containing the class to their Java project's build path<span
style="font-family: monospace;">.</span> Within the Visual Editor the
class can be selected by using <span style="font-style: italic;">ChooseBean</span>
from the palette to drop <span style="font-family: monospace;">MyCustomPrompter</span>
onto a composite. Through inheritance (<span
style="font-family: monospace;">MyCustomPrompter</span> extends <span
style="font-family: monospace;">org.eclipse.swt.widgets.Composite</span>)
the custom control will be rendered correctly and its properties will
be determined using JavaBeans<sup>TM</sup> reflection allowing it to be
modified using the Properties Viewer.&nbsp; The new event will also be
determined automatically through introspection by the Visual Editor and
available to the user to add callback logic to through the <span
style="font-style: italic;">Add Event</span> dialog.&nbsp;</p>
<p>This tutorial shows how to extend the edit experience by creating a
plugin that enables specific Visual Editor behavior over and above the
default that is determined through inheritance.&nbsp; This results in a
higher level edit experience for end users of the <span
style="font-style: italic;">MyCustomPrompter</span> class.&nbsp; The
examples given are purely for illustrative purposes only and to
highlight some of the available ways to extend the behavior of the
Visual Editor, and it is expected that the reader of this tutorial will
use it to learn the extension mechanism and then apply this to their
own custom widget or Java class.&nbsp;</p>
<h3><a name="Intro_Palette"></a>Palette</h3>
<p>The visual editor provides a palette of classes from which the user
can choose commonly used classes.&nbsp; The tutorial shows how to
create a new palette category containing the CustomWidget to allow it
to be brought to the user's selection and easily selected and dropped
without having to use <span style="font-style: italic;">ChooseBean</span>
and enter the class name</p>
<table style="text-align: left; width: 50%;" border="1" cellspacing="2"
cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">Before</td>
<td style="vertical-align: top;">With plugin showing <span
style="font-style: italic;">Custom</span> category with the <span
style="font-style: italic;">MyCustomPrompter</span> class</td>
</tr>
<tr>
<td style="vertical-align: top;"><img
style="width: 147px; height: 241px;" alt="OriginalPalette"
src="images/OriginalPalette.png"><br>
</td>
<td style="vertical-align: top;"><img
style="width: 143px; height: 240px;" alt="NewPalette"
src="images/NewPalette.png"> </td>
</tr>
</tbody>
</table>
<h3><a name="Intro_Property_sheet"></a>Property sheet</h3>
<p><span style="font-family: monospace;">MyCustomPrompter</span> has an
<span style="font-style: italic;">int</span> property called <span
style="font-style: italic;">type</span> that affects the text shown on
the CustomPrompter's button.&nbsp; This has a set of restricted values
corresponding to static constraints.&nbsp; For example, 0 is the
constant <span style="font-family: monospace;">CustomPrompter.DOTS</span>,
1 is <span style="font-family: monospace;">CustomPrompter.MORE</span>
and 2 is <span style="font-family: monospace;">CustomPrompter.OPEN.</span>
Rather than have the user have to remember this the property sheet will
be extended so that there is a drop down list of available values and
the existing value is shown as its meaningful name rather than its
internal <span style="font-style: italic;">int</span> value.</p>
<table style="text-align: left; width: 75%;" border="1" cellspacing="2"
cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">Before</td>
<td style="vertical-align: top;">With plugin</td>
<td style="vertical-align: top;">With plugin</td>
</tr>
<tr>
<td style="vertical-align: top;"><span style="font-style: italic;">type</span>
property displayed with default <span style="font-style: italic;">int</span>
editor</td>
<td style="vertical-align: top;"><span style="font-style: italic;">type</span>
property displayed as static constant name</td>
<td style="vertical-align: top;"><span style="font-style: italic;">type</span>
property edited with drop down list of enumerated allowable values</td>
</tr>
<tr>
<td style="vertical-align: top;"><img
style="width: 217px; height: 85px;" alt="OriginalType"
src="images/OriginalTypeProperty.png"><br>
</td>
<td style="vertical-align: top;"><img
style="width: 216px; height: 86px;"
alt="TypePropertyLabelProviderWithPlugin"
src="images/TypePropertyLabelProvider.png"><br>
</td>
<td style="vertical-align: top;"><img
style="border: 1px solid ; width: 216px; height: 86px;"
alt="TypePropertyCellEditor" src="images/TypePropertyCellEditor.png"></td>
</tr>
</tbody>
</table>
<p><span style="font-family: monospace;">MyCustomPrompter</span> has a
String property called <span style="font-style: italic;">text</span>
that reflects the value shown on the CustomPrompter's text
widget.&nbsp; The default property sheet editor for a String property
is a Text field that allows the value to be changed, however the
tutorial shows how to have a custom property editor that launches a
separate dialog through which the value can be changed</p>
<table style="text-align: left; width: 50%;" border="1" cellspacing="2"
cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">Before with default String
editor behavior for <span style="font-style: italic;">text</span>
property</td>
<td style="vertical-align: top;">With plugin showing custom
editor for <span style="font-style: italic;">text</span> property</td>
</tr>
<tr>
<td style="vertical-align: top;"><img
style="border: 1px solid ; width: 212px; height: 47px;"
alt="OriginalTextProperty" src="images/OriginalTextProperty.png"> </td>
<td style="vertical-align: top;"><img
style="border: 1px solid ; width: 211px; height: 46px;"
alt="TextPropertyCellEditor" src="images/TextPropertyCellEditor.png"> </td>
</tr>
</tbody>
</table>
<h3><a name="Intro_Graphical_behavior"></a>Graphical behavior</h3>
<p>The visual editor uses the graphical editor framework or GEF to
render the visual classes to the user.&nbsp; GEF is a powerful
framework which uses EditPart classes as mediators between the
underlying model and the draw2d view layer.&nbsp; This is similar to
the controller in an MVC pattern and described in overview at <a
href="http://www-128.ibm.com/developerworks/opensource/library/os-gef/index.html">
Create an Eclipse based application using GEF.</a> The default behavior
for a visual class is a WYSIWYG rendering where a preview of the live
runtime widget is drawn.&nbsp; There are times when you may wish to
override this for a specific component such as to visually annotate the
feedback for the figure such as drawing grid lines, additional handles
or other features provided by GEF.&nbsp; As an example of how to alter
the edit part used by the visual editor the tutorial shows how to have <span
style="font-style: italic;">MyCustomPrompter&nbsp;</span> rendered
with an icon <img style="width: 16px; height: 16px;" alt="Custom"
src="images/custom.gif"> and the text <span
style="color: rgb(255, 0, 0);">VE Rules</span> super imposed over the
image of the live visual control.&nbsp; In addition the default
behavior of a Composite graphical edit part is to draw a border around
it in the editor so that it can be located by the user irrespective of
whether it has child controls or not.&nbsp; <span
style="font-style: italic;">MyCustomPrompter</span> is an aggregate of
three child controls into a custom widget so the graphical edit part
will remove the artificial border.</p>
<table style="text-align: left; width: 100%;" border="1" cellspacing="2"
cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">Before with default behavior
showing the image of the live visual control with a border</td>
<td style="vertical-align: top;">With plugin showing custom edit
part with an icon and label and no border</td>
</tr>
<tr>
<td style="vertical-align: top;"><img
style="border: 1px solid ; width: 342px; height: 172px;"
alt="originalGEF" src="images/OriginalGraphicalEditPart.png"> </td>
<td style="vertical-align: top;"><img
style="border: 1px solid ; width: 341px; height: 171px;"
alt="GraphicalEditPart" src="images/GraphicalEditPart.png"> </td>
</tr>
</tbody>
</table>
<h3><a name="Intro_Code_generation"></a>Code generation</h3>
<p>Code generation uses decoder classes to mediate between the visual
editor's model and the Java source model.&nbsp; This tutorial shows how
to create a custom code generation rule for the <span
style="font-style: italic;">text</span> property of <span
style="font-style: italic;">MyCustomPrompter</span> so that it has an
additional comment placed on the line with the set method.&nbsp; This
is the string <span style="color: rgb(0, 102, 0);">// Prompter Text
Property</span></p>
<table style="text-align: left; width: 100%;" border="1" cellspacing="2"
cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">Before with default code
generation behavior</td>
<td style="vertical-align: top;">With plugin showing the extra
comment line code generated for the setText(String) method</td>
</tr>
<tr>
<td style="vertical-align: top; font-family: monospace;"><span
style="color: rgb(153, 0, 0);">private void</span>
createMyCustomPrompter() {<br>
&nbsp; myCustomPrompter = <span style="color: rgb(153, 0, 0);">new</span>
MyCustomPrompter(sShell, SWT.<span
style="font-style: italic; color: rgb(51, 51, 255);">NONE</span>);&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<br>
&nbsp; myCustomPrompter.setText(<span style="color: rgb(51, 51, 255);">"Text
Value"</span>);<br>
}</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;"><span style="color: rgb(153, 0, 0);">private
void</span> createMyCustomPrompter() {</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp; myCustomPrompter = <span
style="color: rgb(153, 0, 0);">new</span> MyCustomPrompter(sShell, SWT.<span
style="font-style: italic; color: rgb(51, 51, 255);">NONE</span>);&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span> <br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;
myCustomPrompter.setText(<span style="color: rgb(51, 51, 255);">"Text
value"</span>); <span style="color: rgb(0, 153, 0);">// Prompter Text
Property</span></span> <br style="font-family: monospace;">
<span style="font-family: monospace;">}</span> </td>
</tr>
</tbody>
</table>
<h3><a name="Intro_Preferred_Event"></a>Preferred Event</h3>
<p><span style="font-style: italic;">MyCustomPrompter</span> signals an
event when its button is pressed.&nbsp;&nbsp; Listeners can register
interest in this with the method <span style="font-style: italic;">addButtonSelectionListener(ButtonSelectionListener
aListener)</span> and remove interest with the method <span
style="font-style: italic;">removeButtonSelectionListener(ButtonSelectionListener
aListener).&nbsp;</span> The Visual Editor will automatically detect
this event because the naming convention of the methods and the
listener class follows the JavaBeans specification.&nbsp; The event
will be available from the list of all available events for the custom
control, however it is included in the list that has everything from
mouse through keyboard and paint events.&nbsp; This tutorial shows how
to promote the event to the list of <span style="font-style: italic;">preferred</span>
events whereupon it will be shown on the <span
style="font-style: italic;">Add Events</span> menu for the class.</p>
<table style="text-align: left; width: 100%;" border="1" cellspacing="2"
cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">Before where the Events menu has
no preferred events</td>
<td style="vertical-align: top;">With plugin the Events menu has <span
style="font-style: italic;">buttonSelected</span> as a preferred event</td>
</tr>
<tr>
<td style="vertical-align: top;"><img
style="border: 1px solid ; width: 502px; height: 412px;"
alt="OriginalEventsMenu" src="images/OriginalEventsMenu.png"> </td>
<td style="vertical-align: top;"><img
style="border: 1px solid ; width: 501px; height: 411px;"
alt="EventsMenuAfter" src="images/EventsMenuAfter.png"> </td>
</tr>
</tbody>
</table>
<h2><a name="Getting_started">Getting started</a></h2>
<p>This tutorial goes go through the steps required to build a plugin
called<i>org.eclipse.ve.example.customwidget</i><span
style="font-style: italic;"><span style="font-weight: bold;">.&nbsp;&nbsp;&nbsp;</span></span>
The pre-requisites are an Eclipse 3.1 target environment which has a
3.1 code-base for the Visual Editor, GEF and EMF installed.&nbsp; These
can be obtained from the <a
href="http://download.eclipse.org/tools/ve/downloads/index.php">Visual
Editor's download page</a>.&nbsp; There is an SDK version of the Visual
Editor available as well as a runtime, and to develop this tutorial
ensure you have the SDK download for the VE. If you obtain the SDK
drivers for GEF and EMF it means you will be able to view their source
and debug code more easily.</p>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;">&nbsp;&nbsp;&nbsp; Although the
plugin is designed to target 3.1 it can be developed in an earlier
environment such as 3.0.1.&nbsp; The target environment is the one that
is run when the <span style="font-weight: bold;">Run ... Eclipse
Environment</span> is used to launch a runtime workbench.&nbsp; You can
use <span style="font-weight: bold;">Windows-&gt;Preference-&gt;PDE-&gt;Target
Platform</span> to view and change the target environment and <span
style="font-weight: bold;">Help About</span> to see the version of
Eclipse.</p>
<p>The completed plugin can be obtained separately as described in the
section <a href="#A_complete_example">A complete example</a></p>
<h2><a name="Creating_the_Plugin">Creating the Plugin</a></h2>
<p>This section describes how to build the plugin <span
style="font-style: italic;">org.eclipse.ve.example.customwidget.&nbsp;</span>
This will be used to package the CustomWidget itself as well as to
include the extensions required to override its default behavior.&nbsp;
The end result for users is that they will install this plugin onto
their Eclipse environment and then configure their Java projects to use
the custom widget jar that is included in this plugin <a
href="#Using_a_classpath_container">using a class path container</a>.</p>
<p>To create the plugin select open the New Project wizard using the
menu options <span style="font-weight: bold;">File &gt; New &gt;
Project</span> and choose <span style="font-weight: bold;">Plug-in
Project</span><br>
</p>
<p><br>
On the first page of the creation wizard name the plugin <i>org.eclipse.ve.example.customwidget</i>,
select 3.1 as the target version and select the check box <span
style="font-style: italic;">Create an OSGi bundle manifest.&nbsp;&nbsp;</span>
Press <span style="font-style: italic;">Next</span> to bring up the <span
style="font-style: italic;">Plug-in-Content</span> page and enter a
plugin name such as <span style="font-style: italic;">Customwidget VE
Example Plugin</span> in the <span style="font-style: italic;">Plugin-In
Name</span> text field and set the name of runtime library to <span
style="font-style: italic;">customwidgetplugin.jar</span>.&nbsp;</p>
<p><img style="border: 1px solid ; width: 499px; height: 253px;" alt=""
src="images/CreatePluginWizard.png"></p>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;"> The reason the default suggested
runtime library name of <span style="font-style: italic;">customwidget</span><span
style="font-style: italic;"><span style="font-style: italic;">.jar</span></span>
is renamed to <span style="font-style: italic;">customwidgetplugin.jar</span>
is to distinguish the jar file used by the workbench code for the
plugin from the name that will be given to the runtime jar containing
the custom widget.&nbsp; This is covered in the section <a
href="#Different_jars_and_packages">Different jars and packages for
workbench and widget code</a></p>
<p>Press <span style="font-style: italic;">Finish</span> to have the
PDE generate the stub plugin.&nbsp; The workbench might then ask you to
switch to the PDE perspective which you can answer <span
style="font-style: italic;">Yes</span> to.&nbsp; The plugin manifest
editor should be opened by default.&nbsp; This is an editor that allows
you to view and edit the contents of the files called <span
style="font-style: italic;">plugin.xml and manifest.mf</span> that
reside within the plugin.&nbsp; These are both important files as they
describe the extension points used and also the list of pre-requisite
plugins.</p>
<p>A plugin represents a component that can be installed onto an
Eclipse environment and contributes code.&nbsp; Every plugin has a set
of dependent plugins which is those it requires to function.&nbsp; This
list would typically include pre-requisite plugins with classes or
interfaces extended or any extension points that have been used.&nbsp;
The list of pre-requisite plugins for a plugin extending the visual
editor is:</p>
<ul>
<li>org.eclipse.ui</li>
<li>org.eclipse.core.runtime</li>
<li>org.eclipse.ve.java.core</li>
<li>org.eclipse.jdt.core</li>
<li>org.eclipse.jem</li>
<li>org.eclipse.jem.proxy</li>
<li>org.eclipse.ve.cde</li>
<li><img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif">org.eclipse.ve.swt</li>
<li>org.eclipse.ve.propertysheet</li>
<li>org.eclipse.gef</li>
<li>org.eclipse.emf.ecore</li>
</ul>
<p>The pre-requisite plugin&nbsp;<img style="width: 24px; height: 13px;"
alt="" src="../images/tag_1.gif"> org.eclipse.ve.swt is not necessarily
required by everyone extending the visual editor.&nbsp; It contains the
code that enables the visual editor to work with the SWT and because <span
style="font-style: italic;">MyCustomPrompter</span> is an SWT custom
widget the plugin will be extending SWT base behavior.&nbsp; If your
plugin was for a JFC toolkit such as AWT or Swing you would not
necessarily include <span style="font-style: italic;">org.eclipse.ve.swt</span>
in your list of dependencies but instead would use <span
style="font-style: italic;">org.eclipse.ve.jfc.&nbsp;</span> If your
plugin was for an entirely new widget toolkit you might include neither.</p>
<p>To set up the list of required plugins select the <span
style="font-style: italic;">Dependencies</span> tab on the plugin
editor, select the <span style="font-style: italic;">Add ...</span>
button beside the list of Required Plug-ins and enter the list of
plugins listed above.</p>
<p><img style="border: 1px solid ; width: 353px; height: 166px;"
alt="PreReqPlugins" src="images/PreReqPlugins.png"></p>
<p>Having created the plugin there are two major steps remaining.&nbsp;
The first is to create the actual custom widget class itself and test
it, and the second is to extend the visual editor to have the
customized behavior described in the <a href="#Introduction">introduction</a>.</p>
<h2><a name="Different_jars_and_packages"></a>Different jars and
packages for workbench and widget code</h2>
<p>There are two jar files being created as part of this
tutorial.&nbsp; The reason for this is based on the architecture of the
Visual Editor and how it uses a separate JVM for the classes
instantiated by the editor rather with re-use or share the JVM used by
Eclipse itself.<br>
<br>
The Visual Editor can be considered as an extension to the Java
Development Tooling (JDT) that lets you preview any visual controls
that are part of the Java class being edited.&nbsp; The raw Java editor
on its own lets you view and modify the source code for a <span
style="font-style: italic;">.java</span> file, and edit it using
features like Code assist and the Outline viewer.&nbsp; When you use
code assist the list of available classes is scoped to be only those
that are valid for the current compilation unit, namely those present
in the Java build path of the project.&nbsp; The Java build path is
specified through the project's properties and can be thought of as the
list of <span style="font-style: italic;">-classpath</span> entries
that make up the <span style="font-style: italic;">javac</span>
command.&nbsp; If you try to use a class that isn't on the build path
you will get a compile error.&nbsp; If you try to call a method that
doesn't exist on a valid class you will get a compile error, although
if you were to change the build path so that it now contained a version
of the class that had the method it would compile.&nbsp; The build
path's entries determine the environment in which the class you're
editing is being created for and the editor responds accordingly.<br>
<br>
When the Visual Editor is open it uses the JDT's Java editor (as the
bottom half of the screen or a separate tab depending on the workbench
preferences) and parses the code to recognize visual classes and how
they are constructed and associated with each other together with their
initial property values. To create a preview of the visuals these
classes must be actually instantiated in a live environment following
the constructor pattern detected from the source and set methods
actually invoked against the live objects for the desired properties
and relationships.&nbsp; To do this a JVM environment must exist that
contains the list of <span style="font-style: italic;">-classpath</span>
entries that match those in the Java build path so that the JVM can
load and use the actual instances the user is editing their project
with.&nbsp; This can't be the Eclipse's JVM as this is started with the
.jar files required for it to behave as an editor, so a separate JVM is
created each time the Visual Editor is opened on a class.&nbsp; This is
sometimes referred to as the <span style="font-style: italic;">target
VM</span> and its purpose is to host prototype Java instances that the
Visual Editor instantiates and uses based on the source statements in
the <span style="font-style: italic;">.java</span> file being
edited.&nbsp;&nbsp; A good analogy to this process is the one used by
the <span style="font-style: italic;">Run As&gt;Java Application</span>
option in the JDT.&nbsp; If you write a Java class with a public void
main(String[] args) method the JDT lets you edit it inside the Eclipse
JVM, however to test it a separate JVM is launched by the <span
style="font-style: italic;">Java Application</span> launcher.&nbsp;
The JDT launcher's separate JVM can be viewed from the <span
style="font-style: italic;">Debug</span> viewer allowing you to set
breakpoints and step through code, while the Visual Editor's <span
style="font-style: italic;">target VM</span> is deliberately hidden
from the <span style="font-style: italic;">Debug</span> viewer to stop
users from accidentally terminating it.<br>
<br>
When writing the plugin for this tutorial there are two jar files that
will finally be created.&nbsp; The first of these is the <a
href="#Plugin_Jar">plugin side jar</a> and contains the Eclipse
workbench code that is used within the IDE's VM and contains code such
as a JFace property sheet editor, a GEF graphical edit part and a
custom source decoder.&nbsp; The second is the <a href="#Runtime_jar">runtime
side jar</a> that contains the actual <font face="Courier New">MyCustomPrompter</font>
class itself and doesn't run inside the IDE but instead is placed in
the Java build path of the user's project and runs in the target
VM.&nbsp; The runtime side jar also contains the BeanInfo class for
MyCustomPrompter that contains the extensions that conform to the
JavaBeans component model which is covered more in the sections on the <a
href="#Using_an_ENUM_cell_editor"><span style="font-style: italic;">type</span>
property editor</a> and creating the <a href="#Preferred_Event">preferred
event</a>.<br>
<br>
<img style="width: 601px; height: 515px;" alt=""
src="images/JARdiagram.png"><br>
</p>
<h3><a name="Plugin_Jar"></a>Plugin jar</h3>
<p>The plugin code for this tutorial is placed in <span
style="font-style: italic;">customwidgetplugin.jar</span> that is
defined as the runtime jar for the plugin itself.&nbsp; On the New
Project wizard we explicitly changed the default prompted jar name to
be <i>customwidgetplugin.jar</i> so that is will not be confused with
the <a href="#Runtime_jar">run time jar</a>. The <span
style="font-style: italic;">customwidgetplugin.jar </span>contains
the Eclipse code that will run inside the workbench and its definition
can be seen in the in the <span style="font-style: italic;">Runtime</span>
tab of the manifest editor for the plugin's plugin.xml file.&nbsp;<br>
<br>
<img style="border: 1px solid ; width: 357px; height: 155px;" alt=""
src="images/RuintimeLibraryPluginName.png"><br>
<br>
<img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;"> The name of the plugin code's jar
is either held in a <span style="font-family: monospace;">&lt;runtime&gt;&lt;library
name="customwidgetplugin.jar"&gt;&lt;/runtime&gt;</span> tag in the <span
style="font-style: italic;">plugin.xml</span> file for a pre 3.1
plugin, or else for an OSGI 3.1compatible only plugin the jar file name
is held in the <span style="font-style: italic;">MANIFEST.MF</span>
file in the line <span style="font-family: monospace;">Bundle-ClassPath:
customwidgetplugin.jar</span>.&nbsp;<br>
<br>
The package <span style="font-family: monospace;">org.eclipse.ve.example.customwidget</span>
contains the Java code that is used to create the contents of the <span
style="font-style: italic;">customwidgetplugin.jar</span>.<br>
</p>
<h3><a name="Runtime_jar"></a>Runtime jar</h3>
<p>The code for the <span style="font-family: monospace;">MyCustomPrompter</span>
and its BeanInfo class are placed in the package<span
style="font-family: monospace;">org.eclipse.ve.example.customwidget.prompter</span>.&nbsp;
When the plugin is deployed these classes are compiled not into the
plugin's <span style="font-style: italic;">customwidgetplugin.jar</span>
but
instead to a file customwidgets.jar.&nbsp;&nbsp; The steps to create
the customwidgets.jar are described in the section <a
href="#The_Custom_Widget">The Custom Widget</a>.</p>
<h2><a name="The_Custom_Widget">The Custom Widget</a></h2>
<p>The custom widget used in this tutorial extends SWT composite and
has three child controls on it; a label, a text field, and a
button.&nbsp; For this tutorial we used the Visual Editor to build the
custom widget which, although a good exercise in using the Visual
Editor, is outside the scope of what this tutorial is designed to cover
- you can download it directly from CVS to begin working.&nbsp; You
should download the two classes <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/src/org/eclipse/ve/example/customwidget/prompter/MyCustomPrompter.java">
<font face="Courier New">MyCustomPrompter.java</font></a>, and <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/src/org/eclipse/ve/example/customwidget/prompter/ButtonSelectionListener.java">
<font face="Courier New">ButtonSelectionListener.java</font></a> and
place them into the plugin project in a package <span
style="font-style: italic;">org.eclipse.ve.customwidget.prompter.&nbsp;</span>
This is illustrated below together with the Visual Editor opened
against the <span style="font-style: italic;">MyCustomPrompter</span>
class to show the three child controls.&nbsp; The package <span
style="font-style: italic;">org.eclipse.ve.example.customwidget</span>
is where the visual editor classes&nbsp; (such as the specialized
graphical edit part or code generation decoder) will reside, and the
package <span style="font-style: italic;">org.eclipse.ve.customwidget.prompter</span>
is where the classes reside that the user will use to build their
runtime GUIs with.&nbsp;</p>
<p><img style="border: 1px solid ; width: 721px; height: 357px;"
alt="RuntimeClasses" src="images/CustomWidgetPackage.png"></p>
<p>For deployment the classes <span style="font-style: italic;">MyCustomPrompter</span>
and <span style="font-style: italic;">ButtonSelectionListener</span>
will be packaged in a runtime jar.&nbsp; To do this select the runtime
package and use the pop up menu option <span style="font-weight: bold;">Export</span>
to bring up the Export wizard.&nbsp; Select the JAR file option and
name the JAR file <span style="font-style: italic;">customwidgets.jar.&nbsp;</span>
This JAR file will be placed inside the plugin itself and there are two
ways to do this.&nbsp; The first is to either export the JAR to a
temporary location on your computer and then import it into the
project.&nbsp; If you do this you should import the <span
style="font-style: italic;">customwidgets.jar</span> not as a JAR file
as it contains no code of any interest to the plugin itself, but
instead as a raw <span style="font-style: italic;">File</span>.&nbsp;&nbsp;
The reason for this is that the inclusion of the runtime code in the
plugin is not for the benefit of Eclipse and it will never be loaded by
the Visual Editor into the Eclipse JVM.&nbsp; The user of the plugin
will configure their Java project to use the custom prompter which is
described in the later section <a href="#Using_a_classpath_container">Using
a classpath container</a>, and the visual editor will insert the JAR
into the -classpath of the VM that it uses to host the Java classes
that make up the user's classes.<br>
<br>
The second way to ensure that the <span style="font-style: italic;">customwidgets.jar</span>
is included in the plugin that avoids having to export to the file
system and then re-import as a file, is to export straight to the
directory used by the plugin itself.&nbsp; To see the location of the
plugin you can open its properties and select Info.&nbsp; The figure
below shows an example of this where the workbench location is
D:\temp\tutorial and the JAR wizard creates customwidgets.jar into the
directory used by the <span style="font-style: italic;">org.eclipse.ve.example.customwidget</span>
plugin.&nbsp; If you do export directly to the workbench as shown below
afterwards you will need to do a manual refresh of the project's
contents using F5 (or the pop-up menu option) to ensure that the
Eclipse workbench is in sync with the file system contents that have
just been altered.<br>
</p>
<img style="border: 1px solid ; width: 466px; height: 401px;"
alt="JarExport" src="images/JARExport.png"><br>
<br>
<h3><a name="Testing_MyCustomPrompter"></a>Testing MyCustomPrompter</h3>
<p>Having created the plugin you can now test it.&nbsp; To do this
create an Eclipse launch configuration using the <span
style="font-weight: bold;">Run</span> menu to bring up the list of
available launch configurations, selecting <span
style="font-style: italic;">Eclipse Application</span> and <span
style="font-style: italic;">New</span> and then running this using the
default application.</p>
<p><img alt="" style="border: 1px solid ; width: 261px; height: 311px;"
src="images/LaunchConfig.png"></p>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;"> On Eclipse 3.0.x an <i>Eclipse
Application</i> launch configuration is called <i>Run-time Workbench.</i></p>
<p>This will launch a second Eclipse workbench - the first being your
one that you are using to develop the plugin and the second being the
one you are going to use to deploy the plugin into.&nbsp; In the
deployed workbench create a Java project and add <i>customwidgets.jar</i>
to the Java build path.&nbsp; This is done using the pop-up menu option
to open the <span style="font-weight: bold;">Properties</span> of the
project and selecting <span style="font-weight: bold;">Java Build path
...</span>.&nbsp; On the build path select the <span
style="font-style: italic;">Libraries</span> tab and <span
style="font-style: italic;">Add External Jar ...</span>.&nbsp; Point
to the location of the jar in the plugin itself - for the example
figure above this would be <span style="font-style: italic;">D:\temp\tutorial\org.eclipse.ve.example.customwidget.customwidgets.jar.</span>&nbsp;
Having added the JAR containing the <span style="font-style: italic;">MyCustomPrompter</span>
class you can now use it within a visual editor class.&nbsp; Create a
test sample using <span style="font-weight: bold;">File &gt; New &gt;
Visual class</span> and selecting <span style="font-weight: bold;">SWT
&gt; Shell.&nbsp;</span> This will open the Visual Editor over a class
with an SWT shell.&nbsp; Select the <span style="font-style: italic;">Choose
Bean</span> palette entry and because <span style="font-style: italic;">customwidgets.jar</span>
is in the project's build path (the effective -classpath used by the
Eclipse Java compiler and by the Visual Editor) you can choose <span
style="font-style: italic;">MyCustomPrompter</span> and drop it onto
the Shell.<br>
<br>
The behavior of <span style="font-style: italic;">MyCustomPrompter</span>
is everything picked up by default as the Visual Editor will realize
that <span style="font-style: italic;">MyCustomPrompter</span> extends
<span style="font-style: italic;">org.eclipse.swt.widgets.Composite</span>
so it will be rendered visually and have default property sheet, code
generation, graphical edit part and event menu behavior.&nbsp; The
remainder of this tutorial shows how to customize this behavior as
described in the <a href="#Introduction">introduction</a>.</p>
<h2><a name="Creating_a_Classpath_Container">Creating a classpath
container</a></h2>
<p>For the test described at the end of the preceding section the <span
style="font-style: italic;">MyCustomPrompter</span> class was made
available to the user's Java project by them adding it as an external
JAR.&nbsp; This isn't ideal as it requires the user knowing the
location of the plugin directory on their computer and physically
pointing to it.&nbsp; A better way is to use a classpath
container.&nbsp; This allows one-touch configuration of a Java project
to use a named container which handles all the internals of how to
locate the correct runtime code.&nbsp;</p>
<p>A Java container is a class that implements the JDT interface <span
style="font-style: italic;">org.eclipse.jdt.core.IClasspathContainer</span>.&nbsp;&nbsp;
It is added to a Java project's build path using the <span
style="font-style: italic;">Add Library</span> button on the <span
style="font-style: italic;">Libraries</span> tab and an example of one
used by the Visual Editor is <span style="font-style: italic;">org.eclipse.ve.internal.swt.SWTContainer</span>.&nbsp;&nbsp;
As well as the JDT using the container to locate the runtime classes
the Visual Editor uses this as a marker for extension behavior.&nbsp;
When the Visual Editor opens over a project all of the containers are
scanned and matched against extension points to see if there are any
plugins that wish to contribute to the palette or any other custom
visual editor behavior based on the classes included within the
container.</p>
<p>This tutorial doesn't create a new container class because the
complexities involved doing this require knowledge of JDT concepts such
as IPath and IClassPathEntry[].&nbsp; It is expected that commercial
quality plugins extending the Visual Editor will create their own
containers in which case the <span style="font-style: italic;">SWTContainer</span>
class is a good example to look at to learn how to do this, however for
simplicity the visual editor provides a reference implementation
container class&nbsp; <span style="font-style: italic;">org.eclipse.ve.internal.java.core.RegisteredClassPathContainer.&nbsp;</span>
The Registered container uses extension points to determine the JAR
files it will add to the user's build path.</p>
<p>The user experience is that a container called "Custom Prompter"
will be available for them to add to a Java project's build path.&nbsp;
This is described in the section <a href="#Using_a_classpath_container">Using
a classpath container</a>.&nbsp; The JDT extension point <span
style="font-style: italic;">org.eclipse.jdt.ui.classpathContainerPage</span>
allows contributions to be made for an entry to appear in the list of
containers and be available for the user to select, as well as the
wizard page that will then appear once <span
style="font-style: italic;">Next</span> is pressed.&nbsp; The wizard
page is responsible for configuring the project's build path to
actually add the container classpath entry.</p>
<p>To add the <span style="font-style: italic;">Custom Prompter</span>
entry to the list of available containers add the following to the <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/plugin.xml">
plugin.xml</a> of the <span style="font-style: italic;">org.eclipse.ve.examples.customwidget</span>
plugin.</p>
<pre> <a name="ContainerPageDefinition"></a>&lt;extension<br> point="org.eclipse.jdt.ui.classpathContainerPage"&gt;<br> &lt;classpathContainerPage<br><img
style="width: 24px; height: 13px;" alt="tag1" src="../images/tag_1.gif"> name="Custom Prompter"<br><img
style="width: 24px; height: 13px;" alt="tag2" src="../images/tag_2.gif"> class="org.eclipse.ve.internal.java.wizard.RegisteredClasspathContainerWizardPage"<br><img
style="width: 24px; height: 13px;" alt="tag3" src="../images/tag_3.gif"> id="org.eclipse.ve.example.PrompterContainer"&gt;<br> &lt;/classpathContainerPage&gt;<br> &lt;/extension&gt;<br></pre>
<p>The name <img style="font-style: italic; width: 24px; height: 13px;"
alt="tag1" src="../images/tag_1.gif"><span style="font-style: italic;">"Custom
Prompter"</span> is the user visible String shown in the list of
available libraries from the <span style="font-style: italic;">Add
Library</span> wizard on the <span style="font-style: italic;">Libraries</span>
tab on the <span style="font-style: italic;">Java build path.&nbsp;</span>
In a commercial quality plugin it is expected this would come from a
resource bundle and be externalized for different locales however this
tutorial will hard code it to the literal <span
style="font-style: italic;">"Custom Prompter"</span>.&nbsp; Once the
user selects a container library to be added and presses <span
style="font-style: italic;">Next</span> a wizard page is brought up
showing configuration details of the particular container.&nbsp; This
wizard page <span style="font-style: italic;">implements
org.eclipse.jdt.ui.wizards.IClasspathContainerPage</span> and for a
commercial quality plugin it is expected that a custom page would be
written.&nbsp; The visual editor SWT container page
org.eclipse.ve.internal.swt.SWTcontainerWizardPage is a good example to
look at if your intention is to create a full wizard page, however the
visual editor provides an example <span style="font-style: italic;">org.eclipse.ve.internal.java.wizard.RegisteredClasspathContainerWizardPage</span>
that can be used <img style="width: 24px; height: 13px;" alt="tag2"
src="../images/tag_2.gif">.&nbsp;&nbsp;<br>
<br>
The container needs an id that uniquely identifies it within an Eclipse
environment and this tutorial uses&nbsp;<img
style="width: 24px; height: 13px;" alt="tag3" src="../images/tag_3.gif"> <span
style="font-style: italic;">org.eclipse.ve.example.PrompterContainer.</span><br>
<br>
The RegisteredClasspathContainerWizardPage will add the container
RegisteredClasspathContainer to the build path of the user's project
once they select it.&nbsp; This is a generic container and to identify
it as being an entry that should point to the runtime files required
for the <span style="font-style: italic;">MyCustomPrompter</span> and
its supporting classes requires two further extension points.&nbsp; If
a specific custom container is being used then these are not required.<br>
<br>
The extension point <span style="font-style: italic;">org.eclipse.jdt.core.classpathContainerInitializer</span>
specificies a container initializer that will be used by the JDT to
configure containers.&nbsp; The following lines should be added to the
plugin.xml for the <span style="font-style: italic;">org.eclipse.ve.examples.customwidget</span>
plugin.</p>
<pre> &lt;extension<br> point="org.eclipse.jdt.core.classpathContainerInitializer"&gt;<br> &lt;classpathContainerInitializer<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> class="org.eclipse.ve.internal.java.core.RegisteredClasspathContainerInitializer"<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> id="org.eclipse.ve.example.PrompterContainer"&gt;<br> &lt;/classpathContainerInitializer&gt;<br> &lt;/extension&gt;<br><br></pre>
<p>The class used is a reference implementation provided by the Visual
Editor and is <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif"> <span style="font-style: italic;">org.eclipse.ve.internal.java.core.RegisteredClasspathcontainerInitializer.&nbsp;</span>
The id used must match the one described earlier as the id of the
container wizard page.&nbsp; This tutorial is using <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> <span
style="font-style: italic;">org.eclipse.ve.example.PrompterContainer.<br>
<br>
</span> Having configured the wizard page and the container initializer
this will now add an instance of the RegisteredClasspathContainer to
the user's build path of their Java project.&nbsp; This needs to be
told where to locate the jars that contain the runtime code.&nbsp;
There is an extension point used by the RegisteredClasspathContainer
class named <span style="font-style: italic;">org.eclipse.ve.java.core.registrations.&nbsp;</span>
To use it add the following lines to the plugin.xml.&nbsp; Note that if
a true container implementation is being done instead then this
extension point is not required - it is only used by the
RegisteredClasspathContainer.&nbsp; For example, the project
org.eclipse.ve.swt that defines the SWT extensions for the visual
editor has its own custom behavior and does not require use of this
extension point.&nbsp;</p>
<pre> &lt;extension<br> point="org.eclipse.ve.java.core.registrations"&gt;<br> &lt;registration<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> container="org.eclipse.ve.example.PrompterContainer"<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> description="Custom Prompter"&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> &lt;<a
name="library_definition"></a>library runtime="customwidgets.jar"/&gt;<br> &lt;/registration&gt;<br> &lt;/extension&gt;<br></pre>
<p>The&nbsp; name of the container must match the id used when the
classpath wizard page and container initializer were defined.&nbsp;
This tutorial is using <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif"> <span style="font-style: italic;">org.eclipse.ve.example.PrompterContainer.&nbsp;&nbsp;</span>
The container needs a description that will appear in the Java build
path list of classpath entries and the tutorial uses the hard coded
literal <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_2.gif"> <span style="font-style: italic;">"Custom
Prompter".&nbsp;</span> The plugin element&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif">
&lt;library runtime="customwidgets.jar".&gt; describes the actual
location of the runtime jars that contain the <span
style="font-style: italic;">MyCustomPrompter</span> class.&nbsp; If
there are multiple jars then the entry can be repeated.&nbsp;&nbsp; The
location of the jar is relative to the plugin itself, so if <span
style="font-style: italic;">customwidgets.jar</span> were in a
directory called <span style="font-style: italic;">jars</span> within
the plugin then the entry would be runtime="jars/.customwidgets.jar".<br>
<br>
Having updated the plugin.xml file to define the classpath container
the next step is to test this.</p>
<h2><a name="Using_a_classpath_container"></a>Using a classpath
container</h2>
<p>Launch the Eclipse Application workbench using the <span
style="font-weight: bold;">Run</span> menu to open the runtime
environment in which the <span style="font-style: italic;">MyCustomPrompter</span>
class can be tested.&nbsp; If you have previously done this and created
a Java project with a build path entry pointing to the <span
style="font-style: italic;">customwidgets.jar</span> as described
earlier remove the jar from the build path.&nbsp; Otherwise create a
new Java project.</p>
<p>The next steps are the experience that a user of the plugin will
take to configure a Java project to work with the <span
style="font-style: italic;">MyCustomPrompter</span> custom
control.&nbsp; Open the properties for the Java project using the <span
style="font-weight: bold;">Properties</span> choice on the pop-up menu
and select <span style="font-style: italic;">Java Build Path.</span><span
style="font-weight: bold;"><span style="font-style: italic;">&nbsp;</span></span>
Select the <span style="font-style: italic;">Libraries</span> tab and
choose the <span style="font-style: italic;">Add Library</span>
button.&nbsp; This will bring up a list of all known Java containers
which will include the <span style="font-style: italic;">Custom
Prompter</span> as defined using the extension point
org.eclipse.jdt.ui.classpathcontainerPage <a
href="#ContainerPageDefinition">earlier.</a> The figure below shows
the Java build path for a project called <span
style="font-style: italic;">Test</span> and the Custom Prompter
displayed in the list of available libraries opened from the <span
style="font-style: italic;">Add Library</span> button</p>
<p><img style="border: 1px solid ; width: 641px; height: 471px;" alt=""
src="images/CustomPrompterContainer.png"></p>
<p>Select the <span style="font-style: italic;">Custom Prompter</span>
and press Next to view the wizard page <span
style="font-style: italic;">org.eclipse.ve.internal.java.wizard.RegisteredClasspathContainerWizardPage</span>
defined <a href="#ContainerPageDefinition">earlier</a>.&nbsp; This is
a generic example of a page and shows details of the jar that will be
added by the page.&nbsp; For commercial quality plugins it is expected
that this page however will be a specific to the particular
plugin.&nbsp;</p>
<p>Pressing Finish on the wizard page will configure the project (using
the RegisteredClasspathcontainerInitializer defined earlier) to include
the container <span style="font-style: italic;">RegisteredClasspathContainer</span>
together with the id of<span style="font-style: italic;">org.eclipse.ve.examples.PrompterContainer.&nbsp;</span>
Expanding the container in the project's build path will show that it
points to the correct location for the customwidgets.jar as described
in the <span style="font-family: monospace;">&lt;library
runtinme="customwidgets.jar"&gt;</span> plugin.xml tag described <a
href="#library_definition">earlier</a>.<br>
<br>
<img style="border: 1px solid ; width: 281px; height: 147px;" alt=""
src="images/TestProjectBuildPath.png"><br>
<br>
<img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;"> The figures above for configuring
the project Test's build path to include the <span
style="font-style: italic;">Custom Prompter</span> container entry
show two other containers, namely the <span style="font-style: italic;">JRE
System library</span> and the <span style="font-style: italic;">Standard
Widget Toolkit.</span>&nbsp;&nbsp; The JRE container will be present on
the Java project by default when it is first created, however the SWT
container will not be.&nbsp; This is a container defined by the plugin
project <span style="font-style: italic;">org.eclipse.ve.swt</span>
that enables the Visual Editor to work with the SWT.&nbsp; If you
created the Test project in the step <a
href="#Testing_MyCustomPrompter">Testing the custom prompter</a>
described earlier when you created the test class using the <span
style="font-style: italic;">New Visual Class Wizard</span>and selected
SWT application the wizard automatically added the SWT container to the
project's build path as required.&nbsp; SWT support for the Visual
Editor can be manually added by using the steps described above but
selecting <span style="font-style: italic;">Standard Widget Toolkiit</span>
instead of <span style="font-style: italic;">Custom Prompter</span> on
the <span style="font-style: italic;">Add Library</span> wizard
page.&nbsp; Adding dependent containers (CustomPrompter requires SWT)
is not something that is supported by the reference implementation of
RegisteredClassPathContainer and it is expected that commercial quality
plugins will provide their own container class with the required logic
to ensure consistency of dependent containers in the user's build path.<br>
<br>
Having configured the Test project to use the <span
style="font-style: italic;">Custom Prompter</span> container you can
now test it by creating an SWT Shell from the <span
style="font-style: italic;">New Visual Class Wizard</span> and
dropping <span style="font-style: italic;">MyCustomPrompter</span>
using the <span style="font-style: italic;">Choose Bean ...</span>
palette entry.&nbsp; the next step is to configure the palette so that
a new category called <span style="font-style: italic;">Custom</span>
is added that has an entry for the <span style="font-style: italic;">MyCustomPrompter</span>
class.</p>
<h2><a name="Adding_a_palette_category_for_our_widget">Adding a palette
category for MyCustomPrompter</a></h2>
<p>The visual editor's palette is described by an EMF model.&nbsp; EMF
serializes to&nbsp; <a
href="http://www.omg.org/technology/documents/formal/xmi.htm">XMI</a>
which is an XML representation of a graph of EMF objects.&nbsp; Plugins
can define their own XMI files that describe the categories to be added
to the palette, the groups these belong to, and the actual entries
themselves.&nbsp; For the org.eclipse.ve.examples.customwidgets plugin
there will be a palette XMI file that describes the single category and
class to add.<br>
<br>
Create a file called customprompter.xmi in the plugin and open it with
a text editor.&nbsp; The data for the file is shown below and can be
downloaded directly from <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/customprompter.xmi">
CVS</a> to avoid re-entry.<br>
<br>
</p>
<pre> &lt;xmi:XMI xmi:version="2.0"<br> xmlns:xmi="http://www.omg.org/XMI"<br> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" <br> xmlns:palette="http:///org/eclipse/ve/internal/cde/palette.ecore"<br> xmlns:utility="http:///org/eclipse/ve/internal/cde/utility.ecore"&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> &lt;palette:CategoryCmp&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> &lt;categoryLabel xsi:type="utility:ConstantString" string="Custom"/&gt;<br> &lt;cmpGroups xsi:type="palette:GroupCmp"&gt;<br><br><img
style="width: 23px; height: 13px;" alt="" src="../images/tag_3.gif"> &lt;cmpEntries xsi:type="palette:AnnotatedCreationEntry" xmi:id="entry2" icon16Name="platform:/plugin/org.eclipse.ve.example.customwidget/icons/custom.gif"&gt;<br> &lt;objectCreationEntry xsi:type="palette:EMFCreationToolEntry"<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif"> creationClassURI<b>=</b>"java:/org.eclipse.ve.example.customwidget.prompter#MyCustomPrompter"/&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif"> &lt;entryLabel xsi:type="utility:ConstantString" string="Prompter"/&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_6.gif"> &lt;values xmi:type="ecore:EStringToStringMapEntry" key="org.eclipse.ve.internal.cde.core.nameincomposition" value="customPrompter"/&gt; <br> &lt;/cmpEntries&gt;<br><br> &lt;/cmpGroups&gt;<br> &lt;/palette:CategoryCmp&gt;<br> &lt;/xmi:XMI&gt;<br></pre>
<p>The&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif"> &lt;palette:categoryCmp&gt; tag describes a
palette category that has a label and groups, each group containing a
number of entries.&nbsp; In the example for the tutorial the label is
hard coded to the literal&nbsp;<img style="width: 24px; height: 13px;"
alt="" src="../images/tag_2.gif"> <span style="font-style: italic;">"Custom".&nbsp;</span>
<img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;"> For
a plugin that needed to support different language locales there is an
EMF class utility:TranslatableString and examples of its usage can be
found in the palette files for the plugin org.eclipse.ve.jfc.<br>
<br>
A single group is defined for the Custom category.&nbsp; If multiple
groups are defined the palette demarks these visually with a
separator.&nbsp; The group has a single entry that defines the&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif">
graphic, the qualified&nbsp;<img style="width: 24px; height: 13px;"
alt="" src="../images/tag_4.gif"> name of the class and the literal <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif">
string that is displayed on the palette entry.&nbsp; To ensure that a
good default name is used each time the user drops an instance of the
CustomPrompter a&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_6.gif"> default <span style="font-style: italic;">nameincomposition
</span>is specified to be "customPrompter". &nbsp; The&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif">
graphic points to the URL of where the image is located, in this case
the entry points to a file <span style="font-style: italic;">custom.gif</span>
in the <span style="font-style: italic;">icons</span> directory of the
plugin called <span style="font-style: italic;">org.eclipse.ve.example.customwidget.&nbsp;</span>
The graphic used&nbsp;<img style="width: 16px; height: 16px;" alt=""
src="images/custom.gif"> is available in <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/icons/custom.gif">CVS</a>
and you will
need to create a folder called <span style="font-style: italic;">icons</span>
in the plugin and copy it there.<br>
<br>
<img style="border: 1px solid ; width: 264px; height: 148px;" alt=""
src="images/IconsFolder.png"></p>
<p><img src="../images/tip.gif" alt="Tip:"
style="width: 62px; height: 13px;">
Because XMI files do not have anything to validate them at design time
errors made in their syntax can easily be made that cause runtime
problems that can be hard to trace and debug.&nbsp; The most
straightforward way to write a Visual Editor XMI file is to copy an
existing one that is similar to what you desire and then alter just the
parts that need changing.</p>
<p>Having created the <span style="font-style: italic;">customprompter.xmi</span>
file we need to enable the Visual Editor to use it.&nbsp; This is done
by associating the palette file with a classpath container, in our case
the Custom Prompter.&nbsp;</p>
<p>Now that we have our palette xmi file available, we need to
contribute it to the Visual Editor.&nbsp; We do so by adding to the
following extension in the plugin's&nbsp; <span
style="font-style: italic;">plugin.xml</span> manifest
file.</p>
<pre> &lt;extension<br><img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif"> point="org.eclipse.ve.java.core.contributors"&gt;<br> &lt;palette<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> container="org.eclipse.ve.example.PrompterContainer"<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> categories="<b>customprompter.xmi</b>"/&gt;<br> &lt;/extension&gt; <br></pre>
<p>The extension point used is&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> <span
style="font-style: italic;">org.eclipse.ve.java.core.contributors.</span>
This has a &lt;palette&gt; child XML tag that points to the id of
the&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_2.gif"> container whose inclusion in a project's
build path causes the palette categories defined in the&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif">
categories tag to be included. The palette categories tag is relative
to the root of the plugin project, for example If the palette XMI file
is in a folder called <span style="font-style: italic;">palette</span>
then the entry would be <span style="font-family: monospace;">categories="palette/customprompter.xmi".</span></p>
<p>When the Visual Editor starts it scans all of the project's build
path entries and for any that are containers it looks to see whether
there are any palette files.&nbsp; These are combined together to
create the overall palette.</p>
<p><img style="width: 63px; height: 13px;" src="../images/note.gif"
alt="Note:"> As well as describing palette entries directly it is
possible to configure the Visual Editor to have an <font
face="Courier New">IConfigurationContribution</font> that has the
ability to manipulate both the -classpath of the Visual Editor's VM and
the palette with more fine control.&nbsp; An example of where this is
done is by SWT that has to add runtime packages such as DLLs or
packages to the VM's arguments, or a plugin that might wish to remove
some of the existing palette entries (such as the JFC ones) for
projects configured with their container present.</p>
<p><img style="height: 13px; width: 62px;" alt="Tip:"
src="../images/tip.gif"> As
well as defining containers to be the trigger point for Visual Editor
custom behavior you can also use plugins by direct name&nbsp;using the <span
style="font-style: italic;">plugin=</span> tag. An example of where
you might do this is if you were extending the Visual Editor to work
with a set of classes that were contained in a specific plugin, so the
user experience to enable a Java project would be to add a dependent
plugin rather than a classpath container.&nbsp; An example of this
might be something like a PDE type development environment for the
actual end user.</p>
<h3><a name="Testing_the_custom_palette"></a>Testing the custom palette</h3>
<p>Having modified the manifest of the example plugin to include the
plugin the next step is so test it.&nbsp; Do this by launching the
Eclipse Application workbench and creating, or re-opening, a class <font
face="Courier New">MyShell</font> that was created from the <span
style="font-style: italic;">New Visual Class <span
style="font-style: italic;">Wizard</span></span> as an SWT
application.&nbsp; The Visual Editor should detect that the container
with an id of <span style="font-style: italic;">org.eclipse.ve.example.PrompterContainer</span>
is in the project's build path and include the palette categories
contained in the <span style="font-style: italic;">custompalette.xmi</span>
file.&nbsp; This is shown in the figure below where the Prompter
palette entry has been selected and dragged out onto the Shell.&nbsp;<br>
<br>
<img style="border: 1px solid ; width: 758px; height: 396px;" alt=""
src="images/CustomPalette.png"><br>
<br>
<img src="../images/tip.gif" alt="Note:" style="height: 13px; width: 62px;">
When
you launch the Eclipse Application workspace use the <span
style="font-style: italic;">-clean</span> option, as each time the <span
style="font-style: italic;">plugin.xml</span> manifest file has
changed we need to be sure the runtime Eclipse environment clears its
cached manifest details<br>
<br>
At this point in the tutorial you should have defined a classpath
container that the user can configure a Java project with to include
the jar containing the runtime code for the <span
style="font-style: italic;"><span style="font-style: italic;"><span
style="font-style: italic;">MyCustomPrompter</span></span></span>
class.&nbsp; The extension point <span style="font-style: italic;">org.eclipse.ve.java.core.contributors</span>
has been used to point to the location of a palette XMI file that
contains a category with an entry for the class.<br>
<br>
The next steps are to configure the Visual Editor so that <span
style="font-style: italic;">MyCustomPrompter</span> has custom
behavior over and above that it inherits by virtue of extending <span
style="font-style: italic;">org.eclipse.swt.widgets.Composite</span>.</p>
<h2><a name="Using_an_ENUM_cell_editor">Enumerated values for the <span
style="font-style: italic;">type</span> property</a></h2>
<p><span style="font-family: monospace;">MyCustomPrompter</span> class
has an <i>int</i> property named <i style="font-weight: bold;">type</i>with
<i>getType</i>() and <i>setType</i>(int aType) methods.&nbsp; While
the signature of <i>setType</i> allows it to accept any int, the class
itself only works with one of the three values 0, 1, or 2 The
definition of the values is held in three static constants on the <span
style="font-family: monospace;">MyPrompterClass</span>.</p>
<pre><span style="color: rgb(153, 0, 0);">public final static int</span> <span
style="font-style: italic; color: rgb(51, 51, 255);">DOTS</span> = 0;<br><span
style="color: rgb(153, 0, 0);">public final static int</span> <span
style="color: rgb(51, 51, 255); font-style: italic;">MORE</span> <span
style="font-style: italic;">=</span> 1;<br><span
style="color: rgb(153, 0, 0);">public final static int</span> <span
style="color: rgb(51, 51, 255); font-style: italic;">OPEN</span> = 2;<br></pre>
<p>The significance of the three values is that they alter the button
text for <span style="font-family: monospace;">MyCustomPrompter to</span>
be either "...", "More", or "Open" respectively.&nbsp;&nbsp; The
following code shows this for <span style="font-family: monospace;">MyCustomPrompter</span>'s
<span style="font-family: monospace;">setType(int type)</span> method.</p>
<pre><span style="color: rgb(153, 0, 0);">public void</span> setType (<span
style="color: rgb(153, 0, 0);">int</span> type) {<br> <span
style="color: rgb(153, 0, 0);">switch</span> (type) {<br> <span
style="color: rgb(153, 0, 0);">case</span> <span
style="font-style: italic; color: rgb(51, 51, 255);">DOTS</span>: button.setText(<span
style="color: rgb(51, 51, 255);">"..."</span>);<br> <span
style="color: rgb(153, 0, 0);">break</span>;<br> <span
style="color: rgb(153, 0, 0);">case</span> <span
style="font-style: italic; color: rgb(51, 51, 255);">MORE</span>: button.setText(<span
style="color: rgb(51, 51, 255);">"More"</span>);<br> <span
style="color: rgb(153, 0, 0);">break</span>;<br> <span
style="color: rgb(153, 0, 0);">case</span> <span
style="font-style: italic; color: rgb(51, 51, 255);">OPEN</span>: button.setText(<span
style="color: rgb(51, 51, 255);">"Open"</span>);<br> <span
style="color: rgb(153, 0, 0);">break</span>;<br> <span
style="color: rgb(153, 0, 0);">default</span>:<br> <span
style="color: rgb(153, 0, 0);">throw new</span> IllegalArgumentException(<span
style="color: rgb(51, 51, 255);">"Value "</span> + type + <span
style="color: rgb(51, 51, 255);">" must be one of 0, 1 or 2"</span>);<br> }<br>}<br></pre>
<p>Whenever a class is selected in the Visual Editor graphical canvas
or Java Beans tree viewer the Properties view will show its properties
and their current values.&nbsp; The view can also be used to edit the
property values, and the Visual Editor has a number of pre-defined
editors associated with specific types.&nbsp; <span
style="font-style: italic;">int</span> properties for example have an
editor that allows only valid <span style="font-style: italic;">int</span>
values to be entered and by default the Visual Editor will use this
whenever the <span style="font-style: italic;">type</span> property is
selected based on its signature.</p>
<p>This step of the tutorial describes how to override the default
behavior so that the <span style="font-style: italic;">type</span>
property is edited using a drop down list of the three allowable
values.&nbsp; Also, instead of the values 0, 1 and 2 being displayed as
the current values the literals "Dots", "More" and "Open" will be used
instead.&nbsp; This is described as an objective of the tutorial in the
<a href="#Introduction">Introduction</a>.</p>
<p>To override the behavior of the <span style="font-style: italic;">type</span>
property so that it has the desired behavior involves using a BeanInfo
class.&nbsp; BeanInfo classes provide a way to describe a classes'
design time behavior and art part of the <a
href="http://java.sun.com/products/javabeans/reference/api/index.html">JavaBeans
specification</a>.&nbsp; The Visual Editor uses the JavaBeans
specification wherever possible to define edit time behavior for a
JavaBean.&nbsp;</p>
<p>The BeanInfo specification allows for a class with the same name as
its Java peer to exist that describes the edit time behavior of the
class.&nbsp; For example, the tutorial class is named <span
style="font-family: monospace;">MyCustomPrompter</span> so there would
be a class <span style="font-family: monospace;">MyCustomPrompterBeanInfo</span>
that implements the interface <span style="font-family: monospace;">java.beans.BeanInfo</span>
associated with it.&nbsp; The simplest way to create this class is to
put it in the same package as the class it describes (e.g. <span
style="font-family: monospace;">org.eclipse.ve.example.customwidget</span>)
.&nbsp; Strictly speaking this isn't good physical separation of
behaviors as the BeanInfo classes should be kept apart from the runtime
in a separate package and separate jar so they don't become part of the
end user's actual deployment configuration.&nbsp; The Visual Editor
does support scenarios where the BeanInfo is in separate packages and
separate jars, however for the purpose of this tutorial the class <span
style="font-family: monospace;">org.eclipse.ve.examples.customwidget.MyCustomPrompterBeanInfo</span>
will be created that extends the abstract superclass <span
style="font-family: monospace;">java.beans.SimpleBeanInfo</span>.</p>
<p>The full source code for the BeanInfo can be downloaded from <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/src/org/eclipse/ve/example/customwidget/prompter/MyCustomPrompterBeanInfo.java">
CVS.</a>&nbsp; A BeanInfo class is responsible for describing the list
of properties used by a tool such as the Visual Editor, and also their
edit time behavior.&nbsp; This is done by specializing the method <span
style="font-family: monospace;">PropertyDescriptor[]
getPropertyDescriptors()</span>.&nbsp; The method returns an array of <span
style="font-family: monospace;">java.beans.PropertyDescriptor</span>
objects, each one representing an item that will appear as a row in the
Properties view and containing information about its display name, the
Java get and set method associated with the property, as well as the
rules for how the property shoud be edited.&nbsp; The specification
allows support for editing behavior is provided by having a <span
style="font-family: monospace;">java.beans.PropertyEditor</span>
defined against the <span style="font-family: monospace;">PropertyDescriptor</span>,
and while the Visual Editor will work correctly if a <span
style="font-family: monospace;">PropertyEditor</span> class has been
defined it also supports a shorthand notation for describing a list of
enumerated values because this pattern occurs frequently in widget
libraries (for example orientation properties on scroll bars, alignment
values on layout constraints, etc...) and is the pattern used by the
MyCustomPrompter's <span style="font-style: italic;">type</span>
property.&nbsp; This shorthand notation involves defining a key value
pair on the PropertyDescriptor, the key of which is the string literal <span
style="font-style: italic;">enumerationValues</span> and the value of
which is an array of tri values.&nbsp; The structure of the array is a
repeating set of <span style="font-weight: bold;">displayName, value,
initializationString</span>.&nbsp; The displayName is the user visible
string shown to the user in the Properties view, the value is the
actual object that identifies the trivalue against a live property
setting, and the initializationString is the fully qualified code
fragment that is generated as argument to the property's set
method.&nbsp; This is illustrated below in the method <span
style="font-family: monospace;">getPropertyDescriptors()</span> for
the class <span style="font-family: monospace;">MyCustomPrompterBeanInfo</span>.</p>
<pre> <span style="color: rgb(153, 0, 0);">public</span> PropertyDescriptor[] getPropertyDescriptors() {<br><br> <span
style="color: rgb(153, 0, 0);">try</span> {<br> PropertyDescriptor[] result = <span
style="color: rgb(153, 0, 0);">new</span> PropertyDescriptor[2];<br><br> result[0] = <span
style="color: rgb(153, 0, 0);">new</span> PropertyDescriptor(<span
style="color: rgb(51, 51, 255);">"text"</span>,MyCustomPrompter.class);<br> result[1] = <span
style="color: rgb(153, 0, 0);">new</span> PropertyDescriptor<span
style="font-weight: bold;">(<span style="color: rgb(51, 51, 255);">"type"</span></span>,MyCustomPrompter.class);<br><br> result[1].setValue(<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"><span
style="color: rgb(51, 51, 255);">"enumerationValues"</span>, <span
style="color: rgb(153, 0, 0);">new</span> Object[] {<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> <span
style="color: rgb(51, 51, 255);">"Dots"</span>, <span
style="color: rgb(153, 0, 0);">new</span> Integer(MyCustomPrompter.<span
style="color: rgb(51, 51, 255); font-style: italic;">DOTS</span>), <span
style="color: rgb(51, 51, 255);">"org.eclipse.ve.example.customwidget.prompter.MyCustomPrompter.DOTS"</span>,<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> <span
style="color: rgb(51, 51, 255);">"More"</span>, <span
style="color: rgb(153, 0, 0);">new</span> Integer(MyCustomPrompter.<span
style="color: rgb(51, 51, 255); font-style: italic;">MORE</span>), <span
style="color: rgb(51, 51, 255);">"org.eclipse.ve.example.customwidget.prompter.MyCustomPrompter.MORE"</span>,<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif"> <span
style="color: rgb(51, 51, 255);">"Open"</span>, <span
style="color: rgb(153, 0, 0);">new</span> Integer(MyCustomPrompter.<span
style="color: rgb(51, 51, 255); font-style: italic;">OPEN</span>), <span
style="color: rgb(51, 51, 255);">"org.eclipse.ve.example.customwidget.prompter.MyCustomPrompter.OPEN"</span> <br> });<br> <br> <span
style="color: rgb(153, 0, 0);">return</span> result;<br> } <span
style="color: rgb(153, 0, 0);">catch</span> (IntrospectionException e) { <br> e.printStackTrace();<br> <span
style="color: rgb(153, 0, 0);">return null</span>;<br> }<br>}<br></pre>
<p>The getPropertyDescriptors() method returns an array of two
properties; <span style="font-style: italic;">text</span> and <span
style="font-style: italic;">type.&nbsp;</span> The <span
style="font-style: italic;">type</span> property has a key value pair
assigned to it with a key of <img style="width: 24px; height: 13px;"
alt="" src="../images/tag_1.gif"> <span style="font-style: italic;">enumerationValues</span>
and a value that is an array of nine elements.&nbsp; These nine
elements represent the three enumerated values defined as a
tri-values.&nbsp; The first of these is for the value 0 and is defined
as <span style="font-weight: bold;">displayName,value,initString</span>
of&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_2.gif"> "Dots", 0, "0".&nbsp; Instead of hard
coding the 0 however they are coded to be the dynamic lookups of the
actual value from the static constant, allowing the constant to
internally change without requiring BeanInfo modification.&nbsp; The
other two values <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_3.gif"> "More" and <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif">
"Open" are defined as tri-values for the 4th, 5th and 6th elements of
the array and the 7th, 8th and 9th respectively.</p>
<p>The <span style="font-family: monospace;">getPropertyDescriptors()</span>
method returns a fully inclusive set of property descriptors for the
JavaBean.&nbsp; For <span style="font-family: monospace;">MyCustomPrompter</span>
the user experience the tutorial wants is that the inherited properties
such as background, foreground, size, etc.. are present on the
class.&nbsp; To achieve this rather than having the <span
style="font-family: monospace;">getPropertyDescriptors()</span> method
collect the full list of all desired properties, the JavaBeans
specification allows for the method <span
style="font-family: monospace;">BeanInfo[] getAdditionalBeanInfo()</span>
to be specialized.&nbsp; This returns an array of <span
style="font-family: monospace;">BeanInfo</span> classes whose
properties are merged together with the result of <span
style="font-family: monospace;">getPropertyDescriptors()</span> to
create the complete list.</p>
<pre> <span style="color: rgb(153, 0, 0);">public</span> BeanInfo[] getAdditionalBeanInfo(){<br> <span
style="color: rgb(153, 0, 0);">try</span>{<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> <span
style="color: rgb(153, 0, 0);">return new</span> BeanInfo[]{Introspector.<span
style="font-style: italic;">getBeanInfo</span>(Control.<span
style="color: rgb(153, 0, 0);">class</span>)};<br> } <span
style="color: rgb(153, 0, 0);">catch</span> (IntrospectionException e){<br> <span
style="color: rgb(153, 0, 0);">return new</span> BeanInfo[0];<br> }<br></pre>
<img src="../images/tip.gif" alt="Note:" style="width: 62px; height: 13px;">
<p>To create the array of BeanInfo classes representing the set of
descriptors to merge one technique might be to write the code <span
style="font-family: monospace;"><span style="color: rgb(153, 0, 0);">return
new</span> BeanInfo[] {CompositeBeanInfo.<span
style="color: rgb(153, 0, 0);">class</span>, ControlBeanInfo.<span
style="color: rgb(153, 0, 0);">class</span>, WidgetBeanInfo.<span
style="color: rgb(153, 0, 0);">class</span>}</span>.&nbsp; However
doing so would be an attempt to hard code the names of the BeanInfo
classes that may currently be associated with the superclass chain of <span
style="font-family: monospace;">MyCustomPrompter</span> but would fail
if new BeanInfo classes were introduced or removed.&nbsp; The preferred
technique for picking up inherited properties is with the statement <span
style="font-family: monospace;"><span style="color: rgb(153, 0, 0);">return
new</span> BeanInfo[]{Introspector.<span style="font-style: italic;">getBeanInfo</span>(Composite.<span
style="color: rgb(153, 0, 0);">class</span>)}</span> where the
argument to the <span
style="font-style: italic; font-family: monospace;">getBeanInfo</span><span
style="font-family: monospace;">(Class aClass)</span> method is the
current bean's superclass.&nbsp; Rather than using <span
style="font-family: monospace;">Composite</span> as the starting point
for merging inherited properties which is the immediate superclass of <span
style="font-family: monospace;">MyCustomPrompter</span>, <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif">&nbsp;
<span style="font-family: monospace;">Control</span> is used
instead.&nbsp; The reason for this is that while <span
style="font-family: monospace;">MyCustomPrompter</span> extends <span
style="font-family: monospace;">Composite</span> it does this more for
physical reasons so it can have its three child controls (the <span
style="font-family: monospace;">Label</span>, <span
style="font-family: monospace;">Text</span> and <span
style="font-family: monospace;">Button</span>), however as a black box
custom class it itself doesn't want to inherit the behavior of <span
style="font-family: monospace;">Composite</span> such as the ability
to have its layout changed.&nbsp; For this reason it is logically a
subclass of <span style="font-family: monospace;">Control.</span></p>
<h3><a name="Testing_the_enumerated_values_for_type"></a>Testing the
enumerated values for <span style="font-style: italic;">type</span></h3>
<p>Having updated <span style="font-family: monospace;">MyCustomPrompterBeanInfo.java</span>
this must be re-exported to the <span style="font-style: italic;">customwidgets.jar</span>
file.&nbsp; The customwidgets.jar in the plugin is the one that the <span
style="font-style: italic;">Custom Prompter</span> classpath container
uses in its build path, and if the step of re-creating the <span
style="font-style: italic;">customwidgets.jar</span> file is not done
when you launch the Eclipse Application you will be using the old
version of the code.&nbsp; Currently Eclipse 3.1 does not support
classpath container entries pointing to folder structures otherwise the
RegisteredClassPathContainer could be coded to automatically look back
into the directory structure of the development environment that
launched it so for now don't forget to keep re-creating the <span
style="font-style: italic;">customwidgets.jar</span> file each time
any of its contents have changed.</p>
<img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;">
<p>The Visual Editor caches information about a class and under some
builds prior to VE 1.1 there are some issues with the cache going stale
and not being automatically refreshed.&nbsp; If this occurs you can
manually recycle the cache by selecting <span
style="font-weight: bold;">Project &gt; Clean</span> and also manually
removing the directory <span style="font-style: italic;">org.eclipse.ve.beaninfo/cache</span>
from the workbench directory.&nbsp;<br>
<br>
The changes to the <span style="font-family: monospace;">MyCustomPrompterBeanInfo</span>
should mean that the <span style="font-style: italic;">type</span>
property is now rendered with its display name rather than just the raw
<span style="font-family: monospace;">int</span> value.&nbsp; The
Properties view also will create a drop down list of the three
allowable values.&nbsp; The figure below shows the list of the three
values and when one is selected the argument to the <span
style="font-family: monospace;">setType(int)</span> method will be
generated with the initializationString as defined in the <span
style="font-family: monospace;">BeanInfo</span> array.<br>
<br>
<br>
<img style="border: 1px solid ; width: 808px; height: 527px;" alt=""
src="images/TypeCodeGeneration.png"><br>
<br>
The BeanInfo mechanism provides one technique to override default edit
behavior for a Java class.&nbsp; The Visual Editor uses BeanInfo
classes internally for many of its customizations and it recognizes
externally created BeanInfo classes according to the JavaBeans
specification.<br>
<br>
Some kinds of customization are not possible through the BeanInfo
mechanism because while it provides a powerful way to describe edit
time behavior and shape for a class the Visual Editor needs to be able
to export some of its innermost extension points to the creator of the
Java class, and the BeanInfo mechanism is designed to provide a
portable way of customizing a Java class that can be transported easily
between different IDEs and tools.&nbsp; For example, the next exercise
in the tutorial is to override the behavior that occurs when the <span
style="font-style: italic;">text</span> property is edited to launch a
dialog editor.&nbsp; This dialog editor will be written using the SWT
and implement Eclipse specific interfaces, so describing it on the
BeanInfo would violate the idea that BeanInfo classes are portable (as
Eclipse interfaces and the SWT are not necessarily available to other
visual design tools).<br>
<br>
For this reason the Visual Editor has a separate mechanism to extend a
class's edit time behavior that is done through <span
style="font-style: italic;">override</span> files<span
style="font-style: italic;">.</span> This works in conjunction with
the BeanInfo mechanism and provides the ability to leverage any Eclipse
IDE or Visual Editor specific behavior for a class.</p>
<h2><a name="The_EMF_override_mechanism"></a>The EMF override mechanism</h2>
<p>At the heart of the Visual Editor is an EMF model that describes a
class being edited.&nbsp; This model describes the instances, their
relationships, scope, and property settings. Instances of objects in
this model implement <span style="font-family: monospace;">org.eclipse.jem.internal.instantiation.base.IJavaInstance</span>.&nbsp;
For example, a visual editor class that has a <span
style="font-family: monospace;">Shell</span> whose size is 200,200
will contain two <span style="font-family: monospace;">IJavaInstance</span>
objects.&nbsp; The first of these is for the <span
style="font-family: monospace;">Shell</span> itself and the second is
for a <span style="font-family: monospace;">Point</span> representing
the size.&nbsp; An EMF relationship between the <span
style="font-family: monospace;">Shell</span> and the <span
style="font-family: monospace;">Point</span> instance will exist whose
structural feature represents the size property.<br>
<br>
EMF is a self describing structure, so behind the instance model there
is a meta-model that describes the classes themselves - their methods,
properties, events and hierarchy. The meta-model is created by the
Visual Editor using a combination of reflection and JavaBeans
Introspection.&nbsp; Instances in this metamodel consist of <span
style="font-family: monospace;">org.eclipse.jem.java.JavaClass</span>&nbsp;
for each Java class.&nbsp; The structural features in the model are
instances of EReference and represent the properties of the Java class.</p>
<p>There are times when it is necessary to provide additional
information that should be merged in with the EMF model of a
JavaClass.&nbsp; An example of this is a new feature has to be added
over and above those that can be determined by reflection.</p>
<p>The Visual Editor uses the EMF model of a JavaClass not only to
define its shape but also to define a number of helper classes used by
the Visual Editor.&nbsp; These are typically mediator classes that are
used by the different Visual Editor subsystems.&nbsp; The names of the
mediator classes to use for a given JavaClass are held in the EMF
model, thereby allowing specific classes to have custom behavior for
each subsystem.&nbsp; Rather than hold these directly against the
JavaClass (which is a generic model of Java classes that can be used by
Eclipse plugins other than the Visual Editor)&nbsp; they are held
against decorator classes that annotate the descriptive information of
a class.&nbsp; These can be thought of similar to key value pairs that
hold information rather than provide functionality.&nbsp;</p>
<p>In summary, override files are used as means to modify, add to or
delete from an EMF JavaClass whose shape is determined through using
standard Java reflection combined with BeanInfo introspection.</p>
<p>For a plugin to contribute override files its plugin manifest must
implement the extension point <span style="font-style: italic;">org.eclipse.jem.beaninfo.registrations</span>.&nbsp;
This specifies the trigger in the build path that will cause the
overrides to be applied (either a classpath container or pre-requisite
project) as well as the name of a Java package and where override files
for its contents are held within the plugin folder structure.&nbsp; The
code below shows the extension used for the plugin.xml for the <span
style="font-style: italic;">org.eclipse.ve.examples.customwidget</span>
example in this tutorial.</p>
<pre> &lt;extension<br> point="org.eclipse.jem.beaninfo.registrations"&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> &lt;registration container="org.eclipse.ve.example.PrompterContainer"&gt;<br> &lt;override<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> package="org.eclipse.ve.example.customwidget.prompter"<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> path="overrides/org/eclipse/ve/example/customwidget/prompter"&gt;<br> &lt;/override&gt;<br> &lt;/registration&gt;<br> &lt;/extension&gt;<br></pre>
<p>The classpath container with an id of <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> is
the one used by the <span style="font-style: italic;">Custom Prompter</span>
library.&nbsp; The class being overriden is <span
style="font-family: monospace;">org.eclipse.ve.example.customwidget.prompter.MyCustomPrompter</span>
so its<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_2.gif"> package is declared together with&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> a
folder location for where the override files will be stored.&nbsp; The
location of the override folder is up to the creator of the plugin and
is any arbitrary folder, however there is a convention that the Visual
Editor uses where override files are held in a top level folder called <span
style="font-style: italic;">overrides</span> and then sub folders
created for the package path. &nbsp; The Figure below shows the
directory structure of the <span style="font-style: italic;">org.eclipse.ve.example.customwidget</span>
plugin with the folder structure of <span style="font-style: italic;">/overrides/org/ecliose/ve/example/customwidget/prompter</span>
(which matches that defined in the registration path=<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif">
extension point).&nbsp;</p>
<p><img style="border: 1px solid ; width: 361px; height: 253px;" alt=""
src="images/OverrideFileStructure.png"></p>
<p>The Figure also shows a file <font face="Courier New">MyCustomPrompter.override</font>
present in the override directory for the package.&nbsp; When the
Visual Editor builds up the EMF JavaClass instance representing the
shape of the MyCustomPrompter class this file will be read and merged
into the definition.&nbsp; The syntax of this file can become complex
due to the number of different ways in which different JavaClasses
needed to be leveraged to implement custom functionality.&nbsp;&nbsp;
The remainder of the three examples in this tutorial are each achieved
through settings in the .override file.&nbsp; These are:</p>
<ul>
<li>Custom cell editing for the text property</li>
<li>Overriding a GEF edit part</li>
<li>Overriding an expression decoder</li>
</ul>
<p>Each of these three is done through adding decorator classes.&nbsp;
Decorator classes are added to ECore elements in the EMF model
representing a class, either the JavaClass itself or an EReference
representing one of its structural features&nbsp;&nbsp; Decorators are
added through the &lt;annotations&gt; property of an ECore object.</p>
<p>The type <span style="font-family: monospace;">org.eclipse.ve.internal.cde.decorators.BasePropertyDecorator</span>
is responsible for specifying property sheet information such as the
name of the classes for the JFace label provider or cell editor, or
whether the entry in the property sheet should override the default
behavior for whether it is expandable, whether null values are allowed,
etc...</p>
<p>The type <span style="font-family: monospace;">org.eclipse.ve.internal.cde.decorators.ClassDescriptorDecorator</span>
is responsible for specifying custom GEF behavior such as custom edit
parts for the graphical editor or the Java Beans tree view.</p>
<h2><a name="Creating_A_SWT_cell_editor">Custom cell editing for the <span
style="font-style: italic;">text</span> property</a></h2>
<p>Because <span style="font-family: monospace;">MyCustomPrompterBeanInfo</span>
returns a <span style="font-style: italic;">text <span
style="font-family: monospace;">PropertyDescriptor</span></span> <span
style="font-family: monospace;"><span
style="font-family: arial,helvetica,geneva;">in</span></span> list of
properties from the method <span style="font-family: monospace;">getPropertyDescriptors()[]</span>
it will be included as an entry in the Properties view.&nbsp; Even
without the explicit BeanInfo the class's signature includes the two
methods <span style="font-family: monospace;"><span
style="color: rgb(153, 0, 0);">public</span> String getText()</span>
and <span style="font-family: monospace; color: rgb(153, 0, 0);">public</span>
<span style="font-family: monospace;">void setText(String aText)</span>
which, because they follow the JavaBeans specification naming
convention for a property's get and set methods, would be automatically
detected by the Visual Editor through Introspection.</p>
<p>The rules for the Properties view is that for a given property a
BasePropertyDecorator is first looked for on the EReference
representing the property in the EMF model.&nbsp; If one is found and
it has an explicit labelProviderClassName or cellEditorClassName then
this is used as appropiate.&nbsp; This is the mechanism that will be
used for the <span style="font-style: italic;">text</span>
property.&nbsp; If no decorator exists in the property defining an
editor then if the EReference came originally through introspection the
java.beans.PropertyDescriptor is queried to look for a
propertyEditorClass or key of <span style="font-style: italic;">enumerationValues.&nbsp;</span>
Failing both of these a default editor is used for the type of the
property.</p>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;">
To determine the default editor for a property based on its type a <span
style="font-family: monospace;">BasePropertyDecorator</span> on the <span
style="font-family: monospace;">JavaClass</span> EMF definition is
used.&nbsp; If no direct decorator can be found annotating the <span
style="font-family: monospace;">JavaClass</span> then the superclass
chain is searched to look for a decorator that provides a custom cell
editor or label provider. For example, the <span
style="font-style: italic;">text</span> property is typed to <span
style="font-family: monospace;">java.lang.String</span> and the plugin
<span style="font-style: italic;">org.eclipse.ve.java.core</span>
provides a <span style="font-style: italic;">String.override</span>
file that annotates the <span style="font-family: monospace;">JavaClass</span>
with a a <span style="font-family: monospace;">BasePropertyDecorator</span>
defining the label provider as <span style="font-family: monospace;">org.eclipse.ve.internal.java.core.StringJavaLabelProvider</span>
and the cell editor as <span style="font-family: monospace;">org.eclipse.ve.internal.java.core.StringJavaCellEditor.</span>&nbsp;
This is an example of where the Visual Editor's implementations of the
JFC and SWT are done thoroughly using its own API.</p>
<p>The cell editor that will be written for the <span
style="font-style: italic;">text</span> property will be placed in the
package <span style="font-family: monospace;">org.eclipse.ve.example.customwidget</span>.&nbsp;
This package will form part of the contents of the plugin jar that
makes up the code that runs in the workbench and extends the Visual
Editor with new Eclipse workbench behavior.&nbsp; The class created is <span
style="font-family: monospace;">org.eclipse.ve.example.customwidget.CustomLabelEditor</span>
and extends the abstract superclass <span
style="font-family: monospace;">org.eclipse.jface.viewers.DialogCellEditor</span>.&nbsp;</p>
<p>IDE specific extensions are defined by annotating the EMF JavaClass
meta object that the Visual Editor uses.&nbsp; This is done with a
.override file, and the contents of <span style="font-style: italic;">MyCustomPrompter.override</span>
should be written as follows:</p>
<pre> &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> &lt;xmi:XMI xmi:version="2.0" <br> xmlns:xmi="http://www.omg.org/XMI" <br> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br> xmlns:org.eclipse.ve.internal.cde.decorators="http:///org/eclipse/ve/internal/cde/decorators.ecore"<br> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" <br> xmlns:event="event.xmi"&gt;<br><br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> &lt;event:Add featureName="eStructuralFeatures"&gt;<br> &lt;addedEObjects xsi:type="ecore:EReference" <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif">name="text" unsettable="true"&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif"> &lt;eAnnotations<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif"> xsi:type="org.eclipse.ve.internal.cde.decorators:BasePropertyDecorator" <br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_6.gif"> cellEditorClassname="org.eclipse.ve.example.customwidget/org.eclipse.ve.example.customwidget.CustomLabelEditor"/&gt;<br> &lt;/addedEObjects&gt;<br> &lt;/event:Add&gt;<br><br> &lt;/xmi:XMI&gt;<br></pre>
<p>The header of a .override file declares the namespaces of the EMF
packages used.&nbsp; Two packages are required to define the objects
required for the CustomLabelEditor, the&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif">
decorators.ecore package and the event model's package.</p>
<p>The purpose of the file is to create a BasePropertyDecorator that
defines the cell editor and annotate the structural feature for the <span
style="font-style: italic;">text</span> property.&nbsp; This is done
by&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_2.gif"> adding a structural feature whose name is <span
style="font-style: italic;"><img style="width: 24px; height: 13px;"
alt="" src="../images/tag_3.gif"></span> <span
style="font-style: italic;">text.&nbsp;</span> Even through the object
used is an <span style="font-style: italic;">Add</span> from the event
model, the Visual Editor will pick up the fact that there is a <span
style="font-style: italic;">text</span> property defined from
introspection (the one explicitly specified in the
MyCustomPrompterBeanInfo or in its absence the one determined through
get and set method pair matching) and merge in with this
property.&nbsp; This way information that has come from introspection
such as the get and set method names are combined with the EReference
defined in the .override file.</p>
<p>The&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_4.gif"> eAnnocations property defines the
annotations for the EReference and the class we're creating is an
instance of <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_5.gif"> <font face="Courier New">org.eclipse.ve.internal.cde.decorators.BasePropertyDecorator</font>.&nbsp;
<img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;"> The <a name="xsi:type_structure"></a>xsi:type
structure does not point to the
Java package directly.&nbsp; The first portion of
org.eclipse.ve.internal.cde.decorators points to the name of a
namespace defined in the&nbsp;<img style="width: 24px; height: 13px;"
alt="" src="../images/tag_1.gif"> xmi:XMI opening tag.&nbsp; This
namespace relates to the URL of decorators.ecore EMF package that
itself is declared in the plugin org.eclipse.ve.cde with its own use of
the extension point <span style="font-style: italic;">org.eclipse.emf.ecore.generated_package</span>
to be the EMF package class
org.eclipse.ve.internal.cde.decorators.DecoratorsPackage.</p>
<p>The class
org.eclipse.ve.internal.cde.decorators.BasePropertyDecorator has an EMF
feature&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_6.gif"> cellEditorClassname.&nbsp; This will be
used by the Visual Editor in the Properties view when the property is
edited and points to our custom editor.</p>
<p>Having defined the .override file that extends the <span
style="font-family: monospace;">MyCustomPrompter</span>'s <span
style="font-style: italic;">text</span> feature to have a custom IDE
cell editor the next step is to write the code for the custom editor
itself.&nbsp; <span style="font-family: monospace;">CustomLabelEditor</span>
extends DialogCellEditor that provides the framework support for
displaying a button to open the actual dialog.&nbsp;</p>
<p><img style="border: 1px solid ; width: 211px; height: 46px;" alt=""
src="images/TextPropertyCellEditor.png"></p>
<p>The next step is to write the dialog that allows the user to edit
the <span style="font-style: italic;">text</span> property and ensure
that this is launched from CustomLabelEditor.</p>
<p>The dialog is created by extending the JFace helper class <span
style="font-family: monospace;">org.eclipse.jface.dialogs.TitleAreaDialog</span>
that provides support for the title area and buttons.&nbsp; The content
or client area of this will be built using the Visual Editor itself as
a visual component class <span style="font-family: monospace;">org.eclipse.ve.example.customwidget.LabelDialogContentArea.</span></p>
<p><img style="width: 719px; height: 524px;" alt=""
src="images/CustomTextEditorDialog.png"></p>
<p>&nbsp;</p>
<p>To logic for what occurs when the dialog is requested to be open is
done by specializing the method <span style="font-family: monospace;">openDialogBox(Control
cellEditorWindow)</span> in <span style="font-family: monospace;">CustomLabelEditor<span
style="font-family: arial,helvetica,geneva;">.</span></span> The
contents for this method are shown below and perform two important
steps.&nbsp; The first of these is to open an actual dialog that lets
the user specify their text property, and the second is to get the
result of this and create a new <span style="font-family: monospace;">IJavaInstance</span>
that represents the next String for the Visual Editor's EMF instance
model.&nbsp; The code below shows how to do this for <span
style="font-family: monospace;">CustomLabelEditor</span>.</p>
<pre><span style="color: rgb(153, 0, 0);">protected</span> Object openDialogBox(Control cellEditorWindow) {<br> Display display = cellEditorWindow.getDisplay();<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> TitleAreaDialog dialog = <span
style="color: rgb(153, 0, 0);">new</span> TitleAreaDialog(display.getActiveShell()) {<br> LabelDialogContent content;<br> <span
style="color: rgb(153, 0, 0);">protected</span> Control createContents(Composite parent) {<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> Control result = super.createContents(parent);<br> setTitleImage(CustomwidgetPlugin.getCustomImage());<br> setTitle(<span
style="color: rgb(51, 51, 255);">"Prompter's text property editor"</span>);<br> setMessage(<span
style="color: rgb(51, 51, 255);">"Enter the text property, or select a default one by checking the Hello or GoodBye"</span>,IMessageProvider.<span
style="font-style: italic;">INFORMATION</span>); <br> <span
style="color: rgb(153, 0, 0);">return</span> result;<br> }<br> <span
style="color: rgb(153, 0, 0);">protected</span> Control createDialogArea(Composite parent) {<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> content = <span
style="color: rgb(153, 0, 0);">new</span> LabelDialogContent(parent, SWT.<span
style="font-style: italic; color: rgb(51, 51, 255);">NONE</span>);<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif"> content.setString(stringValue);<br> <span
style="color: rgb(153, 0, 0);">return</span> content;<br> }<br> <span
style="color: rgb(153, 0, 0);">public</span> String toString() {<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif"> <span
style="color: rgb(153, 0, 0);">return</span> content.getString();<br> }<br> }; <br> <span
style="color: rgb(153, 0, 0);">if</span> (dialog.open() != Window.<span
style="font-style: italic; color: rgb(51, 51, 255);">CANCEL</span>) {<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_6.gif"> <span
style="color: rgb(153, 0, 0);">return</span> createStringJavaObject(dialog.toString());<br> } <span
style="color: rgb(153, 0, 0);">else</span> { <span
style="color: rgb(153, 0, 0);"> return</span> getValue();<br> }<br> }<br></pre>
<p>The dialog editor used is an&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif">
inner class that extends the jface abstract class
org.eclipse.jface.dialogs.TitleAreaDialog.&nbsp; Three methods are
specialized:</p>
<p>The createContents(Composite parent) method is used to build the
actual SWT content area of the dialog.&nbsp; The TitleAreaDialog
supeclass provides a default structure that is invoked through
calling&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_2.gif"> <span style="font-family: monospace;">super.createContents(parent)</span>,
although details such as the image and title are overridden. The
content area of the dialog is the area we're interested in putting out
custom editing experience into, and this is done by creating an
instance of&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_3.gif"> <span style="font-family: monospace;">LabelDialogContent</span>
(that is built below).</p>
<p>The content area for the TitleAreaDialog created by the
LabelCellEditor is the class
org.eclipse.ve.examples.customwidget.LabelDialogContent.&nbsp; This is
available in CVS <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/src/org/eclipse/ve/example/customwidget/LabelDialogContent.java">LabelDialogContent.java</a>
and extends <span style="font-family: monospace;">org.eclipse.swt.Composite</span>
and was built using the Visual Editor.&nbsp; This has the methods <span
style="font-family: monospace;">public setString(String aString)</span>
to set the current value of the String, and <span
style="font-family: monospace;">public String getString()</span> to
return it.&nbsp; These are both called by the <span
style="font-family: monospace;">CustomLabelEditor</span> when it&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif">
initializes the content area and&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif">
returns the value.&nbsp;</p>
<p>The <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_5.gif"> <span style="font-family: monospace;">toString()</span>
method is specialized to return the value of the LableDialogContent,
which represents the String entered by the user as the new <span
style="font-style: italic;">text</span> property.&nbsp; This is so
that the value can be referenced by the CustomLabelEditor itself when
it <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_6.gif">has created the actual object that will be
set into the Visual Editor model.</p>
<p>If the TitleAreaDialog isn't cancelled then the JFace cell editor
needs to return the value of the newly created object representing the
value of the <span style="font-style: italic;">text</span>
property.&nbsp; The LabelDialogContent returns a java.lang.String and
this requires conversion into an IJavaInstance representing the EMF
JavaClass instance for the Visual Editor's model.&nbsp; This is done
with the helper method&nbsp;<img style="width: 24px; height: 13px;"
alt="" src="../images/tag_6.gif"> <span style="font-family: monospace;">IJavaInstance
createStringJavaObject(String aString);</span></p>
<p>To create an <span style="font-family: monospace;">IJavaInstance</span>
requires two steps.&nbsp; First the EMF <span
style="font-family: monospace;">JavaClass</span> needs to be located
and then an instance of <span style="font-family: monospace;">IJavaInstance</span>
needs to be created using this with rules as to how the actual
instantion of the live Java object should occur (both in code and by
the target VM).</p>
<p>To locate a <span style="font-family: monospace;">JavaClass</span>
involves looking up for the object on the current resource set.&nbsp; A
resource set is a physical grouping of EMF documents and to locate the
one being used by the Visual Editor it is held on the editorPart's GEF
editDomain.&nbsp; The Visual Editor uses a subclass of default GEF edit
domain called <span style="font-family: monospace;">org.eclipse.ve.internal.cde.core.EditDomain</span>.&nbsp;
The editDomain provides a way of passing common objects (such as the
target VM helper classes, the set of viewers, and the EMF resource set)
around between different Visual Editor subsystems.&nbsp; For a cell
editor to be given a reference to the edit domain it should implement
the interface <span style="font-family: monospace;">org.eclipse.ve.internal.propertysheet.INeedData</span>
that has a single method <span style="font-family: monospace;">public
void setData(Object data);&nbsp;</span> The argument to this will be
set by the Visual Editor to the editDomin object and the cell editor
should store this in an instance variable.</p>
<pre><span style="font-family: monospace;"><span
style="color: rgb(153, 0, 0);">public class</span> CustomLabelEditor <span
style="color: rgb(153, 0, 0);">extends</span> DialogCellEditor <span
style="color: rgb(153, 0, 0);">implements</span> INeedData {<br> private EditDomain fEditDomain;<br></span><span
style="font-family: monospace;"><span style="font-family: monospace;"><span
style="color: rgb(51, 204, 0);"><span style="color: rgb(0, 153, 0);"> // Remainder of class definition ...</span></span></span><br></span></pre>
and<br>
<pre> <span style="color: rgb(153, 0, 0);">public void</span> setData(Object data) {<br> fEditDomain = (EditDomain) data;<br> }<br></pre>
<p>To lookup the resource set from an EditDomain can be done using the
static helper method<span style="font-family: monospace;">JavaEditDomainHelper.getResourceSet(EditDomain
anEditDomain);</span></p>
<p>Now that the <span style="font-family: monospace;">CustomLabelEditor</span>
has a handle to the Visual Editor's model's resource set it can look up
<span style="font-family: monospace;">JavaClass</span> objects using
the API <span style="font-family: monospace;">org.eclipse.jem.internal.beaninfo.core.Utilities.getJavaClass(String
className, ResourceSet resourceSet);</span>&nbsp;&nbsp;&nbsp; In EMF to
instantiate actual objects the package's factory should be used, so
having obtained the <span style="font-family: monospace;">JavaClass</span>
to get the <span style="font-family: monospace;">IJavaInstance</span>
requires the method call <span style="font-family: monospace;">javaClass.getEPackage().getEFactoryInstance().create(javaClass);</span>&nbsp;</p>
<p>Rather than having to do both steps however there is a helper API
method <span style="font-family: monospace;">org.eclipse.ve.internal.java.core.BeanUtilities.createJavaObject(String
qualifiedClassName, ResourceSet aResourceSet, String initString)</span>;&nbsp;
Examples of its usage are shown below:</p>
<pre>BeanUtilities.createJavaObject(<span
style="color: rgb(51, 51, 255);">"java.lang.Boolean"</span>, aResourceSet, <span
style="color: rgb(51, 51, 255);">"Boolean.TRUE"</span>); <span
style="color: rgb(0, 153, 0);">// Create a Boolean.TRUE instance</span><br>BeanUtilities.createJavaObject(<span
style="color: rgb(51, 51, 255);">"java.awt.Color"</span>, aResourceSet , <span
style="color: rgb(51, 51, 255);">"java.awt.Color.red"</span>); <span
style="color: rgb(0, 153, 0);">// Create an instance of the AWT color red</span><br>BeanUtilities.createJavaObject(<span
style="color: rgb(51, 51, 255);">"boolean"</span>, aResourceSet, <span
style="color: rgb(51, 51, 255);">"true"</span>); <span
style="color: rgb(0, 153, 0);">// Create an instance of the primitive boolean true</span><br>BeanUtilities.createJavaObject(<span
style="color: rgb(51, 51, 255);">"java.lang.String"</span>, aResourceSet, <span
style="color: rgb(51, 51, 255);">"\\"Hello World\\""</span>); <span
style="color: rgb(0, 153, 0);">// Create an instance of the String "Hello World"</span>
</pre>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;">
The third argument to the method represents the code fragment that will
be used to instantiate the actual live Java instance.&nbsp; This is the
actual argument that is used by the Visual Editor when it generates the
<span style="font-family: monospace;">setProperty(Object propertyValue)</span>
method.&nbsp; For the last example that was itself a String for the
quotation marks to be present in the String when the code is generated
they must be present in the literal itself which requires escaping them
with a <span style="color: rgb(51, 51, 255);">\\.</span></p>
<p>The protected helper method on <span style="font-family: monospace;">CustomLabelEditor</span>
and called by <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_6.gif"> <span style="font-family: monospace;">openDialogBox(Control
cellEditorWindow)</span> can now be written as follows.</p>
<pre> <span style="color: rgb(153, 0, 0);">private</span> IJavaInstance createStringJavaObject(String aString) {<br> <span
style="color: rgb(153, 0, 0);">return</span> BeanUtilities.createJavaObject(<br> <span
style="color: rgb(51, 51, 255);">"java.lang.String"</span>,<br> JavaEditDomainHelper.getResourceSet(fEditDomain),<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> BeanUtilities.createStringInitString(aString)<br> );<br> }<br></pre>
<p>Rather than just writing <span style="color: rgb(51, 51, 255);">"\\"</span>
+ aString + <span style="color: rgb(51, 51, 255);">"\\"</span> a
helper method on&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif"> <span style="font-family: monospace;">BeanUtilities</span>
is used to quote the user's string.&nbsp; The helper handles cases such
as the string containing bona-fide escape characters the user put there
that themselves need quoting.</p>
<h3><a name="Rendering_the_text_value_in_the"></a>Rendering the <span
style="font-style: italic;">text value&nbsp;</span> in the Properties
view</h3>
<p>When the <span style="font-style: italic;">text</span> property is
displayed in the Properties view we wish the user to be able to see the
current value.&nbsp; This occurs with nothing extra to be done, because
the <span style="font-style: italic;">text</span> property is typed to
<span style="font-family: monospace;">java.lang.String</span> and there
is a default label provider class for this provided by the <span
style="font-style: italic;">org.eclipse.ve.java.core</span> plugin as
part of its <span style="font-style: italic;">String.override</span>.&nbsp;
For this reason file the Visual Editor already knows how to render
String properties as shown below.</p>
<p><span style="font-family: monospace;"><img
style="border: 1px solid ; width: 266px; height: 63px;" alt=""
src="images/TextPropertyDisplayed.png"></span></p>
<p>With the CustomLabelEditor however specific code is required to
ensure that it displays the current value of the <span
style="font-style: italic;">text</span> property</p>
<p><img style="border: 1px solid ; width: 265px; height: 66px;" alt=""
src="images/TextCurrentValue.png"></p>
<p>This is done by specializing the method <span
style="font-family: monospace;">doSetValue(Object value);&nbsp;</span>
This method is given an argument of an <span
style="font-family: monospace;">IJavaInstance</span> which represents
the current value of the String object in the Visual Editor's EMF
model.&nbsp; To convert from this to this to a <span
style="font-family: monospace;">java.lang.String</span> object can be
done by accessing the target VM to query the value of the live String
object.</p>
<p>To write the code for the <span style="font-family: monospace;">doSetValue(Object
value)</span> method requires an understanding of the API to work with
the Visual Editor target VM objects</p>
<h4><a name="Target_VM_and_its_APIs"></a>Target VM and its APIs</h4>
<p>Live objects used by the Visual Editor exist only on the target VM
and are never loaded by the Visual Editor inside the actual Eclipse
workbench's JVM.&nbsp; For every object created on the target VM there
is a proxy to it held by the Visual Editor inside the Eclipse
JVM.&nbsp;&nbsp;&nbsp; This proxy is an instance of <span
style="font-family: monospace;">org.eclipse.jem.internal.proxy.core.IBeanProxy</span>
and is able to perform tasks such as remote method&nbsp; invocation on
the actual target VM instance.<br>
<br>
The API for this is modelled on the<span style="font-family: monospace;">java.lang.reflect</span>
API however, unlike the reflection API which performs dynamic
invocation within a single JVM, the bean proxy mechanism works between
the Eclipse workbench's JVM where the proxies are, and Visual Editor's
target JVM where the live instances exist.</p>
<table style="text-align: left; width: 75%;" border="1" cellspacing="2"
cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">java.lang and java.lang.reflect
API</td>
<td style="vertical-align: top;">org.eclipse.jem.internal.proxy.core
API</td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">Object</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IBeanProxy</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">Class</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IBeanTypeProxy</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">object.getClass()</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IBeanProxy.getTypeProxy()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">Method</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IMethodProxy</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">Class.getMethod(String methodName)</span>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IBeanTypeProxy.getMethodProxy(String
methodName)</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">Constructor</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IConstructorProxy</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">Class.getConstructor(Class[] types)</span>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IBeanTypeProxy.getConstructorProxy(IBeanTypeProxy[]
types)</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">Constructor.newInstance(Object[]
initArgs)</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IConstructorProxy.newInstance(IBeanProxy[]
initArgs)</span> </td>
</tr>
</tbody>
</table>
<p>To locate instances of <span style="font-family: monospace;">IBeanProxy</span>
(from which method and constructor proxies can be retrieved) a factory
is used that is held on a proxy factory registry.&nbsp; The registry is
used to create and cache instances of <span
style="font-family: monospace;">IBeanTypeProxy</span>, and can be
located through a helper method which retrieves it from the GEF edit
domain.&nbsp; The <span style="font-family: monospace;">IProxyFactoryRegistry</span>
can return factories for retrieving instances of IBeanTypeProxy through
the method getBeanTypeProxy(String typeName) as well as factories for
creating new instances of <span style="font-family: monospace;">IBeanProxy</span>
through the overloaded method <span style="font-family: monospace;">getBeanProxy(Object
anObject)</span> with arguments representing the nine Java primitives,
their <span style="font-family: monospace;">java.lang</span> peers as
well as <span style="font-family: monospace;">java.lang.String</span>.</p>
<p>The following code samples show how to create an instance of a <span
style="font-family: monospace;">java.io.File</span> for the file name <span
style="font-style: italic;">"C:\temp\foo.txt"</span> (i.e. the result
of evaluating <span style="font-family: monospace;"><span
style="color: rgb(153, 0, 0);">new</span> java.io.File(<span
style="color: rgb(51, 51, 255);">"C:\temp\foo.txt"</span>)</span> on
the target VM.</p>
<pre>IProxyFactoryRegistry aProxyFactoryRegistry = JavaEditDomainHelper.getBeanProxyDomain(anEditDomain).getProxyFactoryRegistry();<br>IBeanTypeProxy javaIOFileBeanTypeProxy = aProxyFactoryRegistry.getBeanTypeProxy(<span
style="color: rgb(51, 51, 255);">"java.io.File"</span>);<br></pre>
<p>Having obtained the <span style="font-family: monospace;">IBeanTypeProxy
<span style="font-family: arial,helvetica,geneva;">the instance of</span></span>
an <span style="font-family: monospace;">IBeanProxy</span> for the
java.io.File can be created by locating the correct <span
style="font-family: monospace;">IConstructorProxy</span> and calling <span
style="font-family: monospace;">newInstance(IBeanProxy[])</span> with
the correct arguments.</p>
<pre>IBeanProxy fooStringBeanProxy = aProxyFactoryRegistry.getBeanProxyFactory().createBeanProxyWith(<span
style="color: rgb(51, 51, 255);">"C:\temp\foo.txt"</span>);<br>IConstructorProxy fileConstructorProxy = javaIOFileBeanTypeProxy.getConstructorProxy(<span
style="color: rgb(51, 51, 255);">"java.lang.String"</span>);<br>IBeanProxy fileProxy = fileConstructorProxy.newInstance(fooStringBeanProxy);<br></pre>
<p>In addition to locating the IConstructorProxy and invoking as shown
above there is a shorthand way of creating a bean proxy with a specific
Java initialization string.&nbsp; This is with the method <span
style="font-family: monospace;">newInstance(String
javaInitializationString)</span> on <span
style="font-family: monospace;">IBeanTypeProxy</span>.&nbsp; Using
this the above code can be shortened to</p>
<pre>IBeanProxy fileProxy = javaIOFileBeanTypeProxy.newInstance(<span
style="color: rgb(51, 51, 255);">"C:\temp\foo.txt"</span>);<br></pre>
<p>The Visual Editor's model for the Java class being visually is an
EMF graph of <span style="font-family: monospace;">IJavaInstance</span>
objects. The API method <span style="font-family: monospace;">org.eclipse.jem.internal.proxy.core.BeanProxyUtilities.getBeanProxy(IJavaInstance
aJavaInstance)</span> exists to obtain the bean proxy fom a Visual
Editor EMF object.&nbsp; These are some more examples of the API for
working with bean proxies.</p>
<pre><span style="color: rgb(0, 153, 0);">// Retrieve a proxy to the result of calling the method getType() on a target VM for an IJavaInstance of MyCustomPrompter</span><br>IBeanProxy prompterProxy = BeanProxyUtilities.getBeanProxy(prompterJavaInstance); <span
style="color: rgb(0, 153, 0);">// Obtain an IBeanProxy from an IJavaInstance</span><br>IMethodProxy getTypeMethodProxy = prompterProxy.getTypeProxy().getMethodProxy(<span
style="color: rgb(51, 51, 255);">"getType"</span>);<br>IBeanProxy proxyToGetTypeResult = getTypeMethodProxy.invoke(prompterProxy);<br><br><span
style="color: rgb(0, 153, 0);">// Set the value of setType(String) method to the value "Frog"<br></span>IBeanProxy frogProxy = prompterProxy.getProxyFactoryRegistry().getBeanProxyFactory().createBeanProxyWith(<span
style="color: rgb(51, 51, 255);">"Frog"</span>);<br>IMethodProxy setTypeMethodProxy = prompterProxy.getTypeProxy().getMethodProxy(<span
style="color: rgb(51, 51, 255);">"setType"</span>,<span
style="color: rgb(51, 51, 255);">"java.lang.String"</span>);<br>setTypeMethodProxy.invoke(prompterProxy,frogProxy);<br></pre>
<p>Working with remote proxies from the Eclipse workbench's JVM that
point to instances of real live objects in the Visual Editor's target
JVM provides a way of ensuring that the two are totally insultated and
no class within the user's build path of a Java project needs to be
loaded by the class loader or instantantiated within Eclipse.&nbsp;
This provides a true editing sandbox which allows multiple instances of
classes to exist across different editors working with different build
paths and is the design principle that allows the Visual Editor to be
extended to support new target environment and topologies other than
just pure Java.&nbsp; However at some point the Visual Editor does need
to transport objects back from the target JVM to Eclipse.&nbsp; An
example of this is that having got an <span
style="font-family: monospace;">IBeanProxy</span> for a rectangle
result to the <span style="font-family: monospace;">getBounds()</span>
method this must be converted in its four constituient int values so
that a draw2D rectangle can be created for the GEF figure.&nbsp;
Likewise the Properties view shows the user the values of the target VM
objects.&nbsp; The point at which an object on the target VM can be
retrieved within the Eclipse workbench is when it is a primitive object
or a java.lang peer of a primitive or a String instance.&nbsp; This is
done by having four subinterfaces of <span
style="font-family: monospace;">IBeanProxy</span> in the package <span
style="font-family: monospace;">org.eclipse.jem.internal.proxy.core</span>.</p>
<table cellpadding="2" cellspacing="2" border="1"
style="text-align: left; width: 50%;">
<tbody>
<tr>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;">java.lang Object lookup</td>
<td style="vertical-align: top;">primitive lookup</td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IStringBeanProxy</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">java.lang.String stringValue()</span> </td>
<td style="vertical-align: top;"> <br>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">IBooleanBeanProxy</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">java.lang.Boolean getBooleanValue()</span>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">boolean booleanValue()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">ICharacterBeanProxy</span> </td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">java.lang.Character characterValue()</span>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">char charValue()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"><span
style="font-family: monospace;">INumberBeanProxy</span> </td>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">int intValue()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">long longValue()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">byte byteValue()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">short shortValue()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">float floatValue()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">double doubleValue()</span> </td>
</tr>
<tr>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"> <br>
</td>
<td style="vertical-align: top;"><span
style="font-family: monospace;">number numberValue()</span> </td>
</tr>
</tbody>
</table>
<br>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;">
It is possible to register custom sub instances of <span
style="font-family: monospace;">IBeanProxy</span> for plugin specific
objects and this occurs with <span style="font-style: italic;">org.eclipse.ve.jfc</span>
plugin that has introduces the types <span
style="font-family: monospace;">IPointBeanProxy</span>, <span
style="font-family: monospace;">IRectangleBeanProxy</span> and <span
style="font-family: monospace;">IDimensionBeanProxy</span>.&nbsp; This
can occur safely if you know that the Eclipse workbench's JVM contains
the classes in its -classpath and that these are a compatible shape
with the target VM's instances.&nbsp; This and other advanced topics
such handling arrays, installing helper class on the target VM's
-classpath for a classpath container, exceptions and debugging the
target VM are covered in a later tutorial specific to the target VM
architecture.</p>
<h3><a name="Retrieving_the_target_VM_property_value"></a>Retrieving
the target VM property value</h3>
<p>Having covered some of the background to the target VM API the
method <span style="font-family: monospace;">doSetValue(Object value)</span>
can now be overriden on CustomLabelEditor.&nbsp; This is so that the
Properties view can render correctly the value of the <span
style="font-style: italic;">text</span> property<span
style="font-style: italic;">.&nbsp;</span></p>
<pre><img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif"> <span style="color: rgb(153, 0, 0);">protected</span> String stringValue = <span
style="color: rgb(51, 51, 255);">""</span>;<br> <span
style="color: rgb(0, 153, 0);"> // ...</span><br> <span
style="color: rgb(153, 0, 0);">protected void</span> doSetValue(Object value) {<br> <span
style="color: rgb(153, 0, 0);">if</span> (value != <span
style="color: rgb(153, 0, 0);">null</span>){<br> IStringBeanProxy stringBeanProxy =<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> (IStringBeanProxy) BeanProxyUtilities.getBeanProxy(<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif">(IJavaInstance) value);<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif"> stringValue = stringBeanProxy.stringValue();<br> }<br> <span
style="color: rgb(153, 0, 0);">super</span>.doSetValue(value);<br> }<br> <span
style="color: rgb(0, 153, 0);"> // ...</span>
<img style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif"> <span
style="color: rgb(153, 0, 0);">protected void</span> updateContents(Object value) {<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_6.gif"> <span
style="color: rgb(153, 0, 0);">super</span>.updateContents(stringValue);<br> }<br></pre>
<p>A String instance varialble&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> is
created to store the value of the <span style="font-style: italic;">text</span>
property result that the CustomLabelEditor is working with.&nbsp;</p>
<p>The doSetValue(Object) method will be called when the editor is
first created by the Properties view and after each time the dialog
editor is closed. The argument to this is an&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif">
IJavaInstance for the String inside the Visual Editor's EMF model, so
the target VM can be used to locate the IBeanProxy which, because the <span
style="font-style: italic;">type</span> property is typed to <span
style="font-family: monospace;">java.lang.String</span>, will be an
instance of&nbsp; <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_3.gif"><span style="font-family: monospace;">IStringBeanProxy</span>.&nbsp;&nbsp;
The <span style="font-family: monospace;">java.lang.String</span>
value of this inside the workbench's JVM is retrieved using&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif"> <span
style="font-family: monospace;">IStringBeanProxy.stringValue()</span>
and this is stored in the instance field <span
style="font-family: monospace;">stringValue</span>;</p>
<p>To ensure that the contents of the Label used by the cell editor
shows the string correctly the method&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif"> <span
style="font-family: monospace;">updateContents(Object value)</span> is
overriden to ignore the argument and call&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_6.gif"> <span
style="font-family: monospace;">super.updateContents()</span> with the
actual String.</p>
<h3><a name="Testing_the_text_dialog_cell_editor"></a>Testing the <span
style="font-style: italic;">text</span> dialog cell editor</h3>
<p>To create the curstom <span style="font-style: italic;">text</span>
editor several steps were involved:</p>
<ul>
<li>Use the extension point <span style="font-style: italic;">org.eclipse.ve.jem.beaninfo.registrations</span>
to declare the /override folder structure associated with the
PrompterContainer for the Java package org.eclipse.ve.examples.prompter</li>
<li>Create a <span style="font-style: italic;">MyCustomPrompter.override</span>
file in the /overrides directory that added a BasePropertyDecorator to
the EReference for the <span style="font-style: italic;">text</span>
structural feature.</li>
<li>Set the <span style="font-style: italic;">cellEditorClassname</span>
property of the BasePropertyDecorator to be the class
org.eclipse.ve.examples.CustomLabelEditor</li>
<li>Create the <span style="font-family: monospace;">CustomLabelEditor</span>
class extending the JFace abstract <span
style="font-family: monospace;">DialogEditorClass</span> (and
implementing the interface <span style="font-family: monospace;">INeedData</span>
to ensure it is given the Visual Editor's EditDomain)</li>
<li>Override the method <span style="font-family: monospace;">openDialogBox(Control
aControl)</span> on <span style="font-family: monospace;">CustomLabelEditor</span>
to open an inner subclass of <span style="font-family: monospace;">TextDialogEditor</span></li>
<li>The <span style="font-family: monospace;">TextDialogEditor</span>
contains a content pane which allows the <span
style="font-style: italic;">text</span> property to be edited - this
is a subclass of <span style="font-family: monospace;">Composite</span>
called <span style="font-family: monospace;">LabelDialogContent</span></li>
<li>To render the property correctly in CustomLabelEditor the method<span
style="font-family: monospace;">doSetValue(Object)</span> and <span
style="font-family: monospace;">updateContents(value)</span> is
overriden and the target VM string retrieved and displayed</li>
</ul>
<p>To test the <span style="font-style: italic;">text</span> property
start the runtime Eclipse workbench, drop an instance of <span
style="font-family: monospace;">MyCustomPrompter</span> onto a <span
style="font-family: monospace;">Shell</span> or <span
style="font-family: monospace;">Composite</span> and select and edit
the <span style="font-style: italic;">text</span> property.&nbsp; If
it fails and has the default String label and cell editor look in the <span
style="font-style: italic;">.log</span> file in the .metadata
directory of the target workbench for any syserr output.&nbsp; These
will typically be because some XMI syntax in the .override file was
entered incorrectly.&nbsp; If there is no output then it is possible
that the definition of the beaninfo.registrations extension point is
incorrect, and for this debug the <span style="font-family: monospace;">BeanInfoClassAdapter</span>
class to see that the .override file being searched for.&nbsp;<br>
<br>
The next step of the tutorial will create a special GEF edit part for
MyCustomPrompter that instead of just drawing an image of the live
custom control, renders some text and icon on top of the graphic.<br>
</p>
<h2><a name="Overriding_a_GEF_edit_part">Supplying a custom GEF edit
part</a></h2>
<p>Classes implement the interface <span
style="font-family: monospace;">org.eclipse.gef.GraphicalEditPart</span>
act as mediators between a model object and the draw2D API that renders
the object onto the GEF canvas.&nbsp; The edit part to use for a given <span
style="font-family: monospace;">IJavaInstance</span> (the model
object) by the Visual Editor is obtained from the <span
style="font-family: monospace;">ClassDescriptorDecorator</span> that
annotates its JavaClass.&nbsp; If no explicitly defined <span
style="font-family: monospace;">ClassDescriptorDecorator</span> can be
found, or the one found doesn't have a graphical edit part class
defined, then the inheritance chain of the EMF <span
style="font-family: monospace;">JavaClass</span> (that shadows the
Java type hierarchy) is searched until a graphical edit part class name
is found.&nbsp; following this rule, in the absence of any override for
<span style="font-family: monospace;">MyCustomPrompter</span> the
Visual Editor will pick up the inherited edit part class <span
style="font-family: monospace;">CompositeGraphicalEditPart</span>
because <span style="font-family: monospace;">MyCustomPrompter</span>
extends <span style="font-family: monospace;">Composite</span> and
this is what gives <span style="font-family: monospace;">MyCustomPrompter</span>
its initial default edit experience.</p>
<p>This section of the tutorial will build a custom graphical edit part
named <span style="font-family: monospace;">org.eclipse.ve.example.customwidget.CustomWidgetGraphicalEditPart</span>.&nbsp;
This will be declared in the <span style="font-style: italic;">MyCustomPrompter.override</span>
file as being the graphical edit part class to use, and the class will
be specialized to create the draw2D desired effects.</p>
<p>MyCustomPrompter.override should be updated as below.&nbsp; (The <span
style="color: rgb(153, 153, 153);">grey</span> text fragments of XMI
represents elements in the original file written for the <span
style="font-style: italic;">text</span> property custom editor and the
black the new lines to add)</p>
<pre><span style="color: rgb(153, 153, 153);"><br>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br> &lt;xmi:XMI xmi:version="2.0" <br> xmlns:xmi="http://www.omg.org/XMI" <br> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;<br></span><span
style="color: rgb(153, 153, 153);"><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"></span> <span
style="color: rgb(153, 153, 153);">xmlns:org.eclipse.ve.internal.cde.decorators="http:///org/eclipse/ve/internal/cde/decorators.ecore"</span><br><span
style="color: rgb(153, 153, 153);"> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" <br> xmlns:event="event.xmi"&gt;<br><br></span><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> &lt;event:Add featureName="eAnnotations"&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> &lt;addedEObjects xsi:type="org.eclipse.ve.internal.cde.decorators:ClassDescriptorDecorator"<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif"> graphViewClassname="org.eclipse.ve.example.customwidget/org.eclipse.ve.example.customwidget.CustomWidgetGraphicalEditPart"&gt;<br> &lt;/addedEObjects&gt;<br> &lt;/event:Add&gt;<br><br><span
style="color: rgb(153, 153, 153);"><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif"> &lt;event:Add featureName="eStructuralFeatures"&gt;</span> <span
style="color: rgb(153, 153, 153);"> <br> &lt;addedEObjects xsi:type="ecore:EReference" name="text" unsettable="true"&gt;</span> <span
style="color: rgb(153, 153, 153);"> <br> &lt;eAnnotations xsi:type="org.eclipse.ve.internal.cde.decorators:BasePropertyDecorator"<br></span> <span
style="color: rgb(153, 153, 153);">cellEditorClassname="org.eclipse.ve.example.customwidget/org.eclipse.ve.example.customwidget.CustomLabelEditor"/&gt;</span> <span
style="color: rgb(153, 153, 153);"> <br> &lt;/addedEObjects&gt;</span> <span
style="color: rgb(153, 153, 153);"> <br> &lt;/event:Add&gt;<br></span> <span
style="color: rgb(153, 153, 153);">&lt;/xmi:XMI&gt; &lt;/xmi:XMI&gt;</span>
</pre>
<p>To specify that <span style="font-family: monospace;">BasePropertyDecorator</span>
as annotating the <span style="font-style: italic;">type</span>
structural feature (as was done for the CustomLabelEditor earlier)
an&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_5.gif"> event:Add was created for the EMF feature <span
style="font-style: italic;">eStructuralFeature</span><span
style="font-style: italic;">s</span>.&nbsp; This represents the
features or properties on the JavaClass, and the decorator was then
defined as annotating the feature.&nbsp; To annotate the actual
JavaClass (as opposed to one of its specific features) an&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> <span
style="font-family: monospace;">event:Add</span> is created directly
on the <span style="font-style: italic;">eAnnotations</span> feature
as a top level element in the XMI.&nbsp; Because the file name is <span
style="font-style: italic;">MyCustomPrompter.override</span> the
Visual Editor will process this as an addition to the annotations of
the EMF definition of the <span style="font-family: monospace;">MyCustomPrompter</span>
class.</p>
<p>The class being added as an annotation to MyCustomPrompter is an
instance of&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_3.gif">
org.eclipse.ve.internal.cde.decorators.ClassDescriptorDecorator.&nbsp;
As described <a href="#xsi:type_structure">earlier</a> the XMI
describes this as <span style="font-style: italic;">EMFPackageName:EMFClassName</span>
which corresponds to the EMF registered package <span
style="font-family: monospace;">org.eclipse.ve.internal.cde.decorators.DecoratorsPackage</span>.&nbsp;&nbsp;
A common coding error with XMI is to declare the element for an
annotation assuming that it is the <span style="font-style: italic;">packageName:classNam</span>e
without having the namespace definition&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> at
the top of the XMI file.<br>
&nbsp;<br>
<span style="font-family: monospace;">ClassDescriptorDecorator</span>
stores the name of the graphical edit part to use by GEF with the
syntax of <span style="font-style: italic;">pluginName/qualifiedClassName</span>.
For this tutorial the edit part created is called <span
style="font-family: monospace;">org.eclipse.ve.example.CustomWidgetGraphicalEditPart</span>
and in the plugin name <span style="font-style: italic;">org.eclipse.ve.example.,customwidget</span>.</p>
<p>The method responsible for creating the draw2D figure shown on the
GEF canvas is <span style="font-family: monospace;">createFigure()</span>
and this is overriden to place a draw2L label on top of the inherited
behavior (an image of the live visual).&nbsp; The method is shown below
and the full class list is available at <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/src/org/eclipse/ve/example/customwidget/CustomWidgetGraphicalEditPart.java">
CustomWidgetGraphicalEditPart.java</a>.</p>
<pre><span style="color: rgb(153, 0, 0);">public class</span> CustomWidgetGraphicalEditPart <span
style="color: rgb(153, 0, 0);">extends</span> <span
style="color: rgb(153, 0, 0);"><img style="width: 24px; height: 13px;"
alt="" src="../images/tag_1.gif"></span> ControlGraphicalEditPart {<br><br> <span
style="color: rgb(153, 0, 0);">protected</span> IFigure createFigure() {<br><br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> IFigure figure = super.createFigure();<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"> Label customFigure = <span
style="color: rgb(153, 0, 0);">new</span> Label(<span
style="color: rgb(51, 51, 255);">"VE Rules"</span>,CustomwidgetPlugin.getCustomImage());<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif"> customFigure.setForegroundColor(ColorConstants.red);<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif"> customFigure.setTextPlacement(PositionConstants.SOUTH);<br> <span
style="color: rgb(0, 153, 0);">// ImageFigure has no layout, so we will have to explicitly set the size().</span><br
style="color: rgb(0, 153, 0);"><br> <span
style="color: rgb(0, 153, 0);"> // To get a prefered size (before we look up the hierarchy), Label will need a Font</span>
<img style="width: 24px; height: 13px;" alt="" src="../images/tag_6.gif"> customFigure.setFont(((GraphicalEditPart)getParent()).getFigure().getFont());<br> customFigure.setSize(customFigure.getPreferredSize());<br><br> figure.add(customFigure);<br><br> <span
style="color: rgb(153, 0, 0);">return</span> figure;<br> }<br> }<br></pre>
<p>Although <span style="font-family: monospace;">MyCustomPrompter</span>
extends <span style="font-family: monospace;">Composite</span> and the
Visual Editor uses the class <span style="font-family: monospace;">CompositeGraphicalEditPart</span>
for visually edited composites, the <span
style="font-family: monospace;">CustomWidgetGraphicalEditPart</span>
is defined as extending <img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif"> <span style="font-family: monospace;">ControlGraphicalEditPart</span>.&nbsp;
This is because <span style="font-family: monospace;">CompositeGraphicalEditPart</span>
contains all of the GEF behavior to allow dropping of child controls
and dealing with layout management, and while <span
style="font-family: monospace;">MyCustomPrompter</span> physically
extends <span style="font-family: monospace;">Composite</span> to
enable it to have child controls our usage of it is as a closed black
box that can't accept more child controls and logically extends <span
style="font-family: monospace;">Control</span>'s behavior.&nbsp;</p>
<p>The inherited implementation from <span
style="font-family: monospace;">ControlGraphicalEditPart</span>
returns the class<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_2.gif"> <span style="font-family: monospace;">ImageFigure</span>.&nbsp;
This has the logic required to render a picture of the live
control.&nbsp; To this figure we add a draw2D Label that has an icon <img
style="width: 16px; height: 16px;" alt="" src="images/custom.gif">
and the text <span style="color: rgb(255, 0, 0);">VE Rules</span>
drawn in red.&nbsp; The Label is <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif">
created with the text and image and its&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif">
foreground color and details about how to <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif">
place the text (below the icon) are specified.&nbsp; The size of the
figure is set to its preferred size, and because this involves
calculating using the fontMetrics to determine the width of the label's
text the font must be&nbsp;<img style="width: 24px; height: 13px;"
alt="" src="../images/tag_6.gif"> explicitly set to the value it will
acquire when it is added to the parent.&nbsp; Having completed the
creation of the Label it is added as a child of the <span
style="font-family: monospace;">ImageFigure</span>.</p>
<p>To test the CustomWidgetGraphicalEditPart launch the Eclipse
workbench target and verify that the image of a MyCustomPrompter class
now renders itself with an image of the live visual covered with the <span
style="color: rgb(255, 0, 0);">VE R</span><span
style="color: rgb(255, 0, 0);">ules</span> text and icon <img
style="width: 16px; height: 16px;" alt="" src="images/custom.gif">.&nbsp;</p>
<img style="border: 1px solid ; width: 341px; height: 171px;" alt=""
src="images/GraphicalEditPart.png"><br>
<br>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;">
The original default behavior for MyCustomPrompter in the absence of
its specific graphical edit part was to render the live visual with a
border drawn around it. however the figure above shows that there is no
border drawn.&nbsp; The border is not part of the natural behavior of
an SWT composite (although one can be specified with the style bit of
SWT.BORDER) and it drawn by the Visual Editor around a
CompositeGraphicalEditPart so that an empty Composite with no children
isn't otherwise invisible (as if it were the same color as its
background it'd blend in and be hard to see on the design
canvas).&nbsp; The behavior to render a design time border around a GEF
figure is done by ConttrolGraphicalEditPart (which
CustomWidgetGraphicalEditPart extends) by having initializationData
supplied as part of its definition.&nbsp; InitializationData is used by
the Visual Editor as a way of supplying parameters to a class so that
different usages can supply custom implementations.&nbsp; It occurs by
having the class defined in the .override file implement the interface <span
style="font-family: monospace;">org.eclipse.core.runtime.IExecutableExtension</span>.&nbsp;
This has a single method <span style="font-family: monospace;">setInitializationData(IConfigurationElement
config, String propertyName, Object data).&nbsp;</span><br>
<br>
When the Visual Editor parses a class name defined in a .override file
if there is a colon symbol <span style="font-weight: bold;">:</span>
after the class name then anything following this is parsed and passed
into the setInitializationDataMethod(....).&nbsp; An example of this is
the class ControlGraphicalEditPart implements the IExecutableExtension
interface and uses the initData to determine whether a border should be
drawn around the figure or not as follows:</p>
<pre><span style="color: rgb(153, 0, 0);">public void</span> setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException {<br> <span
style="color: rgb(153, 0, 0);">if</span> (data <span
style="color: rgb(153, 0, 0);">instanceof</span> String)<br> border = Boolean.<span
style="font-style: italic;">valueOf</span>((String) data).booleanValue();<br>}<br></pre>
<p>and in the <span style="font-style: italic;">Composite.override</span>
file in <span style="font-style: italic;">org.eclipse.ve.swt/overrides/org/eclipse/swt/widgets</span></p>
<pre> &lt;addedEObjects xsi:type="org.eclipse.ve.internal.cde.decorators:ClassDescriptorDecorator"<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> graphViewClassname="org.eclipse.ve.swt/org.eclipse.ve.internal.swt.CompositeGraphicalEditPart:<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif">true" <br> &lt;/addedEObjects&gt;<br></pre>
<p>The&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_1.gif"> graphViewClassname is defined as
pluginName/qualifiedClassNane:initData and the value of <img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> <span
style="font-style: italic;">true</span> specifies that an SWT
composite is drawn by the Visual Editor with the border.&nbsp; Because <span
style="font-style: italic;">MyCustomPrompter.override</span> does not
specify the initData of <span style="font-style: italic;">true</span>
it is drawn with the live widget as is.<br>
<br>
The next step in the tutorial is to look at how to affect the code
generation subsystem of the Visual Editor.</p>
<h2><a name="Overriding_an_Expression_Decoder">Custom code generation
for the <span style="font-style: italic;">text</span> property</a></h2>
<p>The code generation subsystem is responsible for parsing a .java
file when it is opened by the Visual Editor and building up the graph
of IJavaInstance objects that represent the model of the visual
class.&nbsp; It does this by working with the JDT's Abstract Syntax
Tree (AST) that represents a set of fine grained nodes for every
compilable fragment of Java source.&nbsp; For every AST expression that
is modeled by the Visual Editor (not all source represents code
constructs that the Visual Editor is interested in showing to the user
or collecting in its model) there is an expression decoder.&nbsp;&nbsp;
The decoder has two helper classes; a feature mapper and a decoder
helper.</p>
<p>The feature mapper is responsible for tying together a source code
expression in the actual Java source to a modeled feature in the Visual
Editor's EMF model and vice-versa.</p>
<p>The decoder helper has the knowledge of how to parse AST expressions
and build up the Visual Editor model portion related to a specific
expression type, as well as how to generate specific expression source
code from the model.&nbsp;</p>
<p>The task of the decoder class is largely a delegate to determine
which feature mapper and decoder helper to use for a given source code
expression</p>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;">
Decoders do not generate AST nodes directly because in many cases the Java
source is created instead by using JavaJet templates.&nbsp; These
templates can be modified by users and recognized by the Visual
Editor&nbsp; and will be covered in more detail in a specific tutorial
covering the code generation subsystem.</p>
<p>This tutorial will create a decoder helper that adds a comment <span
style="font-family: monospace; color: rgb(0, 153, 0);">// Prompter
Text Property</span> to the line of Java code generated for the
setText(String aString) method of the <span style="font-style: italic;">text</span>
property.</p>
<pre><span style="font-family: monospace;"><span
style="color: rgb(153, 0, 0);">private void</span> createMyCustomPrompter() {</span><br
style="font-family: monospace;"> <span style="font-family: monospace;">myCustomPrompter = <span
style="color: rgb(153, 0, 0);">new</span> MyCustomPrompter(sShell, SWT.<span
style="font-style: italic; color: rgb(51, 51, 255);">NONE</span>);</span> <br> <span
style="font-family: monospace;">myCustomPrompter.setText(<span
style="color: rgb(51, 51, 255);">"Text value"</span>); <span
style="color: rgb(0, 153, 0);">// Prompter Text Property</span></span><br><span
style="font-family: monospace;">}<br></span><br>The class created to do this is <span
style="font-family: monospace;">org.eclipse.ve.examples.customwidget.CustomPrompterDecoderHelper</span>.&nbsp; This is declared in the <span
style="font-style: italic;">MyCustomPrompter.override</span> file as annotating the <span
style="font-family: monospace;">JavaClass</span> definition for <span
style="font-family: monospace;">MyCustomPrompter</span> so the Visual Editor uses it.</pre>
<pre><span style="color: rgb(192, 192, 192);"><span
style="color: rgb(153, 153, 153);"> &lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><br> <span
style="color: rgb(153, 153, 153);">&lt;xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span><br> <span
style="color: rgb(153, 153, 153);">xmlns:org.eclipse.ve.internal.cde.decorators="http:///org/eclipse/ve/internal/cde/decorators.ecore"<br></span><span
style="color: rgb(153, 153, 153);"><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif"></span> xmlns:codeGenHelpers="platform:/plugin/org.eclipse.ve.java.core/overrides/codegenHelpers.ecore"<br> <span
style="color: rgb(153, 153, 153);">xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"<br> xmlns:event="event.xmi"&gt;</span><br><br><span
style="color: rgb(153, 153, 153);"><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"></span> &lt;event:AddMany featureName="eAnnotations"&gt;<br> <span
style="color: rgb(153, 153, 153);">&lt;addedEObjects xsi:type="org.eclipse.ve.internal.cde.decorators:ClassDescriptorDecorator"</span><br> <span
style="color: rgb(153, 153, 153);">graphViewClassname="org.eclipse.ve.example.customwidget/org.eclipse.ve.example.customwidget.CustomWidgetGraphicalEditPart"&gt;</span><br> <span
style="color: rgb(153, 153, 153);">&lt;/addedEObjects&gt;</span>
<img style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> &lt;addedEObjects xsi:type="codeGenHelpers:CodeGenHelperClass"<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_4.gif">source="codegen.CodeGenHelperClass"<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif"> expDecoder="org.eclipse.ve.example.customwidget/org.eclipse.ve.example.customwidget.CustomPrompterDecoder"/&gt;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_6.gif"> &lt;/event:AddMany&gt;<br><br> <span
style="color: rgb(153, 153, 153);">&lt;event:Add featureName="eStructuralFeatures"&gt;</span><br> <span
style="color: rgb(153, 153, 153);">&lt;addedEObjects xsi:type="ecore:EReference" name="text" unsettable="true"&gt;</span><br> <span
style="color: rgb(153, 153, 153);">&lt;eAnnotations xsi:type="org.eclipse.ve.internal.cde.decorators:BasePropertyDecorator"<br></span> <span
style="color: rgb(153, 153, 153);">cellEditorClassname="org.eclipse.ve.example.customwidget/org.eclipse.ve.example.customwidget.CustomLabelEditor"/&gt;</span><br> <span
style="color: rgb(153, 153, 153);">&lt;/addedEObjects&gt;</span><br> <span
style="color: rgb(153, 153, 153);">&lt;/event:Add&gt;<br></span><span
style="color: rgb(153, 153, 153);"> &lt;/xmi:XMI&gt;</span>
</pre>
<p>Earlier when just the single ClassDecriptorDecorator was added as an
annotation to MyCustomPrompter the XMI tag used in the .override file
was <span style="font-style: italic;">&lt;event:Add&gt;</span>.&nbsp;
This is the syntax to add a single object, however because a second
annotation now needs to be added the file is changed to use the&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> <span
style="font-style: italic;"><span style="font-style: italic;"><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_6.gif"></span></span><span
style="font-style: italic;">&lt;event:AddMany&gt;</span> element for
the two decorators.&nbsp; The decorator added is a CodeGenHelperClass
and this is done through adding&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_3.gif">
the namespace for codeGenHelper in the XMI package declarations and an
xsi:type of <span style="font-style: italic;">namespace:CodeGenHelperClass</span>
with syntax&nbsp;<img style="width: 24px; height: 13px;" alt=""
src="../images/tag_4.gif"> <span style="font-style: italic;">source="codegen.CodeGenHelperClass</span>".&nbsp;
The expression decoder is stored in the expDecoder feature of the
CodeGenHelperClass and defined with the syntax of&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_5.gif">
pluginName/qualifiedClassName.</p>
<p><font face="Arial">The <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/src/org/eclipse/ve/example/customwidget/CustomPrompterDecoder.java">CustomPrompterDecoder.java</a>.
is responsible for determining which decoder helper is associated with
which property.&nbsp; The superclass
~org.eclipse.ve.internal.swt.codegen.SWTControlDecoder is used as this
contains behavior such as dealing with the SWT code patterns required
for constructor style bits, and the method initialDecoderHelper() is
specialized to associate a decoder helper with the <span
style="font-style: italic;">text</span> property</font></p>
<pre> <span style="color: rgb(153, 0, 0);">public class</span> CustomPrompterDecoder <span
style="color: rgb(153, 0, 0);">extends</span> SWTControlDecoder {<br><br> <span
style="color: rgb(153, 0, 0);">protected void</span> initialDecoderHelper() {<br> <span
style="color: rgb(0, 153, 0);"> // if it is the text property that this decoder is decoding, use a custom helper</span><br> <span
style="color: rgb(153, 0, 0);">if</span> (fFeatureMapper.getFeature(<span
style="color: rgb(153, 0, 0);">null</span>).getName().equals(<font
color="#0000ff">"text"</font>)) {<br> fhelper = <span
style="color: rgb(153, 0, 0);">new</span> CustomPrompterDecoderHelper(fbeanPart, fExpr, fFeatureMapper, this);<br> } <span
style="color: rgb(153, 0, 0);">else</span> {<br> <span
style="color: rgb(153, 0, 0);">super</span>.initialDecoderHelper();<br> }<br> }<br> }<br></pre>
<p>The CustomPrompterDecoderHelper will extend the Visual Editor class
org.eclipse.ve.internal.java.codegen.java.SimpleAttributeDecoderHelper.&nbsp;
The method responsible for generating the code is generate(Object[])
and this is specialized as below.&nbsp; The full source file can be
viewed in CVS <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/src/org/eclipse/ve/example/customwidget/CustomPrompterDecoderHelper.java">
CustomPrompterDecoderHelper.java</a>.</p>
<pre> <span style="color: rgb(153, 0, 0);">public class</span> CustomPrompterDecoderHelper <span
style="color: rgb(153, 0, 0);">extends</span> SimpleAttributeDecoderHelper {<br><br> <span
style="color: rgb(153, 0, 0);">public</span> String generate(Object[] noArgs) <span
style="color: rgb(153, 0, 0);">throws</span> CodeGenException {<br> String result = <span
style="color: rgb(153, 0, 0);">super</span>.generate(noArgs);<br> <span
style="color: rgb(0, 153, 0);"> // Add a comment at the end of the expression</span><br> <span
style="color: rgb(153, 0, 0);">int</span> idx = result.lastIndexOf(<span
style="color: rgb(51, 51, 255);">';'</span>) + 1;<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> <span
style="color: rgb(153, 0, 0);">return</span> result.substring(0, idx) + <span
style="color: rgb(51, 51, 255);">" // Prompter Text Property "</span> + result.substring(idx, result.length());<br> }<br><br> }<br></pre>
<p>The <span style="font-family: monospace;">generate(Object[])</span>
method returns the String that is used for the code fragment generated
and the <span style="font-family: monospace;">CustomPrompterDecoderHelper</span>
adds a hard coded literal to the end of the inherited behavior (that
creates the full expression for the setType(...) method invocation).</p>
<p><img src="../images/note.gif" alt="Note:"
style="width: 62px; height: 13px;">
Instead of having CustomPrompterDecoderHelper and CustomPrompterDecoder
as two separate classes it would have been possible to have the decoder
helper as an anonymous inner class of the decoder itself.&nbsp; By
separating the decoder and the decoder helper into separate classes
however enables for re-use, as other properties that wished to share
the same rules as the <span style="font-style: italic;">text</span>
property can have their own decoders that use the same decoder helper.</p>
<p>You can test the decoder and decoder helper for the <span
style="font-style: italic;">text</span> property by launching the
Eclipse target workbench.&nbsp; Use the Properties view to set the <span
style="font-style: italic;">text</span> property and ensure that the
line is generated with the new comment.&nbsp; If it fails follow the
same steps as for the custom property editor which
involves looking in the .log file for any XMI syntax errors, using the
BeanInfoClassAdapter to ensure the .override is being detected, and
then finally debugging the decoder helper itself.&nbsp;</p>
<p>The final step of the tutorial is to promote the <span
style="font-style: italic;">buttonSelection</span> event to the list
of preferred events used by the Visual Editor when a list of events to
be added is displayed to the user.</p>
<h2><a name="Preferred_Event">Specifying a preferred event</a></h2>
<p><span style="font-family: monospace;">MyCustomPrompter class</span>
has the methods <span style="font-family: monospace;">addButtonSelectionEvent(ButtonSelectionEvent
anEvent)</span> and <span style="font-family: monospace;">removeButtonSelectionEvent(ButtonSelectionEvent
anEvent).</span>&nbsp; This allows anyone developing a class that uses
the custom prompter to be able to get called back anytime the user
presses its button.&nbsp; This is the button on the right hand side of
the prompter that is labelled ..., <span style="font-style: italic;">Open
or More </span>based on the <span style="font-style: italic;">type </span>property
setting.&nbsp; If a button listener is added to the custom prompter the
code generated is as below, and can be used for example to launch an
additional dialog or perform user logic.<br>
</p>
<p><span style="font-family: monospace;"><span
style="color: rgb(153, 0, 0);">private void </span>createCustomPrompter()
{</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; customPrompter
= <span style="color: rgb(153, 0, 0);">new </span>MyCustomPrompter(sShell,
SWT.NONE);&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </span><span
style="font-family: monospace;"></span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
customPrompter.addButtonSelectionListener(<span
style="color: rgb(153, 0, 0);">new </span>ButtonSelectionListener() {
</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span style="color: rgb(153, 0, 0);">public void</span>
buttonSelected(org.eclipse.swt.events.SelectionEvent e)
{&nbsp;&nbsp;&nbsp; </span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(<span
style="color: rgb(51, 51, 255);">"buttonSelected()"</span>); <span
style="color: rgb(0, 153, 0);">// TODO Auto-generated Event stub
buttonSelected()</span></span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; });</span><span
style="font-family: monospace;"></span><br
style="font-family: monospace;">
<span style="font-family: monospace;">}</span><br>
</p>
<p>The purpose of this section is to show how to make it such that the <span
style="font-style: italic;">buttonSelected </span>event is the
preferred event offered to the user because it is the one that will be
most commonly used.<br>
</p>
<p>In the absence of any specific customization
rules the Visual Editor will by default use JavaBeans reflection and
associate these together with an event named <span
style="font-style: italic;">buttonSelection</span>.&nbsp; This will be
available for the user to add events to from the <span
style="font-style: italic;">Add Event</span> wizard that is launched
from the <span style="font-weight: bold;">Events &gt; Add Event ..</span>.
pop-up menu option.</p>
<p>The desired effect though is to override the behavior of the Visual
Editor
such as the buttonSelected event appears on the first level of the <span
style="font-weight: bold;">Events</span> cascaded menu, as shown in
the figure below.&nbsp; The result of this would be that the usability
of the MyCustomPrompter class has been improved because the user is
more aware of its preferred API usage.</p>
<p><img style="border: 1px solid ; width: 501px; height: 411px;" alt=""
src="images/EventsMenuAfter.png"></p>
<p>Preferred events are defined according to the JavaBeans
specification with a custom BeanInfo class.&nbsp; Earlier the tutorial
created a specialized <a
href="http://dev.eclipse.org/viewcvs/indextools.cgi/%7Echeckout%7E/org.eclipse.ve.examples/org.eclipse.ve.example.customwidget/src/org/eclipse/ve/example/customwidget/prompter/MyCustomPrompterBeanInfo.java">
MyCustomPrompterBeanInfo.java</a> to define the <span
style="font-style: italic;">enumerationValues</span> for the <span
style="font-style: italic;">type</span> property.&nbsp; This was done
by specializing the <span style="font-family: monospace;">getPropertyDescriptors()</span>
method.&nbsp; As well as defining the list of available properties and
how they should be edited, a BeanInfo class defines the list of
available events in the method <span style="font-family: monospace;">getEventSetDescriptors()</span>.&nbsp;
This returns an array of <span style="font-family: monospace;">java.beans.EventSetDescriptor</span>
objects and for <span style="font-family: monospace;">MyCustomPrompterBeanInfo</span>
is written as below</p>
<pre> <span style="color: rgb(153, 0, 0);">public</span> EventSetDescriptor[] getEventSetDescriptors() {<br><br> <span
style="color: rgb(153, 0, 0);">try</span> {<br> MethodDescriptor addButtonSelectionMD = <span
style="color: rgb(153, 0, 0);">new</span> MethodDescriptor(<br> ButtonSelectionListener.class.getMethod(<span
style="color: rgb(51, 51, 255);">"buttonSelected"</span>,<br> <span
style="color: rgb(153, 0, 0);">new</span> Class[]{SelectionEvent.<span
style="color: rgb(153, 0, 0);">class</span>})<br> );<br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif"> addButtonSelectionMD.setPreferred(<span
style="color: rgb(153, 0, 0);">true</span>);<br> <br> EventSetDescriptor addButtonSelectionED = new EventSetDescriptor(<br> <span
style="color: rgb(51, 51, 255);">"buttonSelection"</span>,<br> ButtonSelectionListener.<span
style="color: rgb(153, 0, 0);">class</span>,<br> <span
style="color: rgb(153, 0, 0);">new</span> MethodDescriptor[] {addButtonSelectionMD},<br> MyCustomPrompter.<span
style="color: rgb(153, 0, 0);">class</span>.getMethod(<span
style="color: rgb(51, 51, 255);">"addButtonSelectionListener"</span>,<span
style="color: rgb(153, 0, 0);">new</span> Class[]{ButtonSelectionListener.class}),<br> MyCustomPrompter.<span
style="color: rgb(153, 0, 0);">class</span>.getMethod(<span
style="color: rgb(51, 51, 255);">"removeButtonSelectionListener"</span>,<span
style="color: rgb(153, 0, 0);">new</span> Class[]{ButtonSelectionListener.<span
style="color: rgb(153, 0, 0);">class</span>})<br> );<br><br><img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif"> addButtonSelectionED.setPreferred(<span
style="color: rgb(153, 0, 0);">true</span>);<br> <br> return <span
style="color: rgb(153, 0, 0);">new</span> EventSetDescriptor[] {addButtonSelectionED};<br><br> } <span
style="color: rgb(153, 0, 0);">catch</span> (Exception e){<br> e.printStackTrace();<br> } <br> <span
style="color: rgb(153, 0, 0);">return null</span>;<br> }<br></pre>
<p>To prompt a method to be preferred requies both the&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_1.gif">
MethodDescriptor being set to preferred and also the&nbsp;<img
style="width: 24px; height: 13px;" alt="" src="../images/tag_2.gif">
EventSetDescriptor.</p>
<p>To test the preferred event launch the Eclipse workbench target
environment and verify that the <span style="font-weight: bold;">Events</span>
pop-up menu displays an item for <span style="font-style: italic;">buttonSelected</span>.</p>
<h1><a name="A_complete_example"></a>A complete example</h1>
<p>This tutorial has gone through the steps required to create the
plugin <span style="font-style: italic;">org.eclipse.ve.example.customwidget</span>.&nbsp;
The completed plugin is available <a href="customwidgetexample.zip">
here</a> or can be obtained directly from CVS.<br>
<br>
To install the plugin from CVS into an Eclipse development environment
attach to the host <span style="font-style: italic;">dev.eclipse.org</span>
and repository path <span style="font-style: italic;">/cvsroot/tools</span>
using a user id of <span style="font-style: italic;">anonymous</span>
with no password required.&nbsp; The figure below illustrates the CVS
perspective in Eclipse with the CVS Repositories view showing the
repository correctly attached to.&nbsp; To create the new repository
open the pop-up menu on the CVS Repositories view and select <span
style="font-style: italic; font-weight: bold;">New &gt; Repository
Location.<br>
<br>
</span> Attach to the repository name<span style="font-style: italic;">/cvsroot/tools</span>
on the host name<span style="font-style: italic;">dev.eclipse.org</span>.&nbsp;
Specify a user name of anonymous which allows the code to be checked
out.<span style="font-style: italic; font-weight: bold;"><br>
</span> <span style="font-style: italic; font-weight: bold;"><br>
<br>
</span> <span style="font-weight: bold;"><img
src="images/RepositoriesView.png" alt="CVSRepositoriesView"
style="border: 1px solid ; width: 399px; height: 144px;"><br>
<br>
</span> The CVS Repositories view showing the correct
repository for the tutorial's finished pugin<br>
<br>
Having attached to the repository expand the <span
style="font-style: italic;">Head</span> tree item and search for the
plugin <span style="font-style: italic;">org.eclipse.ve.examples.&nbsp;</span>
Expand this and select <span style="font-style: italic;">org.eclipse.ve.example.customwidget.</span>&nbsp;
This is the complete plugin and to install it onto your workbench use
the pop-up menu option <span style="font-weight: bold;">Check Out</span>
as shown below<br>
<br>
<img style="border: 1px solid ; width: 395px; height: 272px;" alt=""
src="images/CheckOutAsProject.png">&nbsp;</p>
<h2><a name="Conclusion">Conclusion</a></h2>
<p>In&nbsp; this tutorial, we looked at a high level where to start and
extend the Visual Editor and use specialized property cell editors,
BeanInfo, GEF edit parts, palette, and CodeGen decoders.&nbsp; To do
this required understanding how to use Java build path containers as
the trigger point for Visual Editor custom behavior, and how to inject
specialized code through the user of BeanInfo classes (for cross IDE
extensions) and .override files (for Visual Editor only specific
logic).&nbsp; An XMI file for a new palette category was created, and
also the concept of the target VM was discussed.&nbsp;</p>
<p>The software supplied with this article is for illustrative purposes
only and should be used accordingly. The software is provided as is and
with all faults, and hereby disclaims all other warranties and
conditions, either expressed, implied or statutory, including, but not
limited to, any (if any) implied warranties, duties or conditions of
merchantability, of fitness for a particular purpose, of accuracy or
completeness of responses, of results, of workmanlike effort, of lack
of viruses, and of lack of negligence, all with regard to the software.</p>
<p>Further tutorials will cover some of the topics introduced in more
depth and we welcome all feedback.</p>
<p><small>ref: <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=88801">bug
88801</a></small></p>
<p><small>IBM is trademark of International Business Machines
Corporation in the United States, other countries, or both. 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. Microsoft and Windows are trademarks of Microsoft
Corporation in the United States, other countries, or both. Other
company, product, and service names may be trademarks or service marks
of others.</small></p>
</body>
</html>