Swing and TreeTable component

TreeTable combines functionality of two components - Tree and Table. And it is really comfortable to show some hierarchical information like file system structure or many others.
TreeTable have great Qt implementation, it's fast, useful and pretty. It's a pity there is no standard Swing implementation of this component. But there are lots of third-party implementations. Let’s review them:


JEdit uses TreeTable component for Open-Save dialog. It is extremely fast and pretty. But they did it for their own, with package-private constructor and double-linked to other JEdit components. To use it in other projects means to rewrite it almost from scratch, so JEdit is just a good demo of TreeTable possibilities for Swing.


SwingLabs has their implementation. It is feature-rich and customizable. But it has some rendering bugs, much slower than JEdit version, amount of code is too big to extend it yourself and it linked a lot to other SwingX packages.


As Tim Boudreau told us, NetBeans only recently got a good implementation of TreeTable. And this implementation looks great! It works almost as fast as JEdit one, has no rendering bugs, needs only few classes to build it (but not all the framework as previous two implementations) and it's easy to use and customize. But one more problem - you may use it only under either GPL2 or CDDL, and you need to download NetBeans sources and copy org.netbeans.swing.outline package to your project to use it.

All of them extends JTable. I think it's not good, JTable is the biggest class I have ever seen, about 9000 lines of code, and SwingX implementation adds another 4000 lines. It is hard to debug and hard to customize to internals. Swing is so big because backward compatibility, but what sense of JTable compatibility for totally new component? How do you think, may be it is time to write Tree, Table and TreeTable LGPL implementation by ourselves using best practices from core swing, SwingX, JEdit and NetBeans?


Comparing two collections

There is standard task when you have GUI table and database table, and you need to merge differences.
Most of people I know will do it like this:

