This has been on my to-do list for quite a long time, and over the last couple of months i have finally started to add unit tests to the Flamingo component suite. Before long, i have found myself stuck deep in a quagmire of nested runnables, complex interactions with the Event Dispatch Thread (EDT) and code that is hard to read, extend and maintain. And even then the tests behaved unpredictably, with some failing randomly – indicating incorrect interactions with the EDT.

At that moment i have realized that the true potential of open source is collaboration and reuse of existing libraries – unless you’re feeling that you can do better, of course :) The final tipping point came in July when Alex has published a blog entry on how FEST Swing library can facilitate writing clean and maintainable interactions with UI components – and this was it. Since then i have been adding FEST-driven unit tests to test different aspects of Flamingo components, including model manipulation, layout, and interaction with mouse and keyboard. Here, i’m going to show a small subset of these tests – illustrating the relevant parts of FEST Swing.

Before starting to delve into the project documentation, start with the blog entry on writing EDT-safe UI tests. It’s short, it’s clean and it’s quite illuminating. Then, head over to the main project page, read a little bit about the library and download the latest distribution (i’m using the latest 1.2a3 version). Once you’re done, add the following jars to your classpath:

  • fest-assert-1.1.jar
  • fest-reflect-1.1.jar
  • fest-swing-1.2a3.jar
  • fest-swing-junit-1.2a3.jar
  • fest-util-1.1.jar
  • junit-4.3.1.jar

Now let’s take a look at how a unit test class looks like. It starts by extending the base FEST class:

public class ActionCommandButtonTestCase extends FestSwingJUnitTestCase {

The biggest advantage of using this base class is that it automatically installs a custom repaint manager that tracks EDT violations – keeping both your unit tests and your main code clean from them. Next, it’s time to create the main window and a command button for the testing:

   JFrame buttonFrame;
   int count;
   JCommandButton button;

   @Override
   @Before
   public void onSetUp() {
      URL resource = ActionCommandButtonTestCase.class.getClassLoader()
            .getResource("utest/common/edit-paste.svg");
      Assertions.assertThat(resource).isNotNull();
      final ResizableIcon icon = SvgBatikResizableIcon.getSvgIcon(resource,
            new Dimension(32, 32));
      Pause.pause(new Condition("Waiting to load the SVG icon") {
         @Override
         public boolean test() {
            return !((AsynchronousLoading) icon).isLoading();
         }
      });

      GuiActionRunner.execute(new GuiTask() {
         @Override
         protected void executeInEDT() throws Throwable {
            buttonFrame = new JFrame();
            buttonFrame.setLayout(new FlowLayout());

            button = new JCommandButton("test", icon);
            button.setDisplayState(CommandButtonDisplayState.BIG);
            buttonFrame.add(button);
            buttonFrame.setSize(300, 200);
            buttonFrame.setLocationRelativeTo(null);
            buttonFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            buttonFrame.setVisible(true);

            count = 0;
            button.addActionListener(new ActionListener() {
               @Override
               public void actionPerformed(ActionEvent e) {
                  count++;
               }
            });
         }
      });

      GuiActionRunner.execute(new GuiTask() {
         @Override
         protected void executeInEDT() throws Throwable {
            Point locOnScreen = buttonFrame.getLocationOnScreen();
            locOnScreen.move(10, 20);
            robot().moveMouse(locOnScreen);
         }
      });
   }

While the documentation describes two ways of locating components for testing – fixtures and finders – i found it simpler to just store references to the relevant components, especially for test windows that have a very small number of controls.

The onSetUp method has the following main stages:

  • Create an SVG-based icon and wait for it to load. Here, Pause.pause is used to wait for the specific Condition – the name of the test() method is quite unfortunate, and IMO should be renamed to better reflect its purpose.
  • Then, GuiActionRunner.execute(GuiTask) is called to create the main window and the command button. This is by far my favorite method in FEST Swing – it runs the specified code on EDT and waits for it to finish. And while closures could have made the code even more readable, even in its present form it has enormous potential to simplify UI-related tests.
  • Finally, the same method is used to move the mouse away from the button – for subsequent tests of mouse interaction.

Once we have the setup method in place, time for the a very simple unit test:

