The latest addition in the Flamingo component suite is support for pluggable resizing policies on the ribbon tasks and ribbon bands. This has been one of the items on the roadmap for version 4.0 (code named Fainnear), and is now available in the latest 4.0dev drop of Flamingo core and 5.1dev drop of Substance Flamingo plugin.
The existing support has been in place for more than two years, but it was quite flaky. It would often happen that making the ribbon progressively smaller resulted in a jarring resizing behavior of individual bands, and recently a bug report was filed on inconsistent layouts that sometimes enter into an infinite re-layout loop. In addition, the resizing decisions were rigid and not configurable by the application code.
This has finally been addressed in the latest 4.0dev drop of the core Flamingo library. The entire layout / resizing layer has been completely revisited, making the code much simpler, more modular, and, more importantly, configurable by the application code. I will talk about the relevant APIs at the end of this entry, but first let me show a few screenshots that illustrate the out-of-the-box resize policies.
The first screenshot shows the progressive collapse of different ribbon bands under the core CollapseFromLast resize sequencing policy. Under this policy, the ribbon bands are being collapsed from right to left. When the currently collapsing band has reached the last step (iconified), the band to its left becomes the next one to be collapsed.

The next screenshot shows the progressive collapse of different ribbon bands under the core RoundRobin resize sequencing policy. Under this policy, the ribbon bands are being collapsed in a cyclic fashion, distributing the collapsed pixels between the different bands. Under this resize sequencing policy, when the ribbon gets shrinked it is still possible for a specific band to have more width – see the transition from step 5 to step 6 below.

When a ribbon band is fully collapsed (iconified), its contents can be shown by clicking on its collapse button. Unlike before, the display state of the popup band contents is controlled by the most permissive resize policy installed on that band. Here is a screenshot of a popup ribbon band under the core Restrictive resize policy that makes the three trailing buttons to be displayed in MEDIUM display state (unlike before where they were shown in BIG state):

As before, the popups can be multi level (a drop-down gallery shown from a collapsed ribbon band). The command button menus work as well:

Command buttons in popup ribbon bands show their rich tooltips:

Note that all screenshots are taken under Ubuntu and the native GTK look-and-feel. This illustrates how the core Flamingo components adapt the currently set look-and-feel.
If you are interested in testing the new resizing policies in your applications, here is a quick introduction (until the formal documentation is ready). All the relevant code is in the org.jvnet.flamingo.ribbon.resize package.
There are two main concepts – resize policy and resize sequencing policy. The resize policy defines a single visual state of the given ribbon band. For every control in the specific ribbon band (command button, gallery etc), the resize policy defines what is its display state. The resize sequencing policy defines which ribbon band will be chosen next when the ribbon is shrinked / expanded.
The base interface for the resize policies is defined in the RibbonBandResizePolicy interface.The new JRibbonBand.setResizePolicies API can be used to install a custom set of resize policies on the specific ribbon band. The CoreRibbonResizePolicies factory provides two core resize policies list – permissive and restrictive. The default permissive list starts with a resize policy that shows all command buttons and ribbon galleries in the BIG display state, fully utilizing the available screen space. The restrictive list starts with a resize policy that respects the associated ribbon element priority set on the specific component – this is what is used in the last three screenshots (where the popup band shows one BIG button and three MEDIUM buttons).
The base interface for the resize sequencing policies is defined in the RibbonBandResizeSequencingPolicy interface. The new RibbonTask.setResizeSequencingPolicy API can be used to install a custom resize sequencing policy on the specific ribbon task. The CoreRibbonResizeSequencingPolicies factory provides two core policies – round robin and collapse from last. Under the default round robin policy, the ribbon bands are being collapsed in a cyclic fashion, distributing the collapsed pixels between the different bands. Under the collapse from last policy, the ribbon bands are being collapsed from right to left.
If your application needs more control over the resizing of the specific ribbon task or ribbon band, you can implement one (or both) of these interfaces and install them with the APIs mentioned above. To see the default round robin resize sequencing policy and permissive resize policy in action, click the WebStart launch button below and play with the application width:

