The latest addition in the Flamingo component suite is support for horizontal scrolling of collapsed ribbon tasks and shrinked task toggle buttons. 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 new functionality kicks in when you start to shrink the ribbon frame horizontally. At a certain point, the content needs to be either shrinked or scrolled, depending on the minimum size of the corresponding ribbon components and the overall content of the frame. The first screenshot shows three first stages of the ribbon component at progressively smaller widths (all the screenshots in this entry are taken under the Substance Business skin):

The second step shows that the contextual task group header (in the title pane) does not overflow into the bounds of the min / max / close buttons. The third step shows what happens when there is not enough width to show the preferred content of all the task toggle buttons – they begin to shrink (note the last letters that are cut off on some of the buttons), and the area shows horizontal dividers between the buttons.

At a certain point, there is not enough space to show all the task toggle buttons under the minimum width (that is still able to show the first few letters). At this point, the area that hosts the task toggle buttons becomes a scrollable panel:

Clicking on the scroller buttons scrolls the task toggle buttons:

Finally, at some point there is not enough space to show the ribbon bands under the most restrictive resize policy. At that point, the area that hosts the ribbon bands becomes a scrollable panel as well:

As above, clicking the scroller buttons scrolls the ribbon bands:

There are a few usability points built in to this mechanism:

  • When the task toggle buttons become shrinked, the left / right insets become gradually smaller to allow showing more text (compare with the first two steps).
  • When the task toggle buttons become shrinked, they show the full title in the tooltip.
  • You can mouse-wheel the task toggle button area to cycle through the tasks (as before). When you cycle to a task which button is not visible, it will be scrolled to and revealed.
  • The content can be scrolled repeatedly by pressing and holding the mouse over a scroller button.
  • Once the content reaches the edge, the corresponding button is disabled.

If you want to see the scrolling in action under the core look-and-feels, run the following WebStart demo:

If you want to see this functionality under Substance, run the following WebStart demo:

If you want to test the new functionality in your applications, you would need the following (the last two only for applications running under Substance look-and-feel):

The latest 4.0dev drop of Flamingo also introduced a breaking API change. The support for help ribbon task has been removed. Instead (as in the screenshots above), you can place a help button on the far right side of the task toggle buttons using the new org.jvnet.flamingo.ribbon.JRibbon.configureHelp API. It gets two parameters – the icon and the action listener that will be invoked when the button is clicked.

Your feedback is, as always, greatly appreciated.

Here are some Swing links that you might have missed during the last week:

JavaFX 1.0 is one week away, and the full feature list is still unknown. However, an interesting bug report has found its way to the bug parade (bug 6770914):

http://javaweb.sfbay.sun.com/~ngthomas/javafx/mediaplayer/test.html

This is the javafx media player applet. At the bottom of the applet, there are three buttons, which will trigger a javascript -> fx call:

document.getElementById(“app”).script.playVideo(url);

with will change the video clip playing inside the applet. It works with 6u10, and our latest 6u12 nightly. But with 6u11 b03, document.getElementById(“app”).script is undefined/null

Looks like an applet playing media and being controlled by JavaScript associated with HTML buttons. Is this an example of enhanced applet support? At this point, it will take nothing short of a spectacular collection of applets to make them a viable competitor (and no, dragging the applets to desktop is not going to be it).

EclipseCon 2009 submission

November 20th, 2008

In the spirit of transparency and openness, the submission process for EclipseCon 2009 conference is very refreshing. As the main site says

The selection is done transparently and in the open. Specifically, all submissions are made through our submission system. Everyone in the community (including you) is invited to review the submissions, ask for more information, provide comments and critiques – just as everyone in community is invited and encouraged to do for Eclipse bugs and features.

I have just submitted a proposal to talk about our experiences in developing a visual designer for form-based applications, built on top of rich Eclipse tools such as the core platform itself, as well as JDT, EMF, GEF, VE and JEM. The proposal is called “On The Shoulders of Giants: Harnessing the Power of Eclipse Enterprise Ecosystem“, and you are more than welcome to leave comments on the entry. Here is the abstract:


Code reuse in large projects is not just a trendy buzzword. If you can build upon solid, evolving and well tested foundations that are developed and maintained by committed teams, you have much less code to test, integrate and support. The Eclipse Ecosystem is a prime example of an extremely rich foundation for building enterprise grade applications, and this talk is going to show the diverse, yet interoperable technologies that allow businesses to concentrate on their specific requirements without reinventing the plumbing layers.

A part of a larger client-facing offering, Amdocs Smart Client Designer is an advanced visual designer that allows seamless collaboration between designers and developers in creating complex business form-based applications for Support Call Centers in the telecommunication industry. Harnessing the power of such technologies as JDT, GEF, EMF, JEM and VE has allowed us to dramatically reduce the effort to build the basic blocks of the tool (such as persistence, code generation and java syntax tree manipulations). In addition, core platform features such as task and job managers, builders, natures, markers and many more are enabling user-centric asynchronous business flows in a clean, simple and maintainable way.

Building on top of a vibrant and evolving ecosystem has been a pleasant experience, further strengthened by a recent migration to Java 6, Eclipse 3.4 and the latest version of the dependent plugins. In addition, we are going to talk about the “Eclipse way” of designing the flows, where the existing core features guide the design process to facilitate familiar flows and simpler implementation.

If you are developing a large Eclipse-based offering, or considering Eclipse as the vehicle for your next enterprise-grade tool, come to our session to hear about our experiences in this area.

The usual way of creating a Java project is by showing a wizard that guides the user through the different configuration options. In case you want to customize the existing wizard (add a new page, for example), you specify the org.eclipse.ui.newWizards extension point in your plugin.xml and specify a new wizard section with project attribute set to true. But what if you want to create a new Java project in a purely programmatical way without showing any wizard dialog?

