So what now, Stig?

Reading about the BBC’s failed attempts in the High Court to stop publisher HarperCollins outing Top Gear’s Stig as ex-racing driver Ben Collins in his new autobiography, there has been lots of talk of the BBC’s anger at the publisher, but I’ve not read anything about their relationship with Ben Collins himself.

It’s been mentioned that there were obvious confidentiality agreements in place which have now been breached, but I don’t quite understand why the focus of the anger seems to have been towards HarperCollins and not Ben Collins – it’s him that has broken the agreement, not the publisher. Or am I missing something? Maybe it’s just the way it has been reported, or the way I’ve interpreted it.

So where does that leave The Stig? I’m assuming Collins will lose the gig (man, what a job!). Will The Stig be killed off again as happened with the original driver in the role, Perry McCarthy?

Maybe I should get myself a firesuit and Simpson helmet with black visor and send my CV in… 😉

Substance custom table cell renderers

I use the Substance Look & Feel in most of my Java Swing GUIs these days. It’s a very well engineered, mature, configurable implementation of a Swing look & feel which can transform the appearance of any Swing GUI. The author Kirill Grouchnikov has done a great job with it over the years and I’d like to thank him for his work on this project (and his other projects such as the Trident animation library and Flamingo component suite).

Although Substance is extremely configurable, one area that I’ve had problems with in the past is that of custom table cell renderers. Substance provides default renderers for common cell value classes such as strings, numbers, booleans etc. which covers most use cases. However, if you want to customise the cell renderer behaviour and still benefit from all of the Substance effects such as row striping, selection highlighting animation etc. you’re quite limited because Substance enforces that your custom renderer is sub-classed from the SubstanceDefaultTableCellRenderer, which itself sub-classes DefaultTableCellRenderer. This is fine as long as your custom renderer is happy to be, effectively, a sub-class of JLabel, but for anything involving custom painting it’s no good.

This is one area that I think Substance could possibly be improved to make it a bit more extensible and flexible.

One specific situation I encountered this problem with recently was where I wanted to display a mini bar-chart in a table cell. The actual custom bar component was a trivial amount of custom painting but I couldn’t see an easy way of getting this into a Substance table cell renderer. I tried creating a simple cell renderer which extended the bar component and implemented the obligatory TableCellRenderer interface, and although this worked to a degree, I lost all of the nice Substance effects mentioned above by virtue of the fact that the renderer wasn’t derived from SubstanceDefaultTableCellRenderer. I managed to get row background striping back quite easily by calling the SubstanceStripingUtils.applyStripedBackground() method but that wasn’t good enough.

Then I had a mini flash of inspiration triggered when I noticed that Substance provided a default renderer for icons…

Because the Substance default renderer is based on a label, I could set the icon property to an implementation of the javax.swing.Icon interface to get my custom painting “injected” into the renderer. The steps involved were:

  1. Make my custom bar component implement the Icon interface. This was simply a case of moving my custom painting code from the paintComponent method to paintIcon and also providing implementations of the getIconWidth and getIconHeight methods.
  2. Create a simple SubstanceDefaultTableCellRenderer sub-class which wraps an instance of my bar component. In the renderer constuctor I call setIcon to attach the bar component to the renderer. The renderer also needs to override the two setBounds methods so that it can set the size of the wrapped bar component, otherwise it wouldn’t resize with the table cell! Oh, and of course an overridden setValue method needs to update the wrapped bar component value as appropriate.

As a result, my two classes looked something like this:

BarIconComponent

package com.purplegem.substanceplay;

import javax.swing.*;
import java.awt.*;

/**
 * Simple custom component which renders a mini bar chart.
 * Implements the Icon interface so it can be used where an Icon can.
 */
public class BarIconComponent extends JComponent implements Icon {

  private double value = 0.5d;

  public BarIconComponent() {
    setSize(40, 20);
  }

  public double getValue() {
    return value;
  }

  public void setValue(double value) {
    this.value = value;
  }

  @Override
  public void paintIcon(Component c, Graphics g, int x, int y) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setColor(Color.GREEN);
    g2.fillRect(0, 0, (int) (getIconWidth() * value), getIconHeight());
  }

  @Override
  public int getIconWidth() {
    return getWidth();
  }

  @Override
  public int getIconHeight() {
    return getHeight();
  }

  @Override
  protected void paintComponent(Graphics g) {
    paintIcon(this, g, 0, 0);
  }

}

BarCellRenderer

package com.purplegem.substanceplay;

import org.pushingpixels.substance.api.renderers.SubstanceDefaultTableCellRenderer;

import java.awt.*;

/**
 * Custom Substance table cell renderer which renders a mini bar
 * chart using the wrapped BarIconComponent instance
 */
public class BarCellRenderer extends SubstanceDefaultTableCellRenderer {

  private BarIconComponent barComponent = new BarIconComponent();

