Substance 6.0 roadmap

October 13th, 2009

Today I want to share my plans for the next major release of Substance look-and-feel library. I’ve started the development of version 6.0 (code-named Sonoma) about a week ago, and it’s time to talk about the major changes that are coming in this release.

  • Removal of deprecated methods / classes. All APIs detailed at the end of release notes for version 5.3 have been removed from the latest 6.0dev drop. If your application is using one or more of these APIs, consult the release notes to see what you should use instead.
  • Restructuring the code base. Due to lack of proper modularity in Java, some of the internal utility classes have been incorrectly viewed as published APIs by applications. Version 6.0 will have two major packages – substance.api and substance.internal. The application code can only use the api package, and the bundled test applications have been corrected to follow this guideline. For most applications this will require simple re-organization of import sections.
  • Renaming the main package. In a few days the main package will be renamed from org.jvnet.substance to org.pushingpixels.substance. For most applications this will require simple re-organization of import sections.
  • Moving animations to use Trident library. The internal animation engine from the Laf-Widget library will be replaced by the Trident animation library.

Smaller changes planned for Substance 6.0:

  • Polishing of existing skins and a few new skins
  • Support for custom decoration areas – pending performance evaluation
  • Improving performance of tables
  • Further support for High DPI mode

Applications using Substance will be mostly affected by package renaming and usage of Trident.

If your code is setting Substance via a fully-qualified class name, you will need to replace “org.jvnet.substance.skin…” with “org.pushingpixels.substance.api.skin…“. Otherwise you will just need to reorganize your imports section.

Switching to use Trident will require applications to add the matching trident.jar to the classpath (in addition to substance.jar). If you are running Substance-powered application in a signed WebStart environment, you will need to sign the Trident jar with the same key.

The latest 6.0dev drop of Substance contains some of the changes described above. The deprecated APIs have been removed, the packages are now organized in api / internal – but not yet under org.pushingpixels.substance, and custom animations in the test application are powered by Trident.

If you have any questions, comments, suggestions or objections, please open a discussion on the project forums or mailing lists.

Trident 1.1 official release

October 12th, 2009

I am thrilled today to announce the availability of the final release for version 1.1 of Trident animation library (code-named Bogeyman). Most of the new functionality in this version was driven by the user feedback, and includes the following:

In addition to the bundled sample applications, Trident has two blueprint projects. These projects show how to use Trident to drive complex animation scenarios in Internet-enabled rich applications that show graphic information on music albums. Project Onyx is the Swing implementation (see detailed walkthroughs), and Project Granite is the SWT implementation (see detailed walkthroughs).

New Onyx screens

If you have Java 7 installed on your machine, click the button below to launch the WebStart version of Project Onyx:

You are more than welcome to take Trident 1.1 for a ride and report any problems in the project mailing lists, forums or issue tracker.

While Trident requires Java 6 for both the compile and runtime, Emmanuel Bourg has shared his tips on what is required to compile and run version 1.1 of the library under Java 5 and Java 1.4 – complete with a patch for the relevant classes and the build script. While these tips are relevant for the current state of the codebase, Trident core may at any point switch to using Java 6 specific APIs if they are found to be beneficial to the development of the library.

Finally, release 1.1 has one known issue that was found a few hours before the final release was built. As the fix may potentially affect the stability of the library, i have decided to postpone it to the next release. The issue is with running looping timelines on Swing components. If a window hosting such a component is disposed, Trident will continue running the timeline. If the timeline results in updating visual properties of this component (directly or indirectly), the main AWT thread will never shut down – as described in the AWT threading documentation – and the VM will never quit. There are two workaround for this issue in version 1.1:

  • Use EXIT_ON_CLOSE mode instead of DISPOSE_ON_CLOSE
  • Override the Component.removeNotify of the relevant component and cancel / abort the timeline

I am excited today to announce the availability of the release candidate for version 1.1 of Trident animation library (code-named Bogeyman). Most of the new functionality in this version was driven by the user feedback, and includes the following:

In addition to the bundled simple applications, Trident has two blueprint projects. These projects show how to use Trident to drive complex animation scenarios in Internet-enabled rich applications that show graphic information on music albums. Project Onyx is the Swing implementation (see detailed walkthroughs), and Project Granite is the SWT implementation (see detailed walkthroughs).

New Onyx screens

If you have Java 7 installed on your machine, click the button below to launch the WebStart version of Project Onyx:

You are more than welcome to take Trident 1.1RC for a ride and report any problems in the project mailing lists, forums or issue tracker. The final release is scheduled for October 12. Only bugs will be fixed until that date.

Trident animation library for Java applications is nearing release 1.1 (code-named Bogeyman), and it’s time to take a look at the new APIs added in this version. This entry is going to talk about supporting Java UI toolkits.

UI toolkit handlers