The published API to configure the Java project is the org.eclipse.jdt.ui.wizards.JavaCapabilityConfigurationPage. It has two public utility methods, createProject and configureJavaProject that do most of the heavy lifting. The first problem is that the second method is not static (which means that you need an instance of this page to call it), and the second problem is that the implementation of these methods is calling into internal classes. Fortunately, all the APIs that are required to create a new custom Java project are published. Let’s take a look at the sequence of steps.

First, call ResourcesPlugin.getWorkspace().getRoot().getProject(projectName) to get the IProject handle. Calling exists() will let you know whether the project named projectName already exists. All the following steps assume that this project does not yet exist.

Next, call project.create and project.open. This will create and open the new project.

Now it’s time to create the source folders for the project. Suppose you want to create a source folder named custom. Start by creating a new IPath instance with IPath customPath = new Path(“custom“). Next, call IFolder customFolder = project.getFolder(customPath) and finally customFolder.create(true, true, null). If you have more than one source folder, repeat the steps above for each one of them. A source folder can be a link to a directory on your hard disk. To mark the source folder as link, call IFolder.createLink API, passing the path to the hard disk location. The second parameter can be IResource.ALLOW_MISSING_LOCAL to allow the creation of the link source folder even if the linked target folder does not (yet) exist.

Next step is configuring the classpath entries for the new project. The classpath entries include:

  • your source folders
  • your custom jars
  • the JRE container

To create an IClasspathEntry instance that corresponds to your source folder, call JavaCore.newSourceEntry(project.getFullPath().append(customPath)) where customPath is the IPath instance created above.

The simplest way to create the classpath entries for the JRE container is to use the PreferenceConstants.getDefaultJRELibrary() method. This will return the classpath entries for the default JRE of the workspace. If you want to use another JRE, you would need to iterate through the VM install types returned by the JavaRuntime.getVMInstallTypes(), and iterate through the VM installs for each one of them. The IVMInstall does not expose an API to check its Java compliance. Cast it to AbstractVMInstall and check its getJavaVersion() to the specific compliance spec string (such as JavaCore.VERSION_1_6 for Java 6.0, for example). Once you find a matching JRE, you can get its classpath entries with the following:

  • Get the JRE container path with IPath containerPath=new Path(JavaRuntime.JRE_CONTAINER)
  • Assuming that you have found a matching AbstractVMInstall, create its path by IPath vmPath = containerPath.append(vmInstall.getVMInstallType().getId()).append(vmInstall.getName())
  • Now, the classpath entry of that JRE is simply JavaCore.newContainerEntry(vmPath)

To create a classpath entry for a custom jar (with optional javadoc and source attachments), use JavaCore.newLibraryEntry API. The first parameter is the path to the jar file that can be constructed with the various FileLocator APIs. The sources can be specified via the second and the third parameters. The javadoc attachment is passed in the classpath attribute array (fifth parameter). To construct an IClasspathAttribute entry, use JavaCore.newClasspathAttribute API with IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME name and “file:filePath” value where the filePath is the URL of your javadoc file.

Next step is to create a IJavaProject by using IJavaProject javaProject=JavaCore.create(project).

Next step is to add the Java nature to the new project. This is done by getting the IProjectDescription of the project with the IProject.getDescription, creating a new String[] array to hold an additional entry, copying all the existing nature IDs (from IProjectDescription.getNatureIds() API), adding the JavaCore.NATURE_ID entry and setting back the description.

Next step is to create the default output folder for the project. The name of the default output folder can be taken from the PreferenceConstants.getPreferenceStore().getString(PreferenceConstants.SRCBIN_NAME) and the folder itself is created with the same IProject.getFolder and IFolder.create APIs as for the source folders. The only difference is in that the output folder needs to be marked as derived. In order to do this, pass IResource.FORCE | IResource.DERIVED as the first parameter to the IFolder.create method and call IFolder.setDerived(true) afterward.

At this point, the project is ready to be refreshed (before the actual classpath is set). Call project.refreshLocal with IResource.DEPTH_INFINITE).

Next step is to set the classpath on the java project. Call javaProject.setRawClasspath passing the array of all the classpath entries created before.

The next optional step involves setting custom natures and moving the Java builder in the builder sequence. If your project is going to have a custom nature with custom builders, you first need to add the custom nature(s) to the project description. This is done in exactly the same way as with the java nature above. After setting the nature, you might want to move the default Java builder down in the sequence. This is relevant if the Java builder (the one that compiles the source Java classes) needs to be invoked after your custom builder(s) – the ones that generate additional Java classes, perhaps. To do so, get the build spec sequence from IProjectDescription.getBuildSpec array and shuffle the commands as necessary.

The final step is to set the Java compliance settings on the project. This is done to enforce the different Java rules. Get the current settings from IJavaProject.getJavaOptions. Next, set the following entries in the map:

  • JavaCore.COMPILER_COMPLIANCE to the matching JavaCore constant, such as JavaCore.VERSION_1_6.
  • JavaCore.COMPILER_SOURCE to the matching JavaCore constant, such as JavaCore.VERSION_1_6.
  • JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM to the matching JavaCore constant, such as JavaCore.VERSION_1_6.
  • JavaCore.COMPILER_PB_ASSERT_IDENTIFIER to JavaCore.ERROR to prevent using assert as a valid identifier.
  • JavaCore.COMPILER_PB_ENUM_IDENTIFIER to JavaCore.ERROR to prevent using enum as a valid identifier.

After setting these entries, store the options back with IJavaProject.setOptions

Congratulations – now you have a new Java project with custom source folders (some of them linked), custom jars, an output folder and custom builders set. And all of this without the user having to click through the wizard screens.