  public BarCellRenderer() {
    // attach our bar component as an icon
    setIcon(barComponent);
  }

  @Override
  public void setBounds(int x, int y, int width, int height) {
    super.setBounds(x, y, width, height);
    // ensure we update the size of the wrapped bar component
    barComponent.setSize(width, height);
  }

  @Override
  public void setBounds(Rectangle r) {
    super.setBounds(r);
    // ensure we update the size of the wrapped bar component
    barComponent.setSize((int) r.getWidth(), (int) r.getHeight());
  }

  @Override
  protected void setValue(Object value) {
    if (value != null) {
      // update the value of the bar component for this particular table cell
      barComponent.setValue((Double) value);
    }
  }

}

Once I’d implemented all of this I then had exactly the result I was expecting – a mini bar chart in a table cell with all the expected Substance table cell effects 🙂

Uploading files using scp and the Maven Wagon plugin

I’ve been struggling with a little Maven problem for a while but only just managed to find time to look into it in any detail. What I’ve been trying to do is copy an artifact to a remote server using scp. The artifact in question is a WAR which I want to copy to a server hosting Tomcat, so this is not a typical deploy-artifact-to-repository type of requirement.

(As an aside, I know all about the Cargo plugin for deploying web apps to servlet containers but in this instance I’m more interested in the more general issue of copying any artifact, be it a WAR or a JAR or something else, using scp)

In principle this sounds like a very simple thing to do. The Maven Wagon plugin is the tool for the job but the documentation is woefully inadequate and I just could not get it to do what I wanted.

Anyway, after a lot of Googling and, crucially, inspecting Maven debug output from failed attempts at using the plugin I’ve finally cracked it.

Everything I’d seen written about this involved the following aspects…

Configuring details about the server to be copied to (typically in your main Maven settings.xml configuration):

<server>
  <serverId>my-server-id</serverId>
  <user>my-user-name</user>
  <password>my-password</password>
</server>

Using the Wagon plugin to perform the actual copy:

<build>
  <extensions>
    <extension>
       <groupId>org.apache.maven.wagon</groupId>
       <artifactId>wagon-ssh</artifactId>
       <version>1.0-beta-6</version>
     </extension>
   </extensions>

   <plugins>
     <plugin>
       <groupId>org.codehaus.mojo</groupId>
       <artifactId>wagon-maven-plugin</artifactId>
       <version>1.0-beta-3</version>
       <configuration>
         <fromFile>${project.build.directory}/${project.build.finalName}.war</fromFile>
         <url>scp://my-server-id.fully.qualified.domain/path/to/destination</url>
       </configuration>
       <executions>
         <execution>
           <id>upload-war-to-server</id>
           <phase>deploy</phase>
           <goals>
             <goal>upload-single</goal>
           </goals>
         </execution>
       </executions>
     </plugin>
   </plugins>

 </build>

All looks logical… but it simply refused to work, complaining about authentication failures. I knew the corresponding <server> configuration block was using the correct username and password, so the symptoms suggested that it wasn’t finding the <server> configuration. I’d made sure the host part of the server domain in the scp:// URL matched the server id element but it just wouldn’t match them up.

And then I noticed something in the Wagon plugin’s debug output – mention of a serverId property in the configuration. I’d not seen this documented anywhere before, but I thought I’d try adding it to my Wagon plugin configuration all the same…

      <configuration>
        <serverId>my-server-id</serverId></pre>
        <fromFile>${project.build.directory}/${project.build.finalName}.war</fromFile>
        <url>scp://my-server-id.fully.qualified.domain/path/to/destination</url>
      </configuration>

…and all of a sudden it started working! So, in my situation that appears to have been the missing link between my Wagon plugin and the server configuration details.

It’s nice to tell the user what’s happening sometimes…

As much as I like Android and my HTC Desire, there are still a few niggles that need ironing out. One case in point is a problem I’ve had for the last week or so and only just got round to investigating and finding a solution for.

For some reason, Android Marketplace on my Desire stopped working for me. I could browse, search and choose to download apps, but they just wouldn’t get beyond the “Starting download…” step. I tried cancelling the downloads and restarting, with no success. I also tried switching between WiFi and 3G, toggling the radios on and off, restarting the phone – several times. No success.

A similar problem happened to me a couple of months ago when I switched my Google account from “googlemail.com” to “gmail.com”once it had become available again in the UK. I did a lot of investigation into this problem at the time and found that a lot of people were being affected. If I switched back to googlemail.com everything worked fine again. I tried removing the old googlemail.com Google account from my phone so that I could replace it with a gmail.com account instead, but it wouldn’t have it. In the end I backed up my apps and data to SD card, reset the phone to factory settings and started afresh with a gmail.com Google account. Once I’d restored my apps and data I was back in business – everything worked just fine.