   @Test
   public void sanityCheck() {
      String buttonText = GuiActionRunner.execute(new GuiQuery<String>() {
         @Override
         protected String executeInEDT() throws Throwable {
            return button.getText();
         }
      });
      Assertions.assertThat(buttonText).isEqualTo("test");
   }

Here, my second best-favorite feature – GuiActionRunner.execute(GuiQuery) – is used. It provides an EDT-safe way to query the current state of the specific UI component.

At this point it is important to note that UI testing can only be done to a certain degree. While the test above checks that the getText() returns the right value, it does not check that the visual representation of the button on the screen actually display this text (or any text for that matter). Testing the correctness of the painting routines is not simple. Even a straightforward approach of using an offline collection of “expected” screenshots will not work under look-and-feels that use the font settings of the current desktop – which varies not only across operating systems, but also across different DPI settings. As such, at the present moment my tests are focusing on checking the model, layouts and mouse / keyboard interactions.

Here are three tests to check that the associated action listener is invoked when the command button is activated with mouse, keyboard or API:

   @Test
   public void activateButtonWithMouse() {
      robot().click(button);
      robot().waitForIdle();
      Assertions.assertThat(count).isEqualTo(1);
   }

   @Test
   public void activateButtonWithSpace() {
      robot().moveMouse(button);
      robot().pressAndReleaseKeys(KeyEvent.VK_SPACE);
      robot().waitForIdle();
      Assertions.assertThat(count).isEqualTo(1);
   }

   @Test
   public void activateButtonWithAPI() {
      GuiActionRunner.execute(new GuiTask() {
         @Override
         protected void executeInEDT() throws Throwable {
            button.doActionClick();
         }
      });
      robot().waitForIdle();
      Assertions.assertThat(count).isEqualTo(1);
   }

Here i’m using different APIs of the Robot class to simulate the user interaction with keyboard and mouse, as well as EDT-safe invocation of the AbstractCommandButton.doActionClick() API.

Having these building blocks in place allows you to create more complex scenarios, testing various flows through your model classes. Here is a test case that checks that pressing the mouse, moving it away from the button and then releasing it does not activate the registered action listener:

   @Test
   public void pressButtonAndMoveAwayBeforeRelease() {
      robot().pressMouse(button, AWT.centerOf(button));
      robot().waitForIdle();

      robot().moveMouse(button, new Point(-10, 10));
      robot().waitForIdle();

      robot().releaseMouseButtons();
      robot().waitForIdle();

      // no action listener should have been invoked
      Assertions.assertThat(count).isEqualTo(0);
   }

Finally, a more complex scenario tests the API that activates the registered action listener on mouse press – as opposed to mouse release:

