Friday, October 31, 2008

Embedding image in a JLabel

Let's suppose you would like to embed an image inline to a JLabel, JRadioButton or other basic Swing component text (except JEditorPane or JTextPane - that would be cheating ;-))

Let's suppose you have your image on the classpath.

Swing supports HTML out of the box fairly well, so let's try this:
final String msg = "<html>Nice pic: <img src=\"hmmm....\">, is it?";
final JLabel label = new JLabel(msg);

Yeah, the image URL. It needs to point to the image on the classpath and it needs to be understood by Swing.
I considered a custom protocol for a while, but implementing one is cumbersome and an overkill actually.

Long story short:
final URL image = getClass().getResource("/images/image.png");
final String msg = "<html>Nice pic: <img src=\"" + image.toString()
+ "\">, isn't it?";
final JLabel label = new JLabel(msg);

This assumes that getResource() returns a meaningful URL and URL.toString() is reversible. Apparently it is - you get either a file: or jar: URL depending on how you packaged your app.

Tuesday, October 28, 2008

Things That Suck - Part 1

Yes I know, I was supposed to give you the review of Mitsubishi Lancer. Instead, I am starting a new series of posts. But I couldn't help it, I have stuff to share with the world ;). The car reviews will resume shortly, but I would like to give you insights into some stuff that I think is broken in the world, such as:
  • getters and setters (yes my friends, they are an abomination to God, for reasons that I will explain in a subsequent post)
  • class loaders
  • headhunters
But first, let me share with you with the recent suckage, caused by the "fuck the customer" policies of a certain vendor of TV tuners, namely Pinnacle Systems.

I don't have a proper TV-set at home, as me and my wife have decided that TV is mostly crap anyway. The only reason to actually watch it is for my kids to be able to see their daily does of Teletubies, so a computer-based low cost, low qualoty solution would be plenty good enough. So some year and a half ago I happened to buy one of Pinnacle's creations - a USB-based analog TV tuner. I have installed its drivers and a crappy TV-viewing application on my laptop, so my kids would be able to watch TV in the kitchen. Yes, the application was crappy, but it is not the reason I am writing this - bare with me. Of course, I have managed to totally misplace the installation CD and the rest of the packaging immediately. Don't you install the drivers from the internet these days? Aren't they supposed to be free?

Anyway - that was a big mistake.

I have upgraded my home PC from the 5-year old, Intel-issued "home PC" Dell, pitifully underpowered by today's standards. That thing had another TV tuner onboard - from some other vendor (they are excellent, so I will not mention them in an article about things that suck. Email me and I will reveal the brand and model). I am now in the process of transferring all of my digital belongings to the new host. Swapping PCI cards was the last thing on my list, buty meanwhile my wife wanted to watch TV ("Miami Ink" was on and she is in love with Chris Garver :)). So I figured - "why not use the USB TV thingy"? Well, you have to install the TV viewing app for that thing first. But where is it? CD is probably long gone (most likely eaten by my one year old son). Let's grab it from the web then! Ok so I managed to download the thing - all of its 300MB! All belonging to a TV viewing app? Whisky Tango Foxtrot? What could be in there? Well, let's install and start the app to find out. But here comes a nasty surpsrise: in order to install the app, you need a "license key", which is sticked to the CD cover! What? Why? The app would only work on this particular Pinnacle's tuner anyway, I have the tuner, why do you want some stupid key from me? To make sure that I am legit? Why on earth would I want to even bother to download this piece of **** application if I am not a legit owner of the hardware? What's the point here?

You know what Pinnacle? Two things:
  • you are not the only TV tuner vendor in the world. Other ones are much more customer-friendly and much less likely to piss me off. I won't be buying your stuff anymore. Ever. No way.
  • Google knows very well where to find your stupid app's registration keys. Of course, I had to submit myself to the awful looks of astalavista's porn banners (thank godness for Adblock - I wonder how this site looks in IE :)), but the keys are about two clicks away. Why do you even bother with this stupid shit?

Divination from IDEA intestines

When developing IDEA plugins I sometimes feel like I am performing divination rituals, looking for directions by examining IDEA guts ;-)

Apart from forum, koders.com, intellijad and autocomplete feature of IDEA I have written about before, here is yet another BKM for plugin developers: have a look at ExtensionPointName class.

Namely, find all usages of this class in Project and Libraries scope. You may find some really interesting pointers this way.

Like the RunConfigurationExtension that I needed to detect when the program run from IDEA finishes. (for the curious: attach your own ProcessListener to the OSProcessHandler you get in the handleStartProcess)

Thursday, October 23, 2008

Ellipsis (...) in TreeTableView

I use the Idea's TreeTableView to display data in my plugin.
The "tree" part contains the class tree of the current project.

The problem is that when I narrow the tree column the texts just gets truncated without displaying the pretty '...' at the end like it is the case for normal JTable columns.

Most probably this also applies to 'normal' JTree's - I don't have any scrollbar-free JTree at hand to check.

I use a slightly modified DefaultTreeCellRenderer to draw tree nodes, which is practically a JLabel, which in turn should be able to add ellipsis if the component size is too small to contain all the text.

This is the clue - if the renderer has the setSize() set to proper value, it would do the work for you.

A bit of debugging led me to this solution:
Override the paint(Graphics) method of the renderer and manually setSize() of the label just before it is painted.

Where to find the appropriate size? Use the clip bounds that are used to clip the label:
<edit>
Naa, actually clip area is not the right source. This fails when only part of the tree is repainted, for example during scrolling. You would get ellipsis inside of the text.

So, I have changed my renderer to look like this:
private JTree tree;
@Override
public Component getTreeCellRendererComponent(JTree tree, ...) {
// tree size is not known yet for any reason, save for paint()
this.tree = tree;

... // rest of stuff
return this;
}

@Override
public void paint(Graphics g) {
final int maxWidth = tree.getWidth() - getBounds().x;
if (maxWidth < getWidth()) {
setSize(maxWidth, getHeight());
}
super.paint(g);
}

</edit>
Now, the final trick:

Make JLabel draw ellipsis to the left of the text


Like that: '...that'
instead of the default 'Like...'

Solution: reverse the string and give it Right-To-Left direction using unicode marker.
Underlying LabelUI will take care to display it the way you want :-)
(would not work in a RightToLeft environment without modification, but you probably have more serious bugs then ellipsis on the wrong side anyway, right?)

Java snippet:
final String mangledStr = new StringBuilder(str).append('\u202e').reverse().toString();
setText(mangledStr);