Gemini skin was introduced in just-released version 5.3 of Substance look-and-feel, and it is the first skin based completely on “offline” inspiration. Gemini was created from scratch in the Jitterbug color scheme editor from this image:

This is my hand holding one of my son’s shoes. I’ve been spending quite a lot of time with him lately, and these shoes are one of his favorites to drag around the house. It took me some time to realize that i really like the colors, and some more time to analyze the color combinations and translate them to the following Gemini visuals:



The black header is coming from soles, the dark blue toolbars are from the side strip, the gray footer is from the strips around the dark blue strip, and the light gray for controls is from the upper left area. And you can see where the bright yellow highlights are coming from.
Accidentally (or maybe not), a few days ago i’ve bought a couple of winter items that use very similar navy/gray/yellow color combination:

After researching the Internet for a while it appears that this color combination is quite popular now:

So there you go – just look at the everyday things, analyze what you like and why you like it, and use that inspiration in your UIs :)
Project Onyx aims to provide blueprints for animated Swing applications powered by the Trident animation library. It displays scrollable cover art for the specific artist, and allows viewing track listing for the selected album. When i first introduced Onyx a few months ago, it fetched the album information from the Amazon backend. Recently Amazon has decided to further tighten the requirements for applications connecting to its backend, and in addition to using application keys, it also requires that all requests are authenticated using signatures.

As this places even more obstacles for people interested in trying Onyx locally (or remotely, for that matter – since i don’t want to publish the keys that i was using), i started looking for an alternative backend provider. My first stop was Yahoo! Music API, but after reading the documentation i found that in addition to requiring an application key it also returns very small cover art. My next stop was Last.fm Web Services. Here, in addition to requiring an application key, the main limitation seems to be a lack of an API to retrieve the track listing for a specific album.
Finally, a helpful thread at StackOverflow pointed me to the MusicBrainz service. After reading the documentation and trying out the examples – without the need for any application key – i have migrated the Onyx codebase to use MusicBrainz. The best part is that since there is no key, Onyx can now be WebStarted by clicking the button below – just make sure that you have Java 7 installed since it uses the new Window APIs for translucent and shaped windows:

The backend connector for MusicBrainz is quite simple, and it uses the JDOM library to parse the XML responses. There are a few notable issues with MusicBrainz that still don’t make it the best choice to fetch album information from the web:
- In general, content is user supplied and not vetted for completeness.
- Multiple entries for the same albums – need to be filtered out based on artist/title or ASIN.
- Track entries for some albums are named [data track].
- Only XML format supported in replies.
- No ability to sort results based on album attributes (such as release date).
- Cover art is not available. Needs to be fetched using “magically” crafted URLs from Amazon.
In the next few days i’m going to move Project Granite – the SWT counterpart of Onyx – to use MusicBrainz as well. In the meantime, browse the updated Onyx code, run the demo above and enjoy the animations powered by Trident. Release 1.1 is just around the corner.
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.