As always, you are more than welcome to leave comments and report bugs on the project issue tracker, mailing lists or forums.
The previous entry has talked about the implementation details of the Eclipse Help view, and how it is using an embedded HTTP server powered by Jetty to serve dynamic content from a number of sources. Once you have such a custom server in place, you can embed a Browser control in any view / editor and call its setUrl method to show the required content. The links in the browser control will be handled in the same way as in the usual browser control – relative links will be served by the same HTTP server, and absolute links can point to content on the intranet or even external internet pages. But what about the live help actions?
The org.eclipse.help.ILiveHelpAction interface defines an entry point from Eclipse Help view “back” into Eclipse itself. If you include the PLUGINS_ROOT/org.eclipse.help/livehelp.js in your HTML document, you can attach a javascript:liveAction handler on the links in your document. This handler gets three parameters:
- ID of the plugin that contains the class defined by the second parameter
- Fully qualified class name that must implement the ILiveHelpAction interface
- Possibly empty parameter passed to the setInitializationString of the live help action instance
When such a link is clicked, the setInitializationString() and run() methods of the specified class are called. How does this work, and how can this be extended to work outside the Help view in any embedded browser control?
Here is the flow of execution in Eclipse 3.4 (all of these details are internal and subject to change in the future versions).
- The Help view is a collection of HTML pages. These are served from the org.eclipse.help.webapp plugin.
- One of the pages has an IFrame with 0*0 dimension named liveHelpFrame.
- The implementation of liveAction JavaScript method in the livehelp.js locates that frame and sets its location to the URL that encodes the three parameters (plugin ID, class name and argument string)
- A special livehelp servlet registered on the Jetty server gets this request. This servlet is implemented in org.eclipse.help.internal.webapp.servlet.LiveHelpServlet class.
- The doGet method checks that the embedded web server is running, and that the first two parameters are not null.
- The helper BaseHelpSystem.runLiveHelp locates the plugin bundle and loads the specified class. An instance of this class is created (the implicit assumption is that there is a public no-arg constructor).
- If specified, the argument string is passed to the setInitializationString of the created instance.
- A daemon thread based on this instance is created and started. Note that if your live help action needs access to the UI layer (to display a dialog, for example), the logic in the run method needs to be wrapped in Display.runAsync call.
rent a car bulgaria
Note that the above flow does not mention the actual contents of the 0*0 IFrame being used in the process. The whole reason for this frame’s existence is to make a call to the live help servlet. The LiveHelpServlet.doGet does not make anything with the resp object.
As can be seen from this flow, including the livehelp.js and putting a javascript:liveAction on the HTML anchor is not enough. The implementation of the JavaScript liveAction method makes certain checks to ensure that the browser is the one from the Help view. As such, if you click on this link in a browser control placed in another view, it will not result in invoking the specified action.
Until this functionality is supported by Eclipse in a published way, we can mimic this flow in a custom view / editor. Here are the basic steps – assuming that you have a browser control and a Jetty server / servlet already configured.
- Add two more servlets. The first will serve the “core” content, such as a custom livehelp.js, the initial blank content of the invisible IFrame and possibly a custom CSS. The second will handle the live help requests.
- Modify your existing servlet (that serves the usual HTML pages) to inject two pieces into every HTML file that it serves.
- The first piece is a HEAD tag to include the livehelp.js from the new core servlet. This piece can also include a link to the custom global CSS file.
- The second piece is a 0*0 IFrame named liveHelpFrame with initial content set to a blank page served by the core servlet. It is very important to obey the cross-scripting limitations placed by the browsers to make sure that a javascript handler on the main content can change the location of this IFrame.
- Implement the livehelp.js based on the core Eclipse script. You can simplify the implementation since you know exactly where to look for that IFrame. Get the URL of the window, strip away the trailing parts and replace them to point to your live help servlet. Add plugin ID, class name and the argument to the resulting URL to make sure that these are passed to the servlet. Finally, set the complete URL to be the location of the invisible IFrame. This will result in a call to the servlet, but leave the visible browser content unchanged.
- The implementation of the core servlet is very simple, fetching the required content from the bundled files (just like the servlet that is serving the rest of your files).
- The implementation of the live help servlet is the same as the core Eclipse one. Parse the parameters, make sure that the plugin ID and class name are present, load the class, create an instance of that class and then run its run method on a new daemon thread.
Congratulations – you have your own browser that is able to display a rich collection of interlinked documents and invoke actions defined in your plugin classes, interacting with other parts of your plugins / application.
How is Eclipse Help view implemented? This view is a rich collection of interlinked documents that provide the usual functionality of embedding images and navigating between different pages. In addition, it supports live help actions – hyperlinks that can call Eclipse actions (Java code). How is this implemented?
In a usual setup, the HTML content is stored in the file system. If the requested HTML page contains embedded images, these are stored as separate files, and requested separately by the browser. However, the main contents of Eclipse Help view come from one single file – the org.eclipse.platform.doc.user.jar in the plugins folder. This jar contains around one thousand files (in Eclipse 3.4), including HTML and PNG images. How do these get displayed in the Eclipse Help view?
A straightforward approach would be to “explode” the contents of this jar at runtime (the first time the Help view is activated) and then link directly to the files in the filesystem. This is simple to implement, but would require some bookkeeping to clean the files on closing the workspace. Also, you’re going to pay the performance penalty the first time the files need to be extracted from the archive and written to the disk. Instead, Eclipse 3.4 uses an embedded Jetty HTTP server with custom servlets to serve the content of the Help view.
While the implementation of the Help view is deep inside the internal packages of org.eclipse.help.webapp plugin, this functionality can be recreated by using public extension points (thus ensuring upgradability to the next Eclipse versions). The steps below describe the general setup of an embedded Help HTTP server.
First, you need to specify three extension points in your plugin.xml. For the complete example see the plugin.xml of the org.eclipse.help.webapp plugin. The extension points are:
Jumping a little ahead of time (the complete structure will be explained later), the URLs requested from the HTTP server will look like this:
http://127.0.0.1:12345/primaryID/secondaryID/relative/path/to/your.html
The primaryID is the HTTP context ID specified in the first extension point above. It is also used in the specification of the second and third extension points. The secondaryID allows mapping your content via different servlets (see later). In the simplest example (where all content is coming from the same archive), you will have only one servlet specified in the third extension point. The last identification string is specified on the second extension point – it is the other.info filter on the service selector. This string must be the same as the one set during the initialization of Jetty server (see below).
Your MANIFEST.MF will need two changes. The first one is the Import-Packages section and should have the following entries:
- javax.servlet
- javax.servlet.http
- org.osgi.service.http
The second one is in the Require-Bundle section and should have the following entries:
- org.eclipse.equinox.http.jetty
- org.eclipse.equinox.http.servlet
- org.eclipse.equinox.http.registry
These sections will make sure that you will be able to use the relevant classes in your custom Jetty server and servlets.
The next step is the class that controls the lifecycle of the embedded Jetty server. This is the 127.0.0.1:12345 part in the URL above – it is a local HTTP server that is listening on port 12345. Since this specific port may be taken by another application, we are going to ask Jetty to auto select an available port. The complete implementation of the Jetty configurator can be found in the org.eclipse.help.internal.server.WebappServer class, and the main steps are:
-
Make sure that you’re running only one instance of the HTTP server (instead of creating a new instance for each HTTP request).
-
The http.port parameter should be set to 0 to allow Jetty to auto-select an available port.
-
The context.path parameter should be set to the HTTP context ID (primaryID in the example above).
-
The other.info parameter should be set to the same value as the service selector filter in the second extension point in the plugin.xml.
-
INFO / DEBUG messages of Jetty should be suppressed.
-
To check that Jetty has successfully started, get the org.eclipse.equinox.http.registry bundle and check that its state is RESOLVED.
-
To get the Jetty port (for creating the URLs), get the service reference for org.osgi.service.http.HttpService class and (other.info=yourServiceSelectorFilter) filter. Then, get the http.port property and cast it to Integer.
The next step is to create a custom servlet that will intercept the relevant HTTP requests and load the content from your archive. The complete (and very simple) example can be found in the org.eclipse.help.internal.webapp.servlet.ContentServlet class (registered with the third extension point above). In its init() method it creates a custom connector instance (more info below) and uses it in the doGet() and doPost() methods.
The last piece is the connector itself. It analyzes the incoming request, maps it to the corresponding resource and then transfers the resource contents to the response output stream. The beauty of this connector is that the content can come from anywhere. It can be a local file, a file in an archive, or it can be dynamically generated (corresponding to the requested resource, of course).
While EclipseConnector looks at a variety of sources to get the content and provides a custom error page implementation, the logic is very simple. In a simple example where all the content is coming from one archive, you create a URLClassLoader pointing to that jar (this should be done in the constructor to make the subsequent requests faster) and use the getResourceAsStream passing the trailing portion of the URL (stripping away the host, port, primary ID and secondary ID parts). If the returned InputStream is null, you can return a custom error page.
While the above may sound an overkill, it is quite useful and much more flexible than shipping a huge collection of separate files. With a custom HTTP server and a servlet you can control the contents of error page, fetch the content from multiple locations or even create the content dynamically from a database or another source.
Here are some Swing links that you might have missed during the last week:
- Roman Kennke posts an update on the Java2D stack on VxWorks which is now functional enough to run SwingSet2. The followup post has more screenshots of SwingSet2 running under JamaicaVM and OpenJDK stack.
- Looks like JavaFX development is going to bring performance improvements back to Java2D and Swing applications. Bug 6766336 aims to use SSE / MMX CPU instructions to speed up the software pipeline – i have mentioned that while the new Direct3D-accelerated pipeline is great for the modern hardware, the “enterprise” desktops usually only have integrated cards. Bug 6766342 aims to improve the (closed-source) Ductus rasterizer on anti-aliased paths, while bugs 6767500, 6767506 and 6767516 aim to improve performance of various primitives on the hardware accelerated pipelines.
- An interesting bug (6740419) has been opened to provide better control over text grid fitting in Java2D. The subject of printing fidelity has been addressed at length last year by Jeff Atwood and Joel Spolsky, and it looks like the designer team behind JavaFX is pushing for Apple-style font rendering in JavaFX. I have already talked about why it is a bad idea, and the introduction of DirectWrite in Windows 7 (more on this in a later post) will obviate the need to invest the precious time in supporting this feature in JavaFX.
- Jean Francois Poilpret has announced release candidate for release 1.0 of DesignGridLayout.
- Adam Bien compares Eclipse RCP and NetBeans RCP and leans towards the later in his recommendations. I don’t have any experience with NetBeans RCP, but i’ve been doing heavy Eclipse / SWT work over the last three years at work. I have almost never considered SWT / Eclipse to be more limiting that Swing. In fact, once you understand that it’s better not to fight the platform and instead tweak your design to match the recommended UI guidelines of the platform (re vertical labels in tables), you will find SWT / JFace combination (especially with the Instantiations designer) a very productive and enjoyable environment. Not to mention that you can most certainly create non-Eclipse looking SWT applications, and this is going to be much easier in the near future.
- Ayman Al-Sairafi has announced release 0.9.3 of the JSyntaxPane component. New in this release – line numbering, reworked Find / Replace dialog and support for Python, C, C++ and Ruby syntax.
Finally, if you are interested in the responses to my posting on the state of core Swing, you’re welcome to read the following:
And Dale Beermann has an interesting series about moving a large Java project to Flash and ActionScript. The first post addresses the reasons why this port has been done, while part 2, part 3 and part 4 (ongoing series) address the specific technical issues in porting Java code to ActionScript.