| <html> | |
| <head> | |
| <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/> | |
| <title>Eclipse Forms: Rich UI for Rich Client Applications</title> | |
| <link href="../default_style.css" rel="stylesheet"/> | |
| </head> | |
| <body> | |
| <div align="right"> | |
| Copyright © 2005 International Business Machines Corp. | |
| <table border="0" cellpadding="2" cellspacing="0" width="100%"> | |
| <tr> | |
| <td bgcolor="#0080C0" colspan="2" valign="top"> | |
| <p><font color="#FFFFFF"><b> Eclipse Corner | |
| Article</b></font></p> | |
| </td> | |
| </tr> | |
| </table> | |
| </div> | |
| <div> | |
| <h1><img class="center" height="86" src="images/Idea.jpg" width="120"/></h1> | |
| </div> | |
| <h1 class="center">Eclipse Forms: Rich UI for the Rich Client</h1> | |
| <blockquote> | |
| <p><b>Summary</b></p> | |
| <p>Spice up your rich client with rich user experience using | |
| Eclipse Forms. Written as a thin layer on top of SWT, Eclipse | |
| Forms allow you to achieve the Web look in your desktop | |
| applications without using the embedded browser. This allows you | |
| to retain full control of the widgets in the UI and to maintain | |
| portability across all operating systems Eclipse already runs on. | |
| This article will take you from baby steps to advanced topics of | |
| the rich user interface experience of Eclipse Forms.</p> | |
| <p><b>By Dejan Glozic, IBM Canada Ltd.</b></p> | |
| <p>January 16, 2005</p> | |
| </blockquote> | |
| <hr width="100%"/> | |
| <h2>The History (as we see it)</h2> | |
| <p>One of the fundamental features of the Eclipse platform is that | |
| applications built on top of it look, feel and smell like genuine | |
| native applications. Thanks to SWT, menus, windows, trees, tables, | |
| buttons and other widgets all feel 'right' no matter what | |
| OS or windowing system you are on. Being one of the first members | |
| of the Eclipse team, I remember the days when I could get hours | |
| of joy by playing with our prototype Eclipse code. Menus are | |
| real. Tool bars are real. Combos, text, button, check boxes, radios are | |
| all real. There is not a drawn widget in sight, all are native widgets.</p> | |
| <p>For a long time, if your plug-ins contributed Eclipse user | |
| interface artifacts, they would generally fall into the following | |
| categories:</p> | |
| <ol> | |
| <li>Editors</li> | |
| <li>Views</li> | |
| <li>Wizards</li> | |
| <li>Dialogs</li> | |
| </ol> | |
| <p>There are clear presentation rules for artifacts in these categories. | |
| We are used to seeing trees and | |
| tables in views, documents in editors and grids of simple widgets | |
| like buttons and text fields in wizards and dialogs. These rules | |
| are easy to follow and live by as long as your application is | |
| similar in principle to Eclipse SDK.</p> | |
| <p>The RCP (Rich Client Platform) concept in Eclipse 3.x represents | |
| a fundamental broadening of the platform scope. It brought as a | |
| corollary an effective explosion of the problem domains. You can now build Rich | |
| client applications on top of Eclipse that have | |
| little in common with IDEs. While generic workbench parts like | |
| views and editors continue to work well, the widgets that are | |
| populating these parts in IDEs (trees, tables, text editors, etc...) | |
| may not be the best solution for this class of applications. | |
| Available since Eclipse 3.0, Eclipse Forms are designed to offer | |
| appealing alternatives.</p> | |
| <p>Ironically, we developed Eclipse Forms as a solution for a | |
| concrete problem in the Eclipse SDK long before RCP existed as a | |
| concept. Developers of the PDE (Plug-in Development Environment) | |
| working on the plug-in manifest editor did not feel happy with | |
| following a Java editor paradigm of offering a color-coded, | |
| context-assisted text editor for the plugin.xml file. There is | |
| nothing wrong with Java editor in Eclipse by itself - in fact, it | |
| is very powerful and ideally suited for the task. However, it was | |
| designed for editing Java source files. In plug-in manifests, XML | |
| was used as a format to describe data at a higher level of | |
| abstraction. Editing XML by hand, even with color-coding and | |
| context assist/code completion was not perceived as the correct | |
| level of abstraction for the majority of users. In a plug-in | |
| manifest, the syntax itself is not important (yet another thing to | |
| learn). It is the data and what it represents that is important.</p> | |
| <p>A good example of different ways of looking at markup | |
| is HTML authoring tools. At the source code level, all we can see | |
| are nested elements with the associated attributes. Although we see | |
| the syntax, it is hard to visualize what it really represents. A | |
| WYSIWYG view of the document can reveal a table, colors, some texts that span tables, images, etc. | |
| Working with HTML files at this level of | |
| abstraction is vastly more productive because syntax and markup are | |
| hidden in the background (which is the reason why I am typing this | |
| article on a WYSIWYG HTML authoring tool instead of hacking HTML | |
| tags).</p> | |
| <p>It is easy to understand what WYSIWYG concept means for HTML | |
| documents. Since the HTML tags represent instructions for the web | |
| browser on how to compose a document from text, presentation | |
| attributes, hyperlinks and images, WYSIWYG in this context means | |
| editing the document in its final form -- as close as possible to | |
| the way it will appear in the browser. It was harder to figure out | |
| what the alternative presentation would mean for the plug-in | |
| manifest editor. Ultimately, the team made the following decisions:</p> | |
| <ol> | |
| <li>Represent each section of the manifest in the way | |
| most suitable for its nature. For example, vital information | |
| like plug-in name, provider etc. can be easily edited in a text | |
| field. Hierarchical structure of extensions maps nicely into the | |
| tree widget etc.</li> | |
| <li>Show sections of the manifest on separate editor pages, | |
| regardless of their physical order in the source</li> | |
| <li>Pages of the editor would keep a document feel and would be | |
| able to host a mix of widgets, hyperlinks, images and text, and | |
| offer scroll bars when content is too large for the page | |
| size.</li> | |
| </ol> | |
| <p class="center"><img border="0" height="488" | |
| src="images/plugin-overview.jpg" width="546"/></p> | |
| <p class="center"><b>Figure 1: </b>The Plug-in manifest editor as it | |
| first appeared in Eclipse SDK 1.0. It offered a mixture SWT | |
| widgets, hyperlinks and images that could scroll when there is not | |
| enough space (as you would expect in a web browser). Note how all | |
| the widgets have the 'flat' look that was selected for | |
| less clutter and better fit in the document context.</p> | |
| <p>The third point effectively spelled the birth of a plug-in that | |
| now goes by the name of Eclipse Forms. Soon after release 1.0, | |
| other developers wanted to replicate the rich user interface that | |
| appeared in PDE multi-page editors. It was finally made available | |
| as a plug-in with public APIs in Eclipse 3.0. </p> | |
| <p>In the following text, we will show you what Eclipse Forms are | |
| (and what they are not) and how to use them to create rich UI with | |
| little effort.</p> | |
| <h2>Eclipse Forms Mission</h2> | |
| <p>Now that we know how Eclipse Forms came into being, it is useful | |
| to describe their mission before going into details:</p> | |
| <blockquote> | |
| <p><i><b>Eclipse Forms is an</b></i> <img align="baseline" | |
| height="13" src="images/tag_1.gif" width="24"/><i><b>optional | |
| Rich Client plug-in</b></i> <img align="baseline" height="13" | |
| src="images/tag_2.gif" width="24"/><i><b>based on SWT and JFace | |
| that provides the support for creating</b></i> | |
| <img align="baseline" height="13" src="images/tag_3.gif" | |
| width="24"/><i><b>portable web-style user interfaces</b></i> | |
| <img align="baseline" height="13" src="images/tag_4.gif" | |
| width="24"/><i><b>across all Eclipse UI categories.</b></i></p> | |
| </blockquote> | |
| <p>Let's look at the mission statement in more detail:</p> | |
| <blockquote> | |
| <table border="0" bordercolor="#111111" cellpadding="0" cellspacing="0" id="AutoNumber1" style="border-collapse: collapse" width="90%"> | |
| <tr> | |
| <td valign="top" width="25"><img class="center" alt="1" | |
| height="13" src="images/tag_1.gif" width="24"/></td> | |
| <td width="744"> | |
| <b>Optional Rich Client plug-in</b> - Eclipse Forms have | |
| been rewritten in the 3.0 release to depend only on the | |
| platform UI plug-in, and no longer rely on the PDE UI | |
| plug-in. Despite they are not part of the minimal RCP | |
| layer, you can add Eclipse Forms to any RCP application. | |
| </td> | |
| </tr> | |
| <tr> | |
| <td valign="top" width="25"><img class="center" alt="2" | |
| height="13" src="images/tag_2.gif" width="24"/></td> | |
| <td width="744"><b>Based on SWT and JFace</b> - Eclipse Forms | |
| were not designed to compete with or offer an alternative to | |
| SWT or JFace. The plug-in consists of a few carefully chosen | |
| custom widgets, layouts and support classes to achieve the | |
| desired effect when used with SWT and JFace.</td> | |
| </tr> | |
| <tr> | |
| <td valign="top" width="25"><img class="center" alt="3" | |
| height="13" src="images/tag_3.gif" width="24"/></td> | |
| <td width="744"><b>Portable web-style user interfaces</b> -- | |
| obviously, an Eclipse Form often looks like a web page. | |
| The fact that each aspect of the form is | |
| programmatically accessible at all times makes forms | |
| powerful and attractive. Achieving the same flexibility in a | |
| browser would require extensive DOM support and often | |
| proprietary interactions. Eclipse Forms are portable, | |
| being written on top of SWT and JFace.</td> | |
| </tr> | |
| <tr> | |
| <td valign="top" width="25"><img class="center" alt="4" | |
| height="13" src="images/tag_4.gif" width="24"/></td> | |
| <td width="744"><b>Across all Eclipse UI categories</b> - | |
| Eclipse Forms breaks the mode by which certain classes of | |
| widgets are be expected only in certain Eclipse UI categories | |
| (editors, views, wizards, dialogs). An Eclipse form can | |
| appear in any UI category, expanding development | |
| possibilities. The UI developers can use the most appropriate | |
| concept for the task.</td> | |
| </tr> | |
| </table> | |
| </blockquote> | |
| <p>Point <img align="baseline" alt="2" height="13" | |
| src="images/tag_2.gif" width="24"/> cannot be underestimated. When | |
| building interfaces in Eclipse Forms, you are using SWT. There is | |
| no Eclipse Forms button, or Eclipse Forms tree widget as an | |
| alternative to SWT widget. Instead, you are using Eclipse Forms | |
| support to tweak subtly the existing widget set to achieve a richer | |
| user experience.</p> | |
| <p>Eclipse Forms make these rich user interfaces possible with the | |
| following elements:</p> | |
| <ul> | |
| <li>A concept of a 'form' that is suitable for | |
| inclusion in content areas such as views and editors</li> | |
| <li>A toolkit to manage colors, hyperlink groups and other | |
| aspects of a form, and serve as a factory for many SWT | |
| controls</li> | |
| <li>A new layout manager that lays out controls in a manner | |
| similar to an HTML table layout algorithm</li> | |
| <li>A set of custom controls designed to fit in the form | |
| (hyperlink, image hyperlink, scrollable composite, section)</li> | |
| <li>A multi-page editor where most or all of the pages are forms | |
| (e.g. PDE manifest editors)</li> | |
| </ul> | |
| <p><img border="0" height="13" src="images/tip.gif" width="62"/> | |
| Although nothing in the design of Eclipse Forms prevents you from | |
| creating a form in a dialog, most of the usage scenarios have been | |
| focused on using forms in views and editors, rather than dialog and | |
| wizards. It is a matter of consistency -- having only a few | |
| form-based dialogs or wizards would look very strange when all | |
| other dialogs are 'normal'. Nevertheless, it is an | |
| interesting area to explore in the future.</p> | |
| <h2>Baby steps</h2> | |
| <p>It is very easy to start using Eclipse Forms in your user | |
| interfaces. You can start by adding a dependency on | |
| <b>org.eclipse.ui.forms</b> plug-in. We will create an Eclipse view | |
| that hosts a form and gradually fill in the content. Note that the | |
| plug-in with all the source code used in this article is available | |
| as a <a>zip archive</a>.</p> | |
| <h3>Hello, Eclipse Forms</h3> | |
| <p>We will start playing by adding an empty form to a view:</p> | |
| <blockquote> | |
| <pre>public class FormView extends ViewPart { | |
| private FormToolkit toolkit; | |
| private ScrolledForm form; | |
| /** | |
| * The constructor. | |
| */ | |
| public FormView() { | |
| } | |
| /** | |
| * This is a callback that will allow us to create the viewer and | |
| * initialize it. | |
| */ | |
| public void createPartControl(Composite parent) { | |
| <img align="baseline" height="13" src="images/tag_1.gif" width="24"/> toolkit = new FormToolkit(parent.getDisplay()); | |
| <img align="baseline" height="13" src="images/tag_2.gif" width="24"/> form = toolkit.createScrolledForm(parent); | |
| <img align="baseline" height="13" src="images/tag_3.gif" width="24"/> form.setText("Hello, Eclipse Forms"); | |
| } | |
| /** | |
| * Passing the focus request to the form. | |
| */ | |
| public void setFocus() { | |
| form.setFocus(); | |
| } | |
| /** | |
| * Disposes the toolkit | |
| */ | |
| public void dispose() { | |
| toolkit.dispose(); | |
| super.dispose(); | |
| } | |
| }</pre> | |
| </blockquote> | |
| <p>As you can see from this code snippet, it does not take much to | |
| create a form. We start by creating an instance of a toolkit ( | |
| <img align="baseline" height="13" src="images/tag_1.gif" | |
| width="24"/>). We use the toolkit to <img align="baseline" | |
| height="13" src="images/tag_2.gif" width="24"/>create a scrolled | |
| form using the provided composite as a parent. We set the | |
| <img align="baseline" height="13" src="images/tag_3.gif" | |
| width="24"/> title of the form. We also make sure to transfer | |
| focus to the form when needed and dispose the toolkit when the view | |
| is disposed.</p> | |
| <p>When we register the view using the class shown above and launch | |
| the second Eclipse instance, the view should look like this:</p> | |
| <p class="center"><img border="0" height="221" | |
| src="images/hello1.gif" width="217"/> <img border="0" | |
| src="images/hello2.gif"/></p> | |
| <p class="center"><b>Figure 2:</b> A simple empty form in a view. | |
| Making the view narrower will cause the form title to wrap. Once | |
| there is no more space to fit the entire form, scroll bars will | |
| appear.</p> | |
| <p>Note that we have used scrolled form because we placed it in a | |
| view that can be resized. In the more complex situations where a | |
| form needs to be a child in a layout, a non-scrolled version is | |
| available. In this case, we would have called | |
| <code>FormToolkit.createForm()</code> instead and let the outmost | |
| parent worry about scrolling the overall content.</p> | |
| <h3>Adding some content</h3> | |
| <p>Now that we have the form view running, we can start adding some | |
| content to it. Eclipse forms have a body and we should create all | |
| the content there:</p> | |
| <pre>public void createPartControl(Composite parent) { | |
| toolkit = new FormToolkit(parent.getDisplay()); | |
| form = toolkit.createForm(parent); | |
| form.setText("Hello, Eclipse Forms"); | |
| GridLayout layout = new GridLayout(); | |
| <img align="baseline" height="13" src="images/tag_1.gif" width="24"></img> form.getBody().setLayout(layout); | |
| <img align="baseline" height="13" src="images/tag_2.gif" width="24"></img> Hyperlink link = toolkit.createHyperlink(form.getBody(), | |
| "Click here.", SWT.WRAP); | |
| <img align="baseline" height="13" src="images/tag_3.gif" width="24"></img> link.addHyperlinkListener(new HyperlinkAdapter() { | |
| public void linkActivated(HyperlinkEvent e) { | |
| System.out.println("Link activated!"); | |
| } | |
| }); | |
| }</pre> | |
| <p>The body of the form is the usable space below the form title. | |
| Since this space is a SWT <code>Composite</code>, it can serve as a | |
| parent for other widgets. In the code above, we | |
| <img align="baseline" height="13" src="images/tag_1.gif" | |
| width="24"/> set the layout on the body, then <img align="baseline" | |
| height="13" src="images/tag_2.gif" width="24"/> create a | |
| hyperlink. The hyperlink is one of the few custom widgets that | |
| Eclipse Forms provide. The widget allows us to <img align="baseline" | |
| height="13" src="images/tag_3.gif" width="24"/> add a hyperlink | |
| listener so that we can be notified when the user clicks on the | |
| link.</p> | |
| <p>The updated view should look like this:</p> | |
| <p align="center"><img border="0" height="222" | |
| src="images/click-here.gif" width="198"/></p> | |
| <p align="center"><b>Figure 3</b>: A simple form with a | |
| hyperlink</p> | |
| <p>Note how hyperlink has a focus rectangle painted around it. Upon | |
| view activation, focus is transferred to the form, which passes it | |
| to the first control capable of accepting focus -- our link in this | |
| case. With the keyboard focus in the link, simply pressing the | |
| 'Enter' key would activate the link.</p> | |
| <h4>Hyperlink Groups</h4> | |
| <p>Form toolkit has a hyperlink group object. Each created | |
| hyperlink is added to this group object. Hyperlink groups serve | |
| several roles. They define colors -- for normal, hover and active states -- for all links in the group. They change colors of the managed links based on their | |
| state. They change underline style of the managed links based on | |
| their state. They manage cursors and show busy cursor before link | |
| listeners process the link activation, and revert it after. | |
| </p> | |
| <p>You can change the default settings of the hyperlink group by | |
| getting the object from the toolkit with | |
| <code>getHyperlinkGroup()</code>.</p> | |
| <h3>Creating common controls</h3> | |
| <p>One of the design goals of Eclipse Forms was to allow the | |
| creation of common SWT controls in the editor/view content space. | |
| Since form body is a normal composite, you can use any layout and | |
| control you want inside it. However, remember that 'raw' | |
| SWT controls come with a widget background. We will now create some | |
| controls using their constructors:</p> | |
| <pre> layout.numColumns = 2; | |
| GridData gd = new GridData(); | |
| gd.horizontalSpan = 2; | |
| link.setLayoutData(gd); | |
| Label label = new Label(form.getBody(), SWT.NULL); | |
| label.setText("Text field label:"); | |
| Text text = new Text(form.getBody(), SWT.BORDER); | |
| text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); | |
| Button button = new Button(form.getBody(), SWT.CHECK); | |
| button.setText("An example of a checkbox in a form"); | |
| gd = new GridData(); | |
| gd.horizontalSpan = 2; | |
| button.setLayoutData(gd);</pre> | |
| <p>We are now using two columns and creating a label, a text field | |
| and a checkbox. The result is below:</p> | |
| <p class="center"><img border="0" height="183" | |
| src="images/no-toolkit.gif" width="240"/></p> | |
| <p class="center"><b>Figure 4</b>: A form with SWT controls created | |
| directly using their constructors</p> | |
| <p>What is wrong with this picture? The background of controls we | |
| created directly matches the system dialog background, not the form | |
| background. In addition, the text field looks fine because the | |
| screen capture was taken on Windows XP. On other windowing systems, | |
| it would look out of place due to the addition of a 3D border. To | |
| fix this problem, we will create these controls using the | |
| toolkit's factory methods instead:</p> | |
| <pre> Label label = toolkit.createLabel(form.getBody(), "Text field label:"); | |
| Text text = toolkit.createText(form.getBody(), ""); | |
| text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); | |
| Button button = toolkit.createButton(form.getBody(), "A checkbox in a form", SWT.CHECK); | |
| gd = new GridData(); | |
| gd.horizontalSpan = 2; | |
| button.setLayoutData(gd);</pre> | |
| <p>The view will now look better:</p> | |
| <p class="center"><img border="0" height="177" | |
| src="images/with-toolkit.gif" width="233"/></p> | |
| <p class="center"><b>Figure 5:</b> A form with SWT controls created | |
| using the form toolkit as a factory</p> | |
| <p>Factory methods provided by the form toolkit are there for your | |
| convenience. The toolkit is not all-inclusive --even for the SWT | |
| widget set-- and definitely not for the custom controls that you may | |
| have. A utility method <code>FormToolkit.adapt(Control control, | |
| boolean trackFocus, boolean trackKeyboard)</code> should be used to | |
| adapt an existing SWT control to fit into the form. Most of | |
| the factory methods call <code>adapt</code> themselves.</p> | |
| <h4>Achieving the 'flat' look</h4> | |
| <p>One of the recognizable attributes of Eclipse Forms used in PDE | |
| editors was the elegant 'flat' look of the controls. All | |
| the controls used there were without 3D borders that look fine in | |
| dialogs but less appealing in editors or views. This support is | |
| built into the FormToolkit class. However, on some platform it | |
| comes at a price of some custom rendering. For example, look at | |
| this screen capture from PDE editor (version 2.1):</p> | |
| <p class="center"><img border="0" height="507" | |
| src="images/plugin-dependencies.gif" width="545"/></p> | |
| <p class="center"><b>Figure 6:</b> The flat look of Eclipse Forms | |
| circa Eclipse 2.1</p> | |
| <p>Controls like tables, text entries, combo box etc. are rendered | |
| with a flat one-pixel border. These borders do not come from the | |
| controls themselves (SWT.BORDER style is not used). Instead -- if | |
| instructed -- the toolkit will add itself as a paint listener to | |
| each control's parent, and draw borders around controls during | |
| paint events. To make this happen, you need to call the toolkit | |
| method <code>paintBordersFor(parent)</code> for each composite | |
| where you created controls like text, tree, table etc. Note that | |
| one call per parent is enough: there is no need to make a call for | |
| each control of this type.</p> | |
| <p>The Form toolkit knows which controls require a custom border. | |
| However, you may create a new one that also needs a border that is | |
| not on the list. You can give a hint to the toolkit by adding the | |
| following code:</p> | |
| <div> | |
| <blockquote> | |
| <pre>Control myControl = new MyControl(parent); | |
| myControl.setData(FormToolkit.KEY_DRAW_BORDER, <strong>FormToolkit.TEXT_BORDER</strong>); | |
| // or myControl.setData(FormToolkit.KEY_DRAW_BORDER, <strong>FormToolkit.TREE_BORDER</strong>); | |
| toolkit.paintBordersFor(parent);</pre> | |
| </blockquote> | |
| </div> | |
| <p>As you can see from the picture above, 'structural' | |
| controls like trees and tables have a border style different from | |
| text areas and you can choose which one to render for your control. | |
| Note that this is not needed for controls created using | |
| toolkit's factory methods.</p> | |
| <p><img height="13" src="images/win_only.gif" width="49"/> Since | |
| Eclipse 3.0 and on Windows XP, no border rendering is done when the | |
| file <code>javaw.exe.manifest</code> file is present in the | |
| Java virtual machine bin folder (I took all the screen shots in this article on Windows XP). | |
| The presence of this file -- you can download | |
| one from the | |
| <a href="http://dev.eclipse.org/viewcvs/index.cgi/~checkout~/platform-swt-home/faq.html#xpthemes" | |
| >SWT home page</a> -- instructs the toolkit to use XP skins for | |
| native widgets. With XP skins, controls like text, table and tree | |
| are already flat and there is no need to adjust the look. For | |
| your code to be portable, you should always call | |
| <code>paintBordersFor(Composite)</code>, and let the toolkit choose | |
| what to do depending on the windowing system.</p> | |
| <h2>Custom layouts</h2> | |
| <p>Eclipse Forms offer two new layouts in addition to the base SWT layouts. | |
| These layouts extend the SWT <code>Layout</code> base class and | |
| can be used on any SWT composite, but are typically used in | |
| conjunction with Eclipse Forms.</p> | |
| <h3>TableWrapLayout</h3> | |
| <p>Now that we know how to populate the form, let's throw it a | |
| curve. We will change the hyperlink text to be much longer:</p> | |
| <pre> link.setText("This is an example of a form that is much longer "+ | |
| "and will need to wrap.");</pre> | |
| <p>Let's see the result on screen:</p> | |
| <p class="center"><img border="0" height="177" | |
| src="images/long-link.gif" width="233"/></p> | |
| <p class="center"><b>Figure 7</b>: A form laid out using | |
| <code>GridLayout</code></p> | |
| <p>What happened? Remember that we are using | |
| <code>GridLayout</code>. When it asked the link control to compute | |
| its size, it gave it the size needed to render the text in one long | |
| line. Although we instructed the control to wrap, it did not | |
| matter because <code>GridLayout</code> requires that a control | |
| return its size in isolation. The link itself -- as well as other | |
| SWT controls like <code>Label</code> -- is capable of computing the | |
| height given its width if you pass the width instead of | |
| <code>SWT.DEFAULT</code> in <code>computeSize</code>, but | |
| <code>GridLayout</code> is not passing the width as an argument.</p> | |
| <p>What we need is a different layout algorithm that works more | |
| like HTML tables. We want the content to try to fit in the provided | |
| client area, and grow vertically to compensate. Eclipse Forms | |
| provide an alternative layout for just such a purpose called | |
| <code>TableWrapLayout</code>. There are many similarities between | |
| <code>GridLayout</code> and <code>TableWrapLayout</code>. Both | |
| organize parent's children in grids. Both have layout data | |
| that instructs the layout how to treat each control. Both can | |
| accept hints on which control should grab excess space etc.</p> | |
| <p>However, they fundamentally differ in the approach to the | |
| layout. <code>TableWrapLayout</code> starts with columns. It | |
| computes minimal, preferred and maximum widths of each column and | |
| uses this information to assign excess space. It also tries to be | |
| fair when dividing space across columns so that there is no excess | |
| wrapping of some controls.</p> | |
| <p>It is possible to mix <code>GridLayout</code> and | |
| <code>TableWrapLayout</code> but the branch of widgets tree where | |
| <code>GridLayout</code> is used is the one where wrapping stops. | |
| This is quite acceptable if you do not want it to wrap, | |
| typically if the composite contains controls that cannot wrap | |
| anyway, like text, buttons, trees etc... However, you should have an | |
| un-broken path from the form body to each text control that needs | |
| to wrap.</p> | |
| <p>Let's rework our example to use <code>TableWrapLayout</code> | |
| (with changes highlighted):</p> | |
| <pre> public void createPartControl(Composite parent) { | |
| toolkit = new FormToolkit(parent.getDisplay()); | |
| form = toolkit.createForm(parent); | |
| form.setText("Hello, Eclipse Forms"); | |
| <b><font color="#ff0000">TableWrapLayout layout = new TableWrapLayout();</font></b> | |
| form.getBody().setLayout(layout); | |
| Hyperlink link = toolkit.createHyperlink(form.getBody(),"Click here.", SWT.WRAP); | |
| link.addHyperlinkListener(new HyperlinkAdapter() { | |
| public void linkActivated(HyperlinkEvent e) { | |
| System.out.println("Link activated!"); | |
| } | |
| }); | |
| link.setText("This is an example of a form that is much longer and will need to wrap."); | |
| layout.numColumns = 2; | |
| <b><font color="#ff0000">TableWrapData td = new TableWrapData(); | |
| td.colspan = 2; | |
| link.setLayoutData(td);</font></b> | |
| Label label = toolkit.createLabel(form.getBody(), "Text field label:"); | |
| Text text = toolkit.createText(form.getBody(), ""); | |
| <b><font color="#ff0000">td = new TableWrapData(TableWrapData.FILL_GRAB); | |
| text.setLayoutData(td);</font></b> | |
| Button button = toolkit.createButton(form.getBody(), "A checkbox in a form", SWT.CHECK); | |
| <b><font color="#ff0000">td = new TableWrapData(); | |
| td.colspan = 2; | |
| button.setLayoutData(td);</font></b> | |
| }</pre> | |
| <p>We used the same concepts that for GridData. Some of | |
| the variables have different names (for example, | |
| <code>colspan</code> and <code>rowspan</code>, <code>align</code> | |
| and <code>valign</code> are taken from HTML TABLE attributes), but | |
| you are doing the same thing -- creating a grid with two columns | |
| where link and button span two columns. Since margins are the same | |
| as in <code>GridLayout</code>, the result will look similar except | |
| the link will now wrap:</p> | |
| <p class="center"><img border="0" height="177" | |
| src="images/wrapped-link.gif" width="233"/></p> | |
| <p class="center"><b>Figure 8:</b> A form laid out using | |
| <code>TableWrapLayout</code></p> | |
| <p>One of the main differences between <code>TableWrapLayout</code> | |
| and <code>GridLayout</code> is that with the former you should stop | |
| thinking about the vertical dimension. In <code>GridLayout</code>, | |
| you would typically let the 'rigid' controls assume their | |
| natural positions and sizes and let 'flexible' controls | |
| (text, tree and table) grab horizontal and/or vertical excess space. | |
| In contrast, <code>TableWrapLayout</code> works top-down and when | |
| it places all the controls, its work is complete. The concept of grabbing | |
| excess space still exists in the horizontal dimension (as shown | |
| above). However, vertically you can only choose to FILL the cell in | |
| case it is taller than the control, or pick TOP, MIDDLE or BOTTOM | |
| vertical alignment.</p> | |
| <p>You may notice one thing that may seem contradictory to the | |
| previous claim: <code>TableWrapData</code> still has | |
| <code>grabVertical</code> variable. However, the variable is here | |
| for a distinct purpose: when a fixed height control spans | |
| multiple rows, its height will create a local condition where vertical | |
| dimension is known, and controls in the spanned cells need to | |
| divide the extra space between them.</p> | |
| <p>In order to have good results with <code>TableWrapLayout</code>, | |
| ensure that controls that can wrap have the appropriate style bit | |
| (<code>SWT.WRAP</code>). Composite custom controls provided by | |
| Eclipse Forms are wrap-enabled out of the box. This is achieved by | |
| using internal layouts that implement <code>ILayoutExtension</code> | |
| interface:</p> | |
| <blockquote> | |
| <pre>public interface ILayoutExtension { | |
| /** | |
| * Computes the minimum width of the parent. All widgets capable of word | |
| * wrapping should return the width of the longest word that cannot be | |
| * broken any further. | |
| * | |
| * @param parent the parent composite | |
| * @param changed <code>true</code> if the cached information should be | |
| * flushed, <code>false</code> otherwise. | |
| * @return the minimum width of the parent composite | |
| */ | |
| public int computeMinimumWidth(Composite parent, boolean changed); | |
| /** | |
| * Computes the maximum width of the parent. All widgets capable of word | |
| * wrapping should return the length of the entire text with wrapping | |
| * turned off. | |
| * | |
| * @param parent the parent composite | |
| * @param changed <code>true</code> if the cached information | |
| * should be flushed, <code>false</code> otherwise. | |
| * @return the maximum width of the parent composite | |
| */ | |
| public int computeMaximumWidth(Composite parent, boolean changed); | |
| }</pre> | |
| </blockquote> | |
| <p><code>TableWrapLayout</code> implements this interface itself, | |
| which allows it to handle cases where composites with this layout | |
| are children of the composite that is laid out. The additional two | |
| methods allow it to compute the two extreme cases - the absolute | |
| minimum width and the maximum width if all the controls are spread | |
| as wide as possible. The difference between the two allows the | |
| algorithm to distribute extra space fairly between columns to | |
| minimize excess wrapping.</p> | |
| <p>Let's take a closer look at space distribution. We will comment | |
| the code we wrote so far in the view and replace it with the | |
| following:</p> | |
| <pre> layout.numColumns = 3; | |
| Label label; | |
| TableWrapData td; | |
| label = toolkit.createLabel(form.getBody(), | |
| "Some text to put in the first column", SWT.WRAP); | |
| label = toolkit.createLabel(form.getBody(), | |
| "Some text to put in the second column and make it a bit "+ | |
| "longer so that we can see what happens with column "+ | |
| distribution. This text must be the longest so that it can "+ | |
| "get more space allocated to the columns it belongs to.", | |
| SWT.WRAP); | |
| td = new TableWrapData(); | |
| td.colspan = 2; | |
| label.setLayoutData(td); | |
| label = toolkit.createLabel(form.getBody(), | |
| "This text will span two rows and should not grow the column.", | |
| SWT.WRAP); | |
| td = new TableWrapData(); | |
| td.rowspan = 2; | |
| label.setLayoutData(td); | |
| label = toolkit.createLabel(form.getBody(), | |
| "This text goes into column 2 and consumes only one cell", | |
| SWT.WRAP); | |
| label.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB)); | |
| label = toolkit.createLabel(form.getBody(), | |
| "This text goes into column 3 and consumes only one cell too", | |
| SWT.WRAP); | |
| label.setLayoutData(new TableWrapData(TableWrapData.FILL)); | |
| label = toolkit.createLabel(form.getBody(), | |
| "This text goes into column 2 and consumes only one cell", | |
| SWT.WRAP); | |
| label.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB)); | |
| label = toolkit.createLabel(form.getBody(), | |
| "This text goes into column 3 and consumes only one cell too", | |
| SWT.WRAP); | |
| label.setLayoutData(new TableWrapData(TableWrapData.FILL)); | |
| <img align="baseline" height="13" src="images/tag_1.gif" width="24" /> form.getBody().setBackground(form.getBody().getDisplay(). | |
| getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));</pre> | |
| <p>This code creates a number of wrapping labels with text of | |
| variable length. Some labels span columns, some span rows. To make | |
| the test easier, we will <img align="baseline" height="13" | |
| src="images/tag_1.gif" width="24"/> set the form background to | |
| widget background so that cells will be easy to spot. When we run | |
| the example, we will get the following:</p> | |
| <p class="center"><img border="0" height="275" | |
| src="images/wrapped-layout.gif" width="266"/></p> | |
| <p class="center"><b>Figure 9</b>: Excess space distribution in | |
| <code>TableWrapLayout</code></p> | |
| <p>The key in space distribution is that the difference between | |
| control minimum and maximum width is compared. The greater the | |
| difference, the greater allocation of excess width will be for the | |
| column. Excess width is any width greater than the width needed to | |
| fit all the controls with their minimum widths taken into account. | |
| Notice how column 3 is slightly wider than column 2 because text in | |
| column 2 is somewhat longer. The overall goal is to avoid excessive | |
| empty space in cells. If you want to read more about the theory | |
| behind this layout algorithm, go to | |
| <a href="http://www.w3.org/TR/html4/appendix/notes.html#h-B.5.2.2"> | |
| W3C recommendations for HTML table auto-layout</a>.</p> | |
| <h3>ColumnLayout</h3> | |
| <p>Another Eclipse Forms custom layout is a variation of SWT | |
| <code>RowLayout</code>. If we configure <code>RowLayout</code> to | |
| place children vertically -- in columns-- and to make all controls | |
| have the same width within a column, we would get several columns, | |
| depending on the width of controls. However, the last column would | |
| typically not be completely filled -- depending on the number of | |
| controls. When placed in a form, we would again get all the | |
| controls in one column because <code>RowLayout</code> cannot do | |
| 'vertical' wrapping. If we use <code>GridLayout</code> | |
| instead, we would have to choose the number of columns up front and | |
| live with the choice.</p> | |
| <p>There are situations in more complex forms where we want the | |
| number of columns to be adaptive. In other words, we would like the | |
| number to change depending on the width of the form -- use more | |
| when possible, drop the number down as the width decreases. We | |
| would also like to fill the form area equally like a newspaper | |
| layout, with all the columns roughly the same height. All this can | |
| be achieved with <code>ColumnLayout</code>.</p> | |
| <p>Compared to <code>TableWrapLayout</code>, | |
| <code>ColumnLayout</code> is much simpler. Hardly any configuration | |
| is needed. The only choice you need to make is the range of columns | |
| you want to have (default is 1 to 3). The following example shows a | |
| form with a large number of sections (we will talk about sections | |
| later) using <code>ColumnLayout</code>. Initially, there is enough | |
| space to arrange the sections in two columns. | |
| When we make the editor narrower, the layout arranges the sections in only one column:</p> | |
| <p class="center"><img border="0" height="481" | |
| src="images/two-columns.gif" width="583"/> <img border="0" | |
| height="480" src="images/one-column.gif" width="413"/></p> | |
| <p class="center"><b>Figure 10</b>: Sections arranged in columns | |
| using <code>ColumnLayout.</code> The layout started with two | |
| columns but dropped to one when there was not enough space to fit | |
| all the sections.</p> | |
| <h2>Complex controls</h2> | |
| <p>Eclipse Forms provide four complex custom controls that can help | |
| you build rich looking UI: expandable composite, section, image | |
| hyperlink and form text. Let's look closely at each of them.</p> | |
| <h3>Expandable composite</h3> | |
| <p>A common theme in sleek web pages is the ability to collapse a | |
| portion of the page content using a toggle control. Eclipse Forms | |
| offer such a control: <code>ExpandableComposite</code>.</p> | |
| <div> | |
| <pre> ExpandableComposite ec = toolkit.createExpandableComposite(form.getBody(), | |
| ExpandableComposite.TREE_NODE| | |
| ExpandableComposite.CLIENT_INDENT); | |
| ec.setText("Expandable Composite title"); | |
| String ctext = "We will now create a somewhat long text so that "+ | |
| "we can use it as content for the expandable composite. "+ | |
| "Expandable composite is used to hide or show the text using the " | |
| "toggle control"; | |
| Label client = toolkit.createLabel(ec, ctext, SWT.WRAP); | |
| ec.setClient(client); | |
| td = new TableWrapData(); | |
| td.colspan = 2; | |
| ec.setLayoutData(td); | |
| ec.addExpansionListener(new ExpansionAdapter() { | |
| public void expansionStateChanged(ExpansionEvent e) { | |
| form.reflow(true); | |
| } | |
| });</pre> | |
| </div> | |
| <p>The composite accepts a number of styles that control its | |
| appearance and behavior. Style TREE_NODE will create the toggle | |
| control used in a tree widget for expanding and collapsing nodes, | |
| while TWISTIE will create a triangle-style toggle. Using EXPANDED | |
| will create the control in the initial expanded state. If style | |
| COMPACT is used, control will report width in the collapsed state | |
| enough to fit in the title line only (i.e. when collapsed, it will | |
| be as compact horizontally as possible). Finally, CLIENT_INDENT | |
| will indent the client to align with the title (otherwise, client | |
| will be aligned with the toggle control).</p> | |
| <p><code>ExpandableComposite</code> is responsible for rendering | |
| the toggle control and the title. The client control to expand or | |
| collapse must be a direct child of the expandable composite.</p> | |
| <p>We needed to add expansion listener to the control and 'reflow' | |
| the form on the state change. This is because expansion causes | |
| changes in expandable composite size, but the change will not take | |
| effect until the next time the parent is laid out (hence the need | |
| to force it). In general, every time you do something that causes | |
| the layout of the form to be invalid, you need to | |
| 'reflow' the form. 'Reflowing' the form will reposition the | |
| controls according to the new sizes and update the scroll bars.</p> | |
| <p>Our view now looks like this:</p> | |
| <p class="center"><img border="0" height="215" | |
| src="images/expandable-closed.gif" width="305"/></p> | |
| <p class="center"><b>Figure 11</b>: An example of the expandable | |
| composite in the collapsed state</p> | |
| <p>When you click on the '+' sign or on the title itself, | |
| composite expands to reveal the client:</p> | |
| <p class="center"><img border="0" height="216" | |
| src="images/expandable-open.gif" width="304"/></p> | |
| <p class="center"><b>Figure 12</b>: An example of the expandable | |
| composite in the expanded state</p> | |
| <p>The expandable composite uses | |
| an internal layout implementing Eclipse Forms <code>ILayoutExtension</code>. Therefore you can add it to a parent that uses | |
| <code>TableWrapLayout</code>, as we did in the example above.</p> | |
| <h3>Section</h3> | |
| <p>One of the most versatile custom controls in Eclipse Forms (and | |
| seen in all PDE editors) is <code>Section</code>. It extends the | |
| expandable composite and introduces the following concepts:</p> | |
| <ul> | |
| <li> | |
| Separator - a separator control can be created below the | |
| title | |
| </li> | |
| <li> | |
| Description - an optional description can be added below the | |
| title (and below the separator, if present) | |
| </li> | |
| <li> | |
| Title bar - a title bar that encloses the section can be | |
| painted behind the title (note that separator and title bar | |
| should not be used simultaneously) | |
| </li> | |
| </ul> | |
| <p>The code is similar to the expandable composite code example:</p> | |
| <pre> Section section = toolkit.createSection(form.getBody(), | |
| Section.DESCRIPTION|Section.TITLE_BAR| | |
| Section.TWISTIE|Section.EXPANDED); | |
| td = new TableWrapData(TableWrapData.FILL); | |
| td.colspan = 2; | |
| section.setLayoutData(td); | |
| section.addExpansionListener(new ExpansionAdapter() { | |
| public void expansionStateChanged(ExpansionEvent e) { | |
| form.reflow(true); | |
| } | |
| }); | |
| section.setText("Section title"); | |
| section.setDescription("This is the description that goes "+ | |
| below the title"); | |
| Composite sectionClient = toolkit.createComposite(section); | |
| sectionClient.setLayout(new GridLayout()); | |
| button = toolkit.createButton(sectionClient, "Radio 1", SWT.RADIO); | |
| button = toolkit.createButton(sectionClient, "Radio 2", SWT.RADIO); | |
| section.setClient(sectionClient);</pre> | |
| <p>This time, we used the TWISTIE toggle style, added the | |
| description and asked for the title bar to be painted. The view now | |
| looks like this:</p> | |
| <p class="center"> <img border="0" height="255" | |
| src="images/section.gif" width="305"/></p> | |
| <p class="center"><b>Figure 13</b>: An expandable section with a | |
| painted title bar and a description</p> | |
| <h3>Image hyperlink</h3> | |
| <p>Image hyperlink is a subclass of <code>Hyperlink</code> that | |
| adds an image before the link text. This combination is so common | |
| that it just made a lot of sense to make one control out of it and | |
| save on widgets. The control can be used as an image link only | |
| (when no text is set), or as a combination of link and image. | |
| Images for normal, hover and active (selected) state can be set.</p> | |
| <p>The following is an example of a rich user experience that uses | |
| image hyperlinks:</p> | |
| <p class="center"><img border="0" height="430" | |
| src="images/intro.gif" width="616"/></p> | |
| <p class="center"><b>Figure 14</b>: A form taken from one of the | |
| Eclipse Welcome pages (this is a fallback presentation used for the | |
| cases when embedded browser creation fails)</p> | |
| <h3>Form text control</h3> | |
| <p>Using the combination of labels, hyperlinks, images and | |
| <code>TableWrapLayout</code>, it is possible to create complex and | |
| powerful forms. However, there are some things that are hard to do. | |
| Consider the following example from the PDE manifest editor:</p> | |
| <p class="center"><img border="0" height="466" | |
| src="images/plugin-overview.gif" width="532"/></p> | |
| <p class="center"><b>Figure 15</b>: An example of a complex Eclipse | |
| form that mixes wrapped text, images and hyperlinks</p> | |
| <p>Notice how images, hyperlinks and text snippets are mixed | |
| together. This is very hard using separate label and hyperlink | |
| widgets. To remedy the problem, Eclipse Forms plug-in provides a | |
| very rudimentary text control that can do the following:</p> | |
| <ul> | |
| <li> | |
| Render plain wrapped text | |
| </li> | |
| <li> | |
| Render plain text but convert any segment that starts with | |
| <b>http://</b> into a hyperlink on the fly | |
| </li> | |
| <li> | |
| Render text with HTML-like tags (the form used in Figure 15 | |
| is using form text widgets in this mode) | |
| </li> | |
| </ul> | |
| <p>In all the modes, form text control is capable of rendering | |
| either a string or an input stream.</p> | |
| <h4>Rendering normal text (label mode)</h4> | |
| <div> | |
| <pre> FormText formText = toolkit.createFormText(form.getBody(), true); | |
| td = new TableWrapData(TableWrapData.FILL); | |
| td.colspan = 2; | |
| formText.setLayoutData(td); | |
| String text = "Here is some plain text for the text to render."; | |
| formText.setText(text, false, false);</pre> | |
| </div> | |
| <div> | |
| <p>Second argument set to <code>false</code> means that we will | |
| not bother to parse the tags, and the third that we will not try | |
| to expand URLs if found.</p> | |
| </div> | |
| <h4>Automatic conversion of URLs into hyperlinks</h4> | |
| <p>Now we will add a hyperlink to the text and turn the third | |
| argument into <code>true</code>:</p> | |
| <pre> FormText formText = toolkit.createFormText(form.getBody(), true); | |
| td = new TableWrapData(TableWrapData.FILL); | |
| td.colspan = 2; | |
| formText .setLayoutData(td); | |
| String text = "Here is some plain text for the text to render; "+ | |
| this text is at http://www.eclipse.org web site."; | |
| formText .setText(text, false, <b>true</b>);</pre> | |
| <p>When we look at our view, it now looks like this:</p> | |
| <p class="center"><img border="0" height="287" | |
| src="images/form-text1.gif" width="305"/></p> | |
| <p class="center"><b>Figure 16</b>: Form text control with a URL | |
| automatically converted into a hyperlink</p> | |
| <p>The URL has been converted into a link. The link is part of the | |
| wrapped text - we did not have to create a separate | |
| <code>Hyperlink</code> control and try to sandwich it between the | |
| two labels.</p> | |
| <p>Since form text control can render hyperlinks, it accepts the | |
| same hyperlink listeners we used before. When created by the | |
| toolkit, the form text will use the hyperlink settings from the | |
| hyperlink group that belongs to the toolkit.</p> | |
| <h4>Parsing formatting markup</h4> | |
| <p>The most powerful use of the form text control is when | |
| formatting tags are added to the text. The expected root tag is | |
| 'form'. It can have one or more children that can either | |
| be <p> or <li>. Either of these can have normal text, | |
| text between <b> or <span> tags, images and links. | |
| Images are declared using <img href="<i>image | |
| key</i>"/> (no content), while links are expressed using | |
| <a href="<i>href</i>">text</a>.</p> | |
| <p>Some of the tags mentioned above have additional attributes. Tag | |
| <a> can accept nowrap='true' to block | |
| the link from being wrapped into the new line. Tag <p> can | |
| have attribute vspace='false' (true by | |
| default) that adds additional space between paragraphs when set to | |
| 'true'. Tag <li> has more attributes:</p> | |
| <ul> | |
| <li> | |
| <b>style</b> - can be "text", "bullet" | |
| and "image" (default is "bullet") | |
| </li> | |
| <li> | |
| <b>value</b> - not used for "bullet"; if style is | |
| "text", the value will be rendered instead in place | |
| of a bullet; if style is "image", value represents a | |
| key in the image table of an image to be rendered in place of a | |
| bullet | |
| </li> | |
| <li> | |
| <b>vspace</b> - the same as for the 'p' tag. | |
| </li> | |
| <li> | |
| <b>indent</b> - the number of pixels to indent text | |
| </li> | |
| <li> | |
| <b>bindent</b> - the number of pixels to indent the bullet | |
| (this number is independent from 'indent' - be | |
| careful not to overlap them) | |
| </li> | |
| </ul> | |
| <p>Tags that affect appearance of the normal text are <b> | |
| (works as expected), and <span>. The latter allows you to | |
| change font and/or color of the text within the tag. Finally, soft | |
| line breaks can be added using <br/> tag.</p> | |
| <p><img border="0" height="13" src="images/tip.gif" width="62"/> | |
| Since Eclipse 3.1, it is possible to place an SWT control that is a | |
| child of the form text in the markup. The new element | |
| 'control' accepts attribute 'href' that is a | |
| key to the Control object set using | |
| <code>FormText.setControl(String key, Control control)</code>. | |
| Optionally, attribute "fill" can be set to | |
| <code>true</code> to make the control fill the entire width of the | |
| text. Form text is not responsible for creating or disposing | |
| controls, it only places them relative to the surrounding text. | |
| Similar to <img>, vertical position of the control relative | |
| to the surrounding text can be set using the 'align' | |
| attribute.</p> | |
| <p>How does all this work in practice? Let's make data text | |
| that will use all of these tags together:</p> | |
| <pre> StringBuffer buf = new StringBuffer(); | |
| buf.append("<form>"); | |
| buf.append("<p>"); | |
| buf.append("Here is some plain text for the text to render; "); | |
| buf.append("this text is at <a href=\"http://www.eclipse.org\" "+ | |
| "nowrap=\"true\">http://www.eclipse.org</a> web site."); | |
| buf.append("</p>"); | |
| buf.append("<p>"); | |
| buf.append("<span color=\"header\" font=\"header\">"+ | |
| "This text is in header font and color.</span>"); | |
| buf.append("</p>"); | |
| buf.append("<p>This line will contain some <b>bold</b> and "+ | |
| "some <span font=\"code\">source</span> text. "); | |
| buf.append("We can also add <img href=\"image\"/> an image. "); | |
| buf.append("</p>"); | |
| buf.append("<li>A default (bulleted) list item.</li>"); | |
| buf.append("<li>Another bullet list item.</li>"); | |
| buf.append("<li style=\"text\" value=\"1.\">A list item with text.</li>"); | |
| buf.append("<li style=\"text\" value=\"2.\">Another list "+ | |
| item with text</li>"); | |
| buf.append("<li style=\"image\" value=\"image\">List item with "+ | |
| "an image bullet</li>"); | |
| buf.append("<li style=\"text\" bindent=\"20\" indent=\"40\" value=\"3.\">"+ | |
| "A list item with text.</li>"); | |
| buf.append("<li style=\"text\" bindent=\"20\" indent=\"40\" value=\"4.\">"+ | |
| "A list item with text.</li>"); | |
| buf.append("<p> leading blanks; more white \n\n new "+ | |
| "lines <br/> \n more <b> bb </b> white . </p>"); | |
| buf.append("</form>"); | |
| FormText formText = toolkit.createFormText(form.getBody(), true); | |
| formText.setWhitespaceNormalized(true); | |
| td = new TableWrapData(TableWrapData.FILL); | |
| td.colspan = 2; | |
| formText.setLayoutData(td); | |
| formText.setImage("image", FormArticlePlugin.getDefault(). | |
| getImageRegistry().get(FormArticlePlugin.IMG_SAMPLE)); | |
| formText.setColor("header", toolkit.getColors(). | |
| getColor(FormColors.TITLE)); | |
| formText.setFont("header", JFaceResources.getHeaderFont()); | |
| formText.setFont("code", JFaceResources.getTextFont()); | |
| formText.setText(buf.toString(), true, false); | |
| formText.addHyperlinkListener(new HyperlinkAdapter() { | |
| public void linkActivated(HyperlinkEvent e) { | |
| System.out.println("Link active: "+e.getHref()); | |
| } | |
| });</pre> | |
| <p>One common theme that can be observed is that the widget itself | |
| is not responsible for loading images, fonts, resolving links or | |
| colors. This is not a browser and it is much better to separate | |
| concerns and simply assign images and colors managed elsewhere. | |
| Both links and images simply have 'href' attribute to | |
| reference them. For links, the value of this attribute will be | |
| provided in the hyperlink event when listeners are notified. Images | |
| need to be registered with the text control using the matching | |
| 'href' key. This way, the control does not need to worry | |
| about loading the images - it has them in the hash table and can | |
| render them immediately.</p> | |
| <p>A similar approach has been used for colors and fonts. Colors | |
| are already handled by the toolkit, so you can allocate as many as | |
| you want using a unique key and RGB values by calling | |
| <code>toolkit.getColors().createColor(String key, RGB rgb)</code>. | |
| What is left is to set all the colors referenced in the | |
| 'span' tag so that the control will be able to use them | |
| during rendering.</p> | |
| <p>When the code above is executed, the view looks like this:</p> | |
| <p class="center"><img border="0" height="545" | |
| src="images/form-text2.gif" width="308"/></p> | |
| <p class="center"><b>Figure 17</b>: Form text rendered from the XML | |
| markup</p> | |
| <p>If we expand the section and the expandable composite, and make | |
| the window narrower, the form still holds and everything wraps | |
| perfectly:</p> | |
| <p class="center"><img border="0" height="651" | |
| src="images/form-text3.gif" width="236"/></p> | |
| <p class="center"><b>Figure 18</b>: The sample view made taller and | |
| narrower</p> | |
| <h2>Appropriate usage and limitations</h2> | |
| <p>Although the image above is very promising, it is very important | |
| to contain excitement. A 'prime directive' of the form | |
| text control is:</p> | |
| <blockquote> | |
| <p><b>"Form text control is not, nor will it ever be, a web | |
| browser"</b></p> | |
| </blockquote> | |
| <p>It is very easy to spot limitations of the control. Tags within | |
| list items or paragraphs cannot be nested. Bold is supported, but | |
| not italic (although any font can be set and associated via the | |
| 'span' tag). Attributes for vertical alignment of text | |
| with respect to images are missing. List support is decidedly low | |
| level. There is no BIDI support.</p> | |
| <p>Another important limitation to consider is performance. Form | |
| text is neither a performance nor memory hog, but it was written to | |
| be small and lean, not powerful. For that reason, it does not have | |
| sophisticated painting routines, dirty region management etc. These | |
| routines are cost-effective when the control owns the entire window | |
| and must be scalable. In contrast, form text is best suited for | |
| short snippets of tagged text that are mixed with other controls on | |
| a form. This way, the control is one of several children in the | |
| parent, allowing native dirty region management from the OS to | |
| handle repaints. The best results in Eclipse forms are achieved | |
| with a mixture that is similar to our example above.</p> | |
| <p><img border="0" height="13" src="images/tip.gif" width="62"/> | |
| Performance and painting of the form text widget has been improved | |
| in Eclipse 3.1 and it can now handle more content without | |
| performance degradation. For example, the new Help view is using | |
| form text widget for rendering hundreds of images and search hits. | |
| Nevertheless, the usage guidelines outline above still stand.</p> | |
| <p>If you have a problem with the form text limitations, you should | |
| consider alternatives:</p> | |
| <ul> | |
| <li>If you need editing capability and text styling (with | |
| different fonts and colors), use <code>StyledText</code> (used by | |
| styled text editors like Java editor in Eclipse)</li> | |
| <li>If you only need read-only support but have complex text | |
| formatting needs, use | |
| <code>org.eclipse.swt.browser.Browser</code>. Embedded web | |
| browser works on most platforms and will give you full HTML | |
| support.</li> | |
| </ul> | |
| <p>What this widget is for is to provide for modest text formatting | |
| in combination with <code>TableWrapLayout</code> and other controls | |
| in a form. The power lies in the fact that you have full access to | |
| every control - a kind of direct access that you can only achieve | |
| in a browser if you use proprietary DOM access mechanisms. In | |
| contrast, Eclipse Forms are portable - they run everywhere SWT | |
| runs.</p> | |
| <p>To conclude, use the form text widget:</p> | |
| <ul> | |
| <li>when the UI you want to render is not very long with many | |
| lines of text, hyperlinks and many images in complex layouts (use | |
| embedded browser for that)</li> | |
| <li>when you want to mix text, hyperlinks and images with SWT | |
| controls like trees, tables and buttons.</li> | |
| <li>when you want to run everywhere SWT runs</li> | |
| </ul> | |
| <p>In contrast, use embedded web browser:</p> | |
| <ul> | |
| <li> | |
| when the UI you want to render contains many lines of text, | |
| hyperlinks and images arranged in complex layouts | |
| </li> | |
| <li> | |
| when you do not need to mix SWT controls like trees and | |
| tables with the text | |
| </li> | |
| <li> | |
| when you want to use complex web technologies like | |
| animation, sound or servlets/JSPs and/or render external web | |
| pages in-place | |
| </li> | |
| <li> | |
| when you want to achieve complex rendering effects like | |
| transparency (all SWT widgets are opaque) | |
| </li> | |
| <li> | |
| when you only need to ship on OS and/or window system | |
| combinations where the embedded browser is fully supported | |
| </li> | |
| </ul> | |
| <h2>Advanced Topics</h2> | |
| <p>As usual in the real-world development, there is a chasm between | |
| simple, happy examples that get you started and real code shipped | |
| in products. This section covers aspects of Eclipse Forms that are | |
| employed in production Eclipse code. You do not need to use | |
| them right away, but chances are you will recognize their | |
| advantages as your plug-in grows in complexity. In the following | |
| text, we will address color and toolkit management, managed forms, | |
| master/details block and multi-page editors.</p> | |
| <h3>Color And Toolkit Management</h3> | |
| <p>When using forms in a non-trivial way, it is important to share | |
| as much as possible to conserve resources. For this reason, color | |
| management should be separated from the toolkit when there is more | |
| than one form to handle.</p> | |
| <p>Of course, it is possible to create one toolkit per form, but | |
| that is too wasteful if there are many forms. Instead:</p> | |
| <ul> | |
| <li> | |
| Create one toolkit for all the forms that have the same life | |
| cycle. For example, if creating a multi-page editor, create one | |
| toolkit per editor and dispose it when editor is disposed. All | |
| the pages in the editor should share this toolkit. | |
| </li> | |
| <li> | |
| Create one color manager (<code>FormColors</code>) per | |
| plug-in. When creating the toolkit, pass the color manager to | |
| the toolkit. The toolkit will know that the colors are shared | |
| and will not dispose them. | |
| </li> | |
| <li> | |
| Use platform support for fonts and if possible, use | |
| <code>JFaceResources</code> predefined fonts. Between default, | |
| 'banner' and 'header' fonts, you can | |
| accomplish a lot. Using many fonts is very confusing for the | |
| user, and if you do manage your own, you must ensure | |
| alternatives across platforms. The JFace fonts are guaranteed | |
| to work on all the platforms Eclipse ships on. | |
| </li> | |
| <li> | |
| Dispose the color manager on plug-in shutdown (do not | |
| assume that plug-in shutdown also means platform shutdown - in | |
| Eclipse 3.x OSGi can uninstall your plug-in dynamically with | |
| the platform still running). | |
| </li> | |
| <li> | |
| Use form color manager to allocate all the colors needed by | |
| the forms. | |
| </li> | |
| </ul> | |
| <h3>Managed forms</h3> | |
| <p>Managed forms are wrappers that add life cycle management and | |
| notification to form members. A managed form is not a form by | |
| itself. It <i>has</i> a form and accepts registration of | |
| <code>IFormPart</code> element. For each <code>IFormPart</code>, it | |
| manages events like dirty state, saving, commit, focus, selection | |
| changes etc. In order to reach to the wrapped form widget, call the | |
| '<code>getfForm()'</code> method.</p> | |
| <p>Not every control on the form needs to be a form part. It is | |
| better to group a number of controls and implement | |
| <code>IFormPart</code> interface for the group. Section is a | |
| natural group and Eclipse Form provides <code>SectionPart</code> | |
| implementation. It implements the interface and contains a | |
| <code>Section</code> instance (either created outside and passed | |
| into the constructor, or created in the part itself).</p> | |
| <h3>Master/Details block</h3> | |
| <p>'Master/Details' is a pattern used throughout the UI world. It | |
| consists of a list or a tree ('master') and a set of | |
| properties ('details') driven by the selection in the | |
| master. Eclipse Forms provide the implementation of the pattern as | |
| a useful building block with the following properties:</p> | |
| <ul> | |
| <li> | |
| While 'details' part is managed by the class | |
| itself, the master part factory method is abstract and must be | |
| implemented by the subclass | |
| </li> | |
| <li> | |
| Master and details parts are children of a sash form and the | |
| ratio of the form space allocated for each can be changed by | |
| moving the sash. | |
| </li> | |
| <li> | |
| As usual with a sash form, master and details parts can be | |
| organized horizontally or vertically in the form. | |
| </li> | |
| </ul> | |
| <p>The idea of master/details block is to create a tree or a table | |
| section that fires the selection notification via the managed form. | |
| If the details part can handle the selected object, it should | |
| switch to the page for it and display properties. When building on | |
| top of the provided master/details block, subclasses should:</p> | |
| <ul> | |
| <li> | |
| Create the master part (the one that drives the details) | |
| </li> | |
| <li> | |
| Contribute actions to the form tool bar (consumes | |
| upper-right portion of the form in the title area) | |
| </li> | |
| <li> | |
| Register details pages, one for each distinct input that can | |
| arrive from the master part | |
| </li> | |
| </ul> | |
| <p>We will show how this looks in practice using the source code | |
| that accompanies this article. It creates a table for the master | |
| part and hooks a few dummy objects of two distinct types. Two | |
| details pages are registered to handle selections of these types. | |
| Pages can contain any number of controls - they are created on | |
| demand in the provided parent. The details area scrolls separately | |
| from the master area.</p> | |
| <p>This part can now be used anywhere, but in this example it was | |
| placed inside an editor. Two distinct object types were used | |
| (<code>TypeOne</code> and <code>TypeTwo</code>), and their classes | |
| were used directly as keys (other mapping between details pages and | |
| objects are possible). Details pages registered with the Details | |
| part need to implement <code>IDetailsPage</code> interface.</p> | |
| <p>The page is first initialized with the managed form to get | |
| access to the toolkit and other objects. It is then asked to create | |
| contents in the provided parent. It should also set focus on the | |
| first control when asked, be able to refresh, commit, dispose and | |
| react to the input changes. As long as objects selected in the | |
| master part are of a compatible type, the page will stay visible | |
| and <code>inputChanged</code> will be called.</p> | |
| <p>Let's see how all this looks in practice:</p> | |
| <p class="center"><img border="0" height="402" | |
| src="images/master-details1.gif" width="604"/></p> | |
| <p class="center"><b>Figure 19</b>: An example of a master/details | |
| block in horizontal orientation hosted in an editor</p> | |
| <p>An instance of <code>TypeOne</code> object is selected in the | |
| master part. The appropriate page for the type is loaded in the | |
| details part. The page can contain any number of controls | |
| introduced elsewhere in this article. The ratio of parts on the | |
| page can be changed by scrolling the sash (visible when mouse goes | |
| over the area between the parts). Also note two actions in the | |
| upper-right corner of the form - this is the form tool bar. In this | |
| case, two radio buttons were contributed to control orientation of | |
| the part (horizontal or vertical).</p> | |
| <p>If we change the orientation and select one of the | |
| <code>TypeTwo</code> instances, we get into this state:</p> | |
| <p class="center"><img border="0" height="403" | |
| src="images/master-details2.gif" width="604"/></p> | |
| <p class="center"><b>Figure 20:</b> The same block in vertical | |
| orientation and with a different element type selected</p> | |
| <p>Orientation is now vertical, and a different details page is | |
| shown for the type.</p> | |
| <p>It is possible to register a detail page provider instead of | |
| registering pages up front. This allows dynamic resolution of the | |
| details page for the selected object. It is particularly important | |
| for cases when different pages are needed for objects of the same | |
| type depending on their states.</p> | |
| <h3>Multi-page form editors</h3> | |
| <p>It was a long way to get to this topic, yet PDE multi-page | |
| editors were the first to spark interest in Eclipse Forms. Today, | |
| multi-page editors still represent the most common use case of the | |
| technology, even though it now starts to appear in other places.</p> | |
| <p>Eclipse Forms are designed to work in a variety of | |
| settings. For this reason, the plug-in cannot make assumptions on | |
| the types of editor inputs your editor can receive. A number of | |
| concepts employed in PDE UI cannot be used here because without | |
| knowing about the editor input in more detail, it is hard to | |
| provide a set of reusable classes. Nevertheless, Eclipse Forms | |
| provide the basic support for multi-page editors, which you can | |
| build on.</p> | |
| <p>You should start building an Eclipse Forms multi-page editor by | |
| extending <code>FormEditor</code>:</p> | |
| <blockquote> | |
| <pre>public class SimpleFormEditor extends FormEditor { | |
| public SimpleFormEditor() { | |
| } | |
| protected FormToolkit createToolkit(Display display) { | |
| // Create a toolkit that shares colors between editors. | |
| return new FormToolkit(ExamplesPlugin.getDefault(). | |
| getFormColors(display)); | |
| } | |
| protected void addPages() { | |
| try { | |
| addPage(new FreeFormPage(this)); | |
| addPage(new SecondPage(this)); | |
| addPage(new ThirdPage(this)); | |
| addPage(new MasterDetailsPage(this)); | |
| addPage(new PageWithSubPages(this)); | |
| } | |
| catch (PartInitException e) { | |
| // | |
| } | |
| } | |
| public void doSave(IProgressMonitor monitor) { | |
| } | |
| public void doSaveAs() { | |
| } | |
| public boolean isSaveAsAllowed() { | |
| return false; | |
| }</pre> | |
| </blockquote> | |
| <p>A very simple way to get started is to create pages and add them | |
| as above. Each page needs to implement <code>FormPage</code> and | |
| override <code>createFormContent(IManagedForm managedForm)</code>. | |
| Since there is already a managed form in each page, | |
| you should create contents in that enclosed form and register | |
| any form part that needs to be part of the managed life cycle.</p> | |
| <p>In addition to form pages, you can add one or more text editors | |
| as a raw source alternative to the GUI pages. For this, you should | |
| call <code>addPage(IEditorPart, IEditorInput | |
| input)</code> method in the super class.</p> | |
| <h3>Multi-page editor example</h3> | |
| <p>The source code that comes with this article contains an example | |
| of a multi-page editor suitable for inclusion in an RCP application | |
| because it does not have any dependencies on IDE plug-ins.</p> | |
| <p>Once you launch another Eclipse application, customize the | |
| perspective by checking the following checkbox in the test Eclipse | |
| window:</p> | |
| <p>Window>Customize Perspective...>Commands>Eclipse Forms | |
| Article</p> | |
| <p>This will add a menu to the menu bar called 'Form Article | |
| Editors'. The menu contains only one action - 'Simple | |
| Form Editor'. The action will open the editor. It has the | |
| following pages:</p> | |
| <p class="center"><img border="0" height="401" | |
| src="images/editor1.gif" width="604"/></p> | |
| <p class="center"><b>Figure 21</b>: A multi-page editor page with a | |
| free-flowing text</p> | |
| <p>The first page contains a page with a <code>TableWrapLayout</code> | |
| and some sample content including a <code>FormText</code> widget. The | |
| page content is free-form and will wrap and flow top to | |
| bottom.</p> | |
| <p>In contrast, the second page contains 'stretchy' controls -- two | |
| table viewers -- that consume all the excess space on the page. Since | |
| the controls can scroll themselves, a | |
| <code>GridLayout</code> is used. Several PDE editor pages follow this pattern.</p> | |
| <p class="center"><img border="0" height="403" | |
| src="images/editor2.gif" width="603"/></p> | |
| <p class="center"><b>Figure 22</b>: A multi-page editor page with | |
| sections and tables.</p> | |
| <p>The third page (Flow Page) was shown before in the | |
| <code>ColumnLayout</code> section. It demonstrates how to | |
| use this layout to adjust to the available space. | |
| Master/Details sections are also shown above.</p> | |
| <p>The last page shows how to embed a<code>CTabFolder</code> in | |
| order to add another dimension to a form. In this particular example, the | |
| actual content is not switched -- there is only one text control -- | |
| but its content is loaded from different objects depending on the | |
| selected tab.</p> | |
| <p class="center"><img border="0" height="404" | |
| src="images/subpages.gif" width="606"/></p> | |
| <p class="center"><b>Figure 23:</b> A multi-page editor page with | |
| nested tabs</p> | |
| <h4>Recommended practices for Eclipse Forms multi-page editors</h4> | |
| <p>There are many ways to write a form-based | |
| multi-page editor. It depends on the type of content you are | |
| editing and the proficiency of your users. You can approach it in two ways: | |
| </p> | |
| <ol> | |
| <li> | |
| If the typical users are using the editor infrequently, if raw | |
| source is hard to edit by hand or complex, if your users are not | |
| very technical, you should make COMPLETE pages capable of editing every aspect of the content without | |
| the need to turn to the raw source. In this approach, a source editor | |
| page is there only for occasional validation, rather than for | |
| regular work. In that case, you can get away with a basic | |
| text editor. The PDE extension point schema editor falls into | |
| this group. | |
| </li> | |
| <li> | |
| If your users are more technical, if they have no problem editing | |
| the file by hand but would appreciate some help from time to | |
| time, then consider providing a mixed experience -- make a good | |
| source editor with all the add-ons like incremental outline, | |
| context assist, syntax highlighting etc. Then, add complex | |
| value-added functionality in form pages for actions that are hard to | |
| achieve when editing raw source. We have learned from experience that it is | |
| very hard to convince seasoned users to switch from source | |
| editing if the value added is marginal or debatable. However, | |
| when a function is only available in GUI pages and provides value and usability, it is adopted readily. | |
| </li> | |
| </ol> | |
| <p>Creating a quality multi-page editor with mixed GUI and | |
| source pages has its challenges. Accepting that users will switch | |
| pages frequently requires a good model of the underlying content. | |
| The model should be directly tied to the underlying document(s) to stay | |
| in sync when users edit the raw text directly and | |
| when they change it structurally through the forms pages. Also, do not | |
| forget indirect changes caused by other workbench actions while | |
| the editor is open.</p> | |
| <p>For ideas on how to do this, see the source code of PDE editors | |
| (org.eclipse.pde.ui plug-in) from the Eclipse <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.pde.ui/">CVS repository</a>.</p> | |
| <h2>Conclusion</h2> | |
| <p>The goal of this article was to introduce you to a great way | |
| to create powerful user interfaces in Eclipse 3.x. Eclipse Forms | |
| is neither a competing widget toolkit that you need to choose over | |
| SWT, nor does it make the embedded HTML browser widget obsolete. | |
| Instead, it is a carefully written extension of SWT that allows you | |
| to create surprisingly rich user interfaces in Eclipse while | |
| retaining the portability of SWT. In simple cases, it can also be a | |
| lightweight alternative to the SWT embedded browser widget. When | |
| used within its limitations, Eclipse Forms can spice up your | |
| applications and allow you to introduce a familiar Web-like metaphor.</p> | |
| <h2>Source Code</h2> | |
| <p>To run the example or view the source code for this article, go | |
| through the following steps:</p> | |
| <ol> | |
| <li>Unzip <a href="formsArticle.zip">formsArticle.zip</a> into | |
| your workspace location in the file system.</li> | |
| <li>Import the extracted project (org.eclipse.ui.forms.article) | |
| into your workspace using 'File>Import>Existing | |
| Project into Workspace'</li> | |
| <li>Browse the source code (under 'src' directory).</li> | |
| <li>When ready, launch another Eclipse using 'Run>Run | |
| As>Eclipse Application'</li> | |
| <li>To browse the sample view, use 'Window>Show | |
| View>Other...>Eclipse Forms Article Examples>Eclipse | |
| Form'</li> | |
| <li>To browse the multi-page editor, check the | |
| 'Window>Customize Perspective>Commands>Eclipse | |
| Forms Article' checkbox to activate the action set. After | |
| that, activate the editor from the newly added 'Form Article | |
| Editors' menu.</li> | |
| </ol> | |
| </body> | |
| </html> | |