   @Test
   public void fireActionOnPress() {
      GuiActionRunner.execute(new GuiTask() {
         @Override
         protected void executeInEDT() throws Throwable {
            button.getActionModel().setFireActionOnPress(false);
         }
      });

      Assertions.assertThat(GuiActionRunner.execute(new GuiQuery() {
         @Override
         protected Boolean executeInEDT() throws Throwable {
            return button.getActionModel().isFireActionOnPress();
         }
      })).isFalse();

      // press mouse over the button
      robot().pressMouse(button, AWT.centerOf(button));
      robot().waitForIdle();
      // no action listener should have been invoked
      Assertions.assertThat(count).isEqualTo(0);

      // release mouse
      robot().releaseMouseButtons();
      robot().waitForIdle();
      // action listener should have been invoked
      Assertions.assertThat(count).isEqualTo(1);

      // mark the button to fire the action listeners on mouse press
      GuiActionRunner.execute(new GuiTask() {
         @Override
         protected void executeInEDT() throws Throwable {
            button.getActionModel().setFireActionOnPress(true);
         }
      });

      Assertions.assertThat(GuiActionRunner.execute(new GuiQuery() {
         @Override
         protected Boolean executeInEDT() throws Throwable {
            return button.getActionModel().isFireActionOnPress();
         }
      })).isTrue();

      // press mouse over the button
      robot().pressMouse(button, AWT.centerOf(button));
      robot().waitForIdle();
      // action listener should have been invoked
      Assertions.assertThat(count).isEqualTo(2);

      // release mouse
      robot().releaseMouseButtons();
      robot().waitForIdle();
      // no action listener should have been invoked
      Assertions.assertThat(count).isEqualTo(2);
   }

This entry showed a very small subset of what FEST Swing can do. I am still exploring this library as i continue adding more test cases to cover the command buttons – towards unit tests that will cover the ribbon component.

I am extremely pleased today to announce the availability of release candidate for version 5.3 of Substance look-and-feel (code-named Reykjavik). The release notes for version 5.3 contain the detailed information on the contents of this release which include the following:

Click on the button below to launch a signed WebStart application that shows the available Substance features.

The following sub-projects are also available as release candidates:

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

Sample screenshots of Substance 5.3 in action:




Jitterbug is a visual editor for creating and editing color schemes in Substance look-and-feel introduced in release 5.1 of the library. It primarily addresses the scenarios where you need to translate design mockups or emulate existing UI visuals as a Substance skin. The original version of Jitterbug had two major constraints – it operated on a single color scheme, and did not address the full flows of creating, editing and saving color schemes.

Jitterbug had a major revision in the upcoming release 5.3. Targeting the creation of both Magellan and Gemini skins, it has been redesigned to provide the seamless flows of creating, as well as editing the color scheme definition files that can be used to create complex Substance skins. You no longer need to switch between Jitterbug and another text editor to save color schemes. You no longer need to work on multiple color scheme files, each defining a single color scheme.

The following screenshot shows the new Jitterbug in action (click to see full size view):

To see the Jitterbug in action, run the following signed WebStart demo:

The new version of Jitterbug aims to address deficiencies in the flows of creating and tweaking color schemes. I did try to make the flows straightforward and intuitive, as well as making Jitterbug the only tool you will need to create collections of Substance color schemes. However, i cannot be an objective judge of my own creation. As such, i am not detailing any instructions on how to use Jitterbug. If you find yourself stuck in the middle of the process, or the flows do not simply make sense, let me know in the comments.

Overlay painters in Substance

September 10th, 2009

The decoration painters are used to paint the entire background area of the relevant containers – such as menu bars, tool bars, panels etc. Overlay painters, on the other hand, add the final polish that usually affects relatively small areas at the edges of the relevant decoration areas. Substance also provides a set of published APIs for applications that wish to add visually consistent overlays to custom application containers.

The overlays are best illustrated with screenshots. The following screenshot is a skeleton window under the Nebula Brick Wall skin:

This skin defines custom visual appearance for the title pane, the menu bar and the status bar – the background of these areas is painted by the matching decoration painter – in this case, the <span style="color: darkblue;">org.jvnet.substance.painter.decoration.MarbleNoiseDecorationPainter</span>. To add the final polishing touch and create a unique visual footprint for this skin, we use a number of overlay painters:

The Nebula Brick Wall skin defines two separate overlay painters, each one associated with the relevant decoration areas:

    // add an overlay painter to paint a drop shadow along the top
    // edge of toolbars
    this.addOverlayPainter(TopShadowOverlayPainter.getInstance(),
        DecorationAreaType.TOOLBAR);

    // add an overlay painter to paint separator lines along the bottom
    // edges of title panes and menu bars
    this.bottomLineOverlayPainter = new BottomLineOverlayPainter(
        new ColorSchemeSingleColorQuery() {
          @Override
          public Color query(SubstanceColorScheme scheme) {
            Color dark = scheme.getDarkColor();
            return new Color(dark.getRed(), dark.getGreen(), dark
                .getBlue(), 160);
          }
        });
    this.addOverlayPainter(this.bottomLineOverlayPainter,
        DecorationAreaType.PRIMARY_TITLE_PANE,
        DecorationAreaType.SECONDARY_TITLE_PANE,
        DecorationAreaType.HEADER);
  • The instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.TopShadowOverlayPainter</span> is associated with the toolbar decoration area – adding the drop shadow along the top edge of all application toolbars (see the bottom half of the zoomed area in the screenshot above).
  • An instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.BottomLineOverlayPainter</span> is associated with titlepane and header decoration areas – adding a thin separator line along the bottom edge of the title pane and the menubar (see the top half of the zoomed area in the screenshot above). Note that the application needs to specify what color is used to paint the separator line – using the <span style="color: darkblue;">org.jvnet.substance.api.ColorSchemeSingleColorQuery</span> – more on this interface later.

Here is the same skeleton window under the Gemini skin:

This skin defines custom visual appearance for the title pane, the menu bar, the toolbars and the status bar – the background of these areas is painted by the matching decoration painter – in this case, the <span style="color: darkblue;">org.jvnet.substance.painter.decoration.MatteDecorationPainter</span>. To add the final polishing touch and create a unique visual footprint for this skin, we use a number of overlay painters:

The Gemini skin defines three separate overlay painters, each one associated with the relevant decoration areas:

    // add an overlay painter to paint a bezel line along the top
    // edge of footer
    this.footerTopBezelOverlayPainter = new TopBezelOverlayPainter(
        ColorSchemeSingleColorQuery.DARK,
        ColorSchemeSingleColorQuery.ULTRALIGHT);
    this.addOverlayPainter(this.footerTopBezelOverlayPainter,
        DecorationAreaType.FOOTER);

    // add two overlay painters to create a bezel line between
    // menu bar and toolbars
    this.menuOverlayPainter = new BottomLineOverlayPainter(
        new ColorSchemeSingleColorQuery() {
          @Override
          public Color query(SubstanceColorScheme scheme) {
            return scheme.getUltraDarkColor().darker();
          }
        });
    this.toolbarOverlayPainter = new TopLineOverlayPainter(
        new ColorSchemeSingleColorQuery() {
          @Override
          public Color query(SubstanceColorScheme scheme) {
            Color fg = scheme.getForegroundColor();
            return new Color(fg.getRed(), fg.getGreen(), fg
                .getBlue(), 32);
          }
        });
    this.addOverlayPainter(this.menuOverlayPainter,
        DecorationAreaType.HEADER);
    this.addOverlayPainter(this.toolbarOverlayPainter,
        DecorationAreaType.TOOLBAR);

This skin shows two different ways to add double-line bezel separators – the first between the menu bar and tool bar, and the second between the main application area and the footer:

  • The double separator along the top edge of the footer (status bar) is painted by an instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.TopBezelOverlayPainter</span> which is associated with the footer decoration area – see the bottom zoomed area in the screenshot above.
  • The double separator between the menu bar and the tool bar is painted by two different overlay painters – see the top zoomed area in the screenshot above:
    • An instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.BottomLineOverlayPainter</span> associated with header decoration area – paints the top (darker) separator line along the bottom edge of the menu bar.
    • An instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.TopLineOverlayPainter</span> associated with toolbar decoration area – paints the bottom (lighter) separator line along the top edge of the tool bar.

The last example comes from the Twilight skin:

This skin defines custom visual appearance for the title pane, the menu bar, the toolbars and the status bar – the background of these areas is painted by the matching decoration painter – in this case, the <span style="color: darkblue;">org.jvnet.substance.painter.decoration.MatteDecorationPainter</span>. To add the final polishing touch and create a unique visual footprint for this skin, we use a number of overlay painters:

The Gemini skin defines four separate overlay painters, each one associated with the relevant decoration areas:

    // Add overlay painters to paint drop shadows along the bottom
    // edges of toolbars and footers
    this.addOverlayPainter(BottomShadowOverlayPainter.getInstance(),
        DecorationAreaType.TOOLBAR);
    this.addOverlayPainter(BottomShadowOverlayPainter.getInstance(),
        DecorationAreaType.FOOTER);

    // add an overlay painter to paint a dark line along the bottom
    // edge of toolbars
    this.toolbarBottomLineOverlayPainter = new BottomLineOverlayPainter(
        new ColorSchemeSingleColorQuery() {
          @Override
          public Color query(SubstanceColorScheme scheme) {
            return scheme.getUltraDarkColor().darker();
          }
        });
    this.addOverlayPainter(this.toolbarBottomLineOverlayPainter,
        DecorationAreaType.TOOLBAR);