Set source; // set of records from UI
Set target; // set of records in database
for (Object o : source) {
    // if we have object in source without
    // same object in target - it was added by user:
    if (!target.contains(o)) {
Iterator iterator = target.iterator();
while (iterator.hasNext()) {
    Object o = iterator.next();
    // if we have object in target without
    // same object in source - it was removed by user:
    if (!source.contains(o)) {

We have 2 full collection iterations. In most cases it will not cause big performance issue. But it looks bad and will cause performance problems with slow Collection implementations or with big amounts of data.

After using my brain few minutes I found the best way of comparing, with only one iteration:

Set source; // set of records from UI
Set target; // set of records in database
// just checking:
if (target.equals(source)) {
Iterator iterator = target.iterator();
while (iterator.hasNext()) {
    Object o = iterator.next();
    if (source.contains(o)) {
        // remove all checked objects for future
    else {
        // if source does not contains object -
        // it was removed by user, removing it from target:
// all object left in source are added by user.
// Adding them to target:

Simple enough, isn't it?


KDE for Windows

KDE 4.1 is here, and windows.kde.org packed it for Win32 already. As long as there are lots of useful apps in KDE without good win32 alternatives - I installed it on my working XP machine.

While Amarok is still in deep alpha - I couldn't start it. But there are two apps I can't live without - KWrite and Kompare. Both of them have great user interface, and gives you all advanced possibilities you can imagine. There is no other free editor to support about 90 different source file types and full encoding support, with possibility to open file with one encoding and to save with any other. There is no good file comparition program with such pretty and usable interface as Kompare. If you are interested - give it a try!

I am still waiting for Krusader and Okular, but my life under windows is already much simpler.

Security circus

In big outsourcing offices there are lots of security policies, and most of them are stupid enough. Don't you think so?

On my current job there is policy to change passwords every 3 weeks. What for? My first password was something like "R00mpel$htit$hen", while all the next password are "Anykey1", "Anykey2", ..., "AnykeyN". Same for all guys in my team. So, is office security much stronger now?


Java5 forever or Codename: No Future

Java6 exists almost two years now, and Java5 "is in its Java Technology End of Life (EOL) transition period". While I admire people, using top versions of Sun's Java, there are lots of folks, who are still using Java5. All of them have different reasons: someone just don't want to bother saying "Why should I?", someone have some strange compatibility or porting problems. Someone saying about business, about cost of migrating from Java5 to Java6.

But how long your project will exist on Java5? Year or two? You spent your money on your project, do you really want to join it's lifetime with Java5 lifetime?

Let me explain. You have project, you have
N services and X users. If your organization has no evolution - everything is just fine. But if your project grows - you have N = N + 1 services and X = X + 50 users each half-year. Once your current hardware will not be enough, you will move to better hardware. On better hardware you will have new operating system that supports all your hardware (for example, Windows 2003 Server supports only 4 CPUs/CPU kernels). And what if there will be no Java5 for that operating system? Sun is not supporting Java3, Java4 and soon Java5 anymore, who will care about your problems and your needs? Red Hat? Or Microsoft? Currently, there is even no possibility to download Java3 directly from Sun, or there is no Java4 for x86_64 platform. Do you want to make your business on zombie products?

Sun gives you the best platform of our times. Sun gives you standards, public APIs, open and flexible platform. Sun gives you own implementation of it's platform, saying there are lots of them around. Sun also guarantee backward compatibility (Java4-Java5 is another step, I am talking only about Java5-Java6 now), and only possible compatibility problem - usage of sun.** API. But even here Sun gave you compiler warning: "sun.** is Sun proprietary API and may be removed in a future release", and it's some king of mental retardation to ignore warnings like this.

So, as for me - if you can't move from Java5 to Java6 - your project is dead, and you is guilty in its death, no matter how long will it take to make it smell like old corpse.


KTorrent vs Anti-Cheater

After updating to SUSE 11.0 torrent client for KDE updated from KTorrent 2.2.1 to KTorrent 3.0.x. But on my favourite tracker I receive "Anti-Cheater: You cannot use this agent" as status message while using KTorrent 3. I installed KTorrent 3.1 - and get same message. But after installing back 2.2.x - everything works fine. So, problem is User-Agent string. It is not very hard to search over KTorrent sources and modify it a bit to change User-Agent string. I already mentioned great tutorial about rpm building, and this time it saved me again...

Get the source
Download the src.rpm file and unpack it. I am using mc to navigate into src.rpm and copy all files from there to
/home/to_build/src/ktorrent folder.

Diff to change user-agent
You can add diff to any spec file to apply it before build. It is much better than modify and pack sources back. So, here is my diff to change KTorrent 3.1 User-Agent string from "KTorrent + version" to plain "KTorrent". Now just save it in same folder ("/home/to_build/src/ktorrent" for me).

Modify spec file
Now only few modifications to spec file and time to start building:
Add this lines:

Patch10: user-agent.diff

It is easy enough to find where to insert it, there are already few patches applyed.

And now, to enable blocked by SUSE trackers, comment this two lines:
#Patch2: remove-links.diff

Now just build and use your favourite torrent-client with your favourite tracker!


SUSE 11.0 handmade

SUSE 11.0 released about a week ago. As few previous versions, there is lack of proprietary multimedia formats support. And there is few ways to resolve it. First, most common way - to add packman repository and install everything from there, and to find other repositories for freetype2 and few other packages. But I don't like this way. SUSE team did a great job with packages and integration, downloaded from other sources packages rarely have this level of integration. My way - to take official SUSE src.rpm packages from official source repositories, and build it with SUSE build tools.

There is a great tutorial about "build", it will introduce build procedure for you. It will prepare you for reading this article.
Also, there is some packages from internet repository you will need. I don't know why aren't they on DVD. You can store them to folder of provided packages, "/home/to_build/provided" for me. I got them from x86_64 repository, and videolan repository for libmad and libdvdcss.


Step One - xine
The most important multimedia part of SUSE distro - xine engine. Let's build it first.
1. Download xine-lib-1.1.12-8.1.src.rpm from SUSE repositories and unpack it to some (target) folder.
2. Remove xine-lib-1.1.12-crippled.tar.bz2 from target folder.
3. Download xine-lib-1.1.12.tar.bz2 from official sourceforge website and save it to target folder.
4. Open xine-lib.spec with your favourite editor.
5. Change line like this:
"%define BUILD_XINE %{?_with_internal:2}%{!?_with_internal:%build_xine_default}" to "%define BUILD_XINE 2".
6. Set Release to "Release: 8.1.1" - it will with pleasure override already installed xine.
7. Modify source declaration from crippled:

Source: xine-lib-%version-crippled.tar.bz2
%if 0
Source: xine-lib-%version.tar.bz2

Source: xine-lib-%version.tar.bz2

8. Find and comment each of lines to let sources be uncrippled:

Source99: precheckin_cripple_tarball.sh
Patch70: xine-lib-crippled-LOCAL.diff

9. Also, change all
"mad" and "mad-devel" dependencies to "libmad" and "libmad-devel".
10. just build it:

build --root /home/to_build/root --rpms /home/to_build/provided xine-lib.spec
11. Take your packages from

Step Two - Kaffeine
Kaffeine is best front-end for xine ever-made. Let's build it with DVD support!
1. Download kaffeine-0.8.6-54.1.src.rpm and unpack it.
2. Comment each of this lines:

Patch0: %name.diff
Patch2: messagebox-dvd.diff
3. Build it. I got small problem with some locale files, so you can just add locale files after icons packaging:



Step Three - FreeType2
There is no subpixel font smoothing in SUSE, so it will be useful for LCD owners.
1. Download freetype2-2.3.5-62.1.src.rpm from SUSE repository and unpack it, for example into "/home/to_build/src/freetype".
2. Download full FreeType2 from official website into same folder ("/home/to_build/src/freetype"), replacing old one.
3. Change two blocks:
Source0: http://download.savannah.gnu.org/releases/freetype/freetype-%{version}.tar.bz2
Source1: http://download.savannah.gnu.org/releases/freetype/freetype-doc-%{version}.tar.bz2
Source0: freetype-%{version}.tar.bz2
Source1: freetype-doc-%{version}.tar.bz2
and from
%define enable_subpixel_rendering 0%{?opensuse_bs}
%define enable_subpixel_rendering 1
4. Just build it and install packages from same folder -

That is all! Now you have your SUSE good as new, without less integrated third-party packages and without crippled multimedia. It's time to install win32 codecs from packman and libdvdcss from videolan before first kaffeine launch, install amarok-xine and remove buggy amarok-yauap plugin.


SUSE 11.0 first impression

Yesterday I have installed new SUSE 11.0 linux at home. Impressions are very ambiguous...

1. Package manager works great! Starting from SUSE 10.0 it was slower and slower, scanning repositories for minutes, than hours, checking depencencies, updating indexes and doing lots of interesting, but totally unusable staff. New package manager in 11.0 is faster than light! Adding huge repositories takes less than second, depencency checks are done faster than you can even notice!
Second great improvement for package manager - much better dependencies lists. I hate mono, banshee and other dotnet staff, I totally disregard it. But in SUSE 10.1 and 10.2 I HAD TO install mono just because of some yast pattern. That time I even downloaded few distros to look for SUSE replacement. Why, the Hell, I need software patterns for package manager if there are plain dependencies with straight structure?! But now I am totally happy - no mono, no beagle, no banshee, no gtk-sharps and other crap in my fresh system.

2. Older SUSEs with first boot after installing loaded yast to configure different devices, network and graphics. This did not. It was very hard to read fonts with default screen resolution (1280x1024), while installer worked with 1024x768.

3. Selection of KDE version is very hard. KDE 4.0.4 is very interesting, giving great fast new desktop experience. While there are some leaks: 1) I am not extreme enough to use PIM from unstable 4.1 sources; 2) Alt+Tab hangs sometimes when you have few windows from other users; 3) there is no printer configuration in KDE control center now, and YaST module changed from 10.2 and can't configure it for some reason... So, clicking few hours in KDE4 is great, but I'll wait a month for 4.1 to arrive.

4. It is hard to choose all programs from one of KDE desktops. KTorrent is KDE4 by default, KGet in KDE4 is totally great. But Dolphin will never move Krusader away, K3b and Amarok still not ported to KDE4, Gwenview of KDE4 differs too much from original KDE3 version, and older is much more usable.


No horses for Nurgle forces

There are four major Chaos Gods in Warhammer. Each of them has it's own main idea. And each of them differs so much from others, that it's hard enough to put all of them to one army. But the most separated from others is Nurgle.

Khorne means rage, blood. It is not hard to give horses or other mounts to bloody berserkers. Tzeentch is hope - he is bad only because he is opposite to imperium or Emperor, so he can do everything. Slaanesh is pleasure - nothing evil, just pleasure. But Nurgle is decay. How many animals will accept decay? How many possibilities decay have? Medieval horses were scared by smell of camels, what can we say about Nurgle warriors? Griffins, dragons - who will take decayed champion close to himself? The only way to get horses or other mounts for Nurgle warriors - put decay deep in their minds and bodies. Small job for major Chaos God, but almost impossible for his cults. Only humanity is decayed enough to accept Nurgle without compromises. This guys far from "grean peace", in spite of being green to.


LookAndFeel chooser

You will not dispute that modern desktop application needs some theming, right? And, being Swing developer, few times you tried to solve this problem, didn't you?..

I have solution now: JLAFChooser.
Now, you can just put JLAFChooser component into your setting dialog, and it will make LookAndFeel chosing possible in runtime. Now you have no need to hardcode all the LookAndFeels you know into your classes or XML files, and user can just download few LookAndFeels and put it somewhere in classpath to make it available to JVM.

It has two main variants: when Apply is allowed and when not.

When Apply is allowed your user can choose something from list and check it at once, and may be choose something else.

When Apply IS NOT allowed you can just show list of possible LookAndFeels, and save somewhere to preferences user selection, to apply it next startup.

Usage is similar to JColorChooser, with few extensions - you can get LookAndFeel instance, it's name or it's class name. Methods to apply and restore LookAndFeel are public, you may use them for your controls.

PS: feel free to mail me for suggestions, bugs, or just to talk about Java, Swing, religion, fantasy or anything...


current KDE version determination

I have a problem. KDE4 is comming, and I need to determine current running version from Java application. Do you know how?

After some investigations I found few ways. KDE is setting it's own env variables. For KDE3:


For KDE4:


But it works only for SUSE, Kubuntu have only KDE_SESSION_VERSION=4 and KDE_FULL_SESSION=true. And this is only for 8.04 KDE4 release of Kubuntu, there was no such flags in 8.04beta. So, determination is simple:

public static boolean isKDERunning() {
  return "true".equals(System.getenv("KDE_FULL_SESSION"));

public static boolean isKDE4Running() {
  if (!isKDERunning()) {
    throw new IllegalStateException("KDE is not running");
  return "4".equals(System.getenv("KDE_SESSION_VERSION")) ||

If you feel paranoid and want to get 100% result it will be better to run Konsole (konsole --version) and parse output. Output for different versions looks like this:

konsole --version
Qt: 3.3.8
KDE: 3.5.7 "release 72"
Konsole: 1.6.6

/usr/bin/konsole --version
Qt: 4.3.4
KDE: 4.0.3 (KDE 4.0.3) "release 9.1"
Konsole: 2.0

So, parsing code:

public static boolean isKDE4Version() throws Exception {
  Process process = Runtime.getRuntime().exec("konsole --version");
  InputStream in = process.getInputStream();
  byte[] buffer = new byte[32];
  ByteArrayOutputStream out = new ByteArrayOutputStream();
  int read = 0;
  while ((read = in.read(buffer)) >= 0) {
    out.write(buffer, 0, read);
  String output = out.toString();
  int indexOfKde = output.indexOf("KDE:");
  if (indexOfKde >= 0) {
    char v = output.charAt(indexOfKde + 5);
    return '4' == v;
  throw new IllegalStateException("KDE version information not found");

And don't fear performance issues - on my Athlon X2 6000+ this operation takes only 26 millis!


life before KDE 4.1

Lots of Linux distros will release major versions before KDE 4.1 will arrive. What for? May be better to still use KDE 3.5.x?

according to Wikipedia:

In principle, in subsequent releases, the major number is increased when there are significant jumps in functionality, the minor number is incremented when only minor features or significant fixes have been added, and the revision number is incremented when minor bugs are fixed.

according to Wikipedia:

KDE 4.0 was released on January 11, 2008. Despite being a stable release, it is intended for early adopters.
[22] Users wanting a stable, "feature complete" desktop may wish to continue using KDE 3.5 for now.[23]

Kubuntu will be released this month with KDE 4.0, Mandriva was released with KDE 4.0.2, and SUSE
will be released just few days before KDE 4.1 will arrive, with latest KDE 4.0.x on board.

I am not against releasing. I am just afraid of possible low quality of KDE 4.1 from update centers...


Do you like April 1?

Day of no-news. Every site see their duty to publish some "jokes". What for? Most of them are not funny nor interesting. Titles are the same as everyday yellow press. The only really interesting joke i noticed is this one.


Premature optimization is not THAT root of evil

Sometimes I can see really ugly code from my colleagues. Something like this:

ArrayList checkList = new ArrayList();
for (Item item : allItems) {
    if (item.isModified) {
for (Item item : itemsList) {
    if (checkList.contains(item)) {

Yes, there are situations, where you need hacks like this. But why, why are they using ArrayList to perform contains checks? HashSet is created for this job, why not to use it? For 10 items you will not see speed problems. For 100 items speed will lose few millis. For 10000 item you will count seconds!
No! I will not do it like you want! Premature optimization is root of evil!

Do you see premature optimization here? For me it is just making use of proper tool, tool that created for this task. Don't you think so?


Less than Hello World

Once I started to learn Assembler. I had a book of one russian hacker. First chapter of this book started like this:

Every book starts with "Hello, World" program. But reader can see programs, that can do more, than just pring "Hello, World". So he might think, that there is programs, that can do less, than "Hello, World".

For now, Assembler is dead, and we are using Java, as perfect technology.
So, less than "Hello, World!":

package helloworld;

public class LessThanHello {

    public static void main(String[] args) {