Graphical applications are a natural fit for animations, and Trident core has built-in support for Swing and SWT. This support covers threading rules, custom property interpolators and repaint timelines. Application code that needs to support additional Java-based UI toolkits should register a custom UI toolkit handler.

Most modern UI toolkits have threading rules that the applications must respect in order to prevent application freeze and visual artifacts. The threading rules for both Swing and SWT specify that the UI-related operations must be done on a special UI thread, and the methods in the org.pushingpixels.trident.UIToolkitHandler are used to determine the relevance of these threading rules. The UIToolkitHandler interface is illustrated by the core support for SWT:

public class SWTToolkitHandler implements UIToolkitHandler {
	@Override
	public boolean isHandlerFor(Object mainTimelineObject) {
		return (mainTimelineObject instanceof Widget);
	}

	@Override
	public boolean isInReadyState(Object mainTimelineObject) {
		return !((Widget) mainTimelineObject).isDisposed();
	}

	@Override
	public void runOnUIThread(Runnable runnable) {
		Display.getDefault().asyncExec(runnable);
	}
}

This is a very simple implementation of a UI toolkit handler that respects the relevant threading rules:

  • The isHandlerFor associates this handler with all SWT widgets
  • The isInReadyState marks disposed widgets to skip the property interpolation / callback invocations
  • The runOnUIThread runs the UI related logic on the SWT thread

Registering custom UI toolkit handlers

Trident provides two ways to register custom UI toolkit handlers – customization APIs and plugins.

The TridentConfig class has the following APIs to work with UI toolkit handlers:

  • addUIToolkitHandler(UIToolkitHandler) – registers the UI toolkit handler
  • removeUIToolkitHandler(UIToolkitHandler) – unregisters the UI toolkit handler
  • getUIToolkitHandlers() – retrieves an unmodifiable collection of all registered (core and custom) UI toolkit handlers

The UIToolkitHandler entries in the plugin descriptor files allow application code to support additional Java-based UI toolkits. The value associated with this key must be the fully qualified class name of an application class that implements the org.pushingpixels.trident.UIToolkitHandler interface.

Respecting the threading rules

The UIToolkitHandler.isHandlerFor(Object) is used to determine whether the main timeline object is a component / widget for the specific UI toolkit. At runtime, all fields registered with the Timeline.addPropertyToInterpolate methods will be changed on the UI thread using the UIToolkitHandler.runOnUIThread method.

In the simple Swing example that interpolates the foreground color of a button on mouse rollover, the timeline is configured as

Timeline rolloverTimeline = new Timeline(button);
rolloverTimeline.addPropertyToInterpolate("foreground", Color.blue,
	Color.red);

If you put a breakpoint in the JComponent.setForeground(Color) – which is called on every timeline pulse – you will see that it is called on the Swing Event Dispatch Thread. Internally, this is what happens:

  • When the timeline is created, all registered UI toolkit handlers are asked whether they are handlers for the specified object
  • The org.pushingpixels.trident.swing.SwingToolkitHandler registered in the core library returns true for the button object in its isHandlerFor(Object)
  • On every timeline pulse, a Runnable object is created internally. The run() method calls the setters for all registered fields – using the PropertyInterpolator.interpolate method of the matching property interpolator
  • This Runnable is passed to the UIToolkitHandler.runOnUIThread method of the matching UI toolkit handler.

And this is how SwingToolkitHandler.runOnUIThread() is implemented:

@Override
public void runOnUIThread(Runnable runnable) {
	if (SwingUtilities.isEventDispatchThread())
		runnable.run();
	else
		SwingUtilities.invokeLater(runnable);
}

Running custom application code on UI thread

The flow described above works for the fields registered with the Timeline.addPropertyToInterpolate methods. What about the custom application callbacks registered with the Timeline.addCallback()? If the callback methods need to respect the UI threading rules of the matching toolkit, the TimelineCallback implementation class needs to be tagged with the org.pushingpixels.trident.callback.RunOnUIThread annotation.

Callback implementations marked with this annotation will have both onTimelineStateChanged and onTimelinePulse invoked on the UI thread, making it safe to query and change the UI. The UIThreadTimelineCallbackAdapter is a core adapter class that is marked with this annotation.

Querying the readiness of the timeline object

The isInReadyState(Object) is the third and final method in the UIToolkitHandler interface. After the specific UI toolkit handler has declared that it will handle the main object of the specific timeline (by returning true from the isHandlerFor(Object) method), it will be used to interpolate the registered fields and run the registered callbacks. However, some UI toolkits may impose additional restrictions on when the UI object is ready to be queried / changed.

For example, once an SWT control is disposed, it will throw an SWTException in the setForeground method. So, if the application code is running a slow animation that changes the foreground color of a button, and the application window containing this button is disposed in the meantime, the call to setForeground should be skipped.