At the time I remembered seeing references to the Google Talk service so this time round I tried starting the Talk app – and it just died immediately. No error message or other information. Nothing. Tried again – same thing. So, I used the very handy aLogcat app to view the system logs just in case the were any clues in there. And lo and behold, there was an exception message stating that the Talk app couldn’t be started due to a lack of device storage space!

Now, I’d not really paid much attention to the low space notification that I’d been seeing for the last few weeks, because I knew that I was close to the limit of the measly built-in storage in the Desire. But I didn’t for a minute think that this could be the cause of my Marketplace problems. After deleting some unused apps and trying Talk again, it worked! I went to the Marketplace and that worked too! Bingo.

So, a few things to note from this experience…

  1. Don’t ignore the low space notifications any more – it could affect more than you think!
  2. Count the days until Android 2.2 is rolled out by HTC to the Desire (when I’ll be able to install apps to the SD card)
  3. Wonder why on earth app developers don’t think it’s important to tell users what’s happening when something they don’t expect happens

On this last point, why does the Talk app not show an error dialog informing the user why it can’t start? And likewise, why does the Android Marketplace app not tell me why it can’t download items. From a UI design perspective this is inexcusable. App developers – take note!

My latest web development – Early Birds Nursery

Every now and again I create the occasional web site for family, friends, local organisations or businesses. I enjoy doing them (quite often for free!) as it’s another opportunity to flex my creative and technical muscles at the same time and also to help out people or organisations who don’t necessarily want to (or simply can’t) spend a fortune on web development.

I’m just finishing off a simple web site for a local pre-school nursery, called Early Birds Nursery (http://www.early-birds-nursery.co.uk).

For this site I’ve tried to come up with a colourful, fun and almost child-like visual style using bold, primary colours and cartoon style graphics.  I don’t know what you think, but I’m pretty pleased with the result.

Go HTC/Android, go!

I’ve just read this article on the BBC News web site stating that sales of HTC smartphones powered by Android (like the HTC Desire I own) have massively exceeded analysts expectations. An amazing 41% growth for the first six months of 2010.

I still think Android is going to be huge, much bigger than iOS which powers the iPhone and iPad.

Note to self… must keep going at those Android app projects I keep starting!

Alternative text input methods on Android – Swype and ShapeWriter

I recently heard about the ShapeWriter (http://www.shapewriter.com/) alternate text input method for Android devices and read some glowing reviews of it so thought I’d give it a try.

If you haven’t already seen or heard about ShapeWriter, it’s an alternate virtual keyboard for mobile devices which lets you type words by dragging your finger from one key to another rather than pressing each individual key. Each time you release your finger, that marks the end of the word and a space is inserted. You can still press each individual key if you want, so you don’t lose any functionality, but you obviously don’t benefit from the big speed increases you can get from using the new finger dragging method.

In use I found that it’s definitely quicker (for me at least) than pressing each individual key and my word input rate has gone up.

Since installing ShapeWriter I also heard about another very similar alternate keyboard called Swype which is currently in beta phase (http://beta.swype.com). I’ve installed both of them so will compare the two over the next few weeks.

Beware when filtering TrueType font resources in Maven

I’ve just come up against an interesting problem while loading custom TrueType fonts bundled with a Java Swing GUI built using Maven.

Initially, for simplicity and because I’d never actually tried creating custom fonts from TTF files before, I loaded the TTF file from an absolute location i.e. not relative to the JAR classpath. Everything worked fine so I proceeded to package the TTF file as a regular resource file packaged into my JAR from the standard Maven src/main/resources directory, and changed the font loading code to load it relative to the JAR classpath. That’s when strange things started to happen…

I noticed that certain glyphs in the font were very subtlely wrong. For example, the top of all “S” glyphs was squashed slightly. I switched my code back to using an absolute file path (referencing the /src/main/resources location) and everything looked fine again. That got me wondering if the font file could be getting corrupted somehow when being packaged into the JAR.

And then it dawned on me… I’m filtering other resources so could that be the problem?

You bet it was!

It turns out that the TTF file was being filtered when packaged into the JAR. As soon as I excluded TTF files from this filtering, everything worked as expected again.

So, the moral of this is watch out for resource filtering when using TrueType font files (or any other file that could potentially be damaged by undesirable filtering).

I’m loving MiG Layout :-)

My Java Swing layout manager of choice to date has been the good old GridBagLayout (with a healthy dose of BorderLayout where applicable). However, there’s a new kid on the block (well, at least on my block)… and that is the MiG Layout (http://www.miglayout.com/)

I heard about MiG Layout ages ago and from what I read about it, it sounded pretty cool. But I’d never actually used it – until now.

I’ve just been doing some GUI work which required some hairy layout management so I thought I’d give MiG Layout a try to see how it fared. And I’m glad to report that it handled it with ease. So I’d definitely recommend you give it a try if you haven’t already.