    // add an overlay painter to paint a dark line along the bottom
    // edge of toolbars
    this.toolbarTopLineOverlayPainter = new TopLineOverlayPainter(
        new ColorSchemeSingleColorQuery() {
          @Override
          public Color query(SubstanceColorScheme scheme) {
            Color fg = scheme.getForegroundColor();
            return new Color(fg.getRed(), fg.getGreen(), fg
                .getBlue(), 32);
          }
        });
    this.addOverlayPainter(this.toolbarTopLineOverlayPainter,
        DecorationAreaType.TOOLBAR);

    // add an overlay painter to paint a bezel line along the top
    // edge of footer
    this.footerTopBezelOverlayPainter = new TopBezelOverlayPainter(
        new ColorSchemeSingleColorQuery() {
          @Override
          public Color query(SubstanceColorScheme scheme) {
            return scheme.getUltraDarkColor().darker();
          }
        }, new ColorSchemeSingleColorQuery() {
          @Override
          public Color query(SubstanceColorScheme scheme) {
            Color fg = scheme.getForegroundColor();
            return new Color(fg.getRed(), fg.getGreen(), fg
                .getBlue(), 32);
          }
        });
    this.addOverlayPainter(this.footerTopBezelOverlayPainter,
        DecorationAreaType.FOOTER);

The overlay painters used in the Twilight skin are:

  • An instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.TopLineOverlayPainter</span> associated with toolbar decoration area – paints the lighter top separator line along the top edge of the tool bar – see the top zoomed area in the screenshot above.
  • An instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.BottomLineOverlayPainter</span> associated with toolbar decoration area – paints the darker bottom separator line along the bottom edge of the tool bar – see the top zoomed area in the screenshot above.
  • An instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.TopBezelOverlayPainter</span> associated with footer decoration area – paints the double bezel separator lines along the top edge of the status bar – see the bottom zoomed area in the screenshot above.
  • The instance of <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.BottomShadowOverlayPainter</span> associated with toolbar and footer decoration areas – paints the drop shadow along the bottom edge of these areas – see the top zoomed area in the screenshot above.

Application-facing APIs

To use the matching overlay painters in custom painting routines of your application, call the following published Substance APIs:

  • <span style="color: darkblue;">SubstanceLookAndFeel.<a href="https://substance.dev.java.net/docs/api/GetCurrentSkin.html">getCurrentSkin()</a></span> to retrieve the component skin.
  • <span style="color: darkblue;">SubstanceLookAndFeel.<a href="https://substance.dev.java.net/docs/api/GetDecorationType.html">getDecorationType()</a></span> to retrieve the decoration area type of the component.
  • <span style="color: darkblue;">SubstanceSkin.getOverlayPainters()</span> to retrieve the overlay painters registered for the specific decoration area type.
  • Loop over the overlay painters and use the <span style="color: darkblue;">SubstanceOverlayPainter.paintOverlay()</span> (see below) to paint the overlays on the specific graphics context.

The base class for Substance overlay painters is <span style="color: darkblue;">org.jvnet.substance.api.painter.overlay.SubstanceOverlayPainter</span>. The only painting method in this class is:

/**
   * Paints the overlay.
   *
   * @param graphics
   *            Graphics context.
   * @param comp
   *            Component.
   * @param decorationAreaType
   *            Decoration area type. Must not be null.
   * @param width
   *            Width.
   * @param height
   *            Height.
   * @param skin
   *            Skin for painting the overlay.
   */
  public void paintOverlay(Graphics2D graphics, Component comp,
      DecorationAreaType decorationAreaType, int width, int height,
      SubstanceSkin skin);

The <span style="color: darkblue;">width</span> and <span style="color: darkblue;">height</span> parameters specify the rectangle for the overlays (the overlay painters can only paint on rectangular areas), the <span style="color: darkblue;">skin</span> specifies the Substance skin to be used to compute the gradient colors, while <span style="color: darkblue;">decorationAreaType</span> indicates the decoration area type.

The overlay painters will be officially available in the next few days as part of the 5.3 release candidate.