Friday, January 12, 2007

NetBeans Platform: CallbackSystemAction sync madness

An annoying problem I had this week involved the CallbackSystemAction class.

Basically the general ideea of this type of action is this: you have the Action implementation, but the "#actionPerformed code" is deferred.

What was my problem: depending on the user selection in an explorer, my action was supposed to become enabled or not (plus some othe conditions).

So, the javadoc says that way to do it is by setting an action in the ActionMap of the TopComponent.

TopComponent tc = ...;
javax.swing.Action yourCopyAction = ...; // the action to invoke instead of Copy

CopyAction globalCopyAction = SystemAction.get (CopyAction.class);
Object key = globalCopyAction.getActionMapKey(); // key is a special value defined by all CallbackSystemActions

// and finally:
tc.getActionMap ().put (key, yourCopyAction);

The problem is that there is no listener on the action map. So if I want later to disable my action and I do a tc.getActionMap().remove(key) -- it won't work ! I mean, it will work if you change the current TopComponent and come back to the original (I guess there are some event thrown there that CallbackSystemAction catches and does a refresh).

So, using the ActionMap.put and #remove doesn't work !

Ok, I said to myself, I'll just use the deprecated #setActionPerformer , which seems to work better. Only it is deprecated, which is not good.

I went and complained on the dev@openide mailing list and I got a tip that I should change my TopComponent's lookup in order to fire the events that CallbackSystemAction might catch to refresh itself.

But you can't call #associateLookup twice ! Arr.

So I just started reading carefully the CallbackSystemAction source code and I've noticed that it does put a listener on the enabled/disable state of the TopComponent's action (ie. yourCopyAction in the example above).

So -- what's the solution ? Dead simple: call getActionMap().put(...) once and then just do a #setEnabled on your Action. Simple -- but very non-intuitive.

Actually in this situation I would say that the Javadoc was more confusing than useful because it says

The action will be automatically disabled when it has no performer.

and removing your action from the ActionMap means exactly that: no performer...

Saturday, January 06, 2007

NetBeans Platform: Combobox in property editor

Happy new year everyone !

I'm going to talk today about something simple GUI-wise but quite a lot asked on the mailing lists: how does one display a combobox in the property editor ? Actually, how does one use an editor that displays a combobox.

What should get you started with this task (and other editor customizing) is a little file from the Platform javadoc.

This is what we plan to get:

In order to do this note the Custom parameters in core editors paragraph from the above link and the fact that for java.lang.Integer properties there are some custom keys we can use:
  • stringKeys - an array of strings to be present in the combobox
  • intValues - an array of integers representing the values of the selection in the combobox.
So something like this:

Node.Property p=new YourProperty(Integer.class);
p.setValue("intValues",new int[]{1,2,3,4});
p.setValue("stringKeys",new String[]{"One","Two","Three","Four"});

is all you need.

Note: Please take care that for the current property
  • #getValue is the index in the intValues array. So if you want to see "Three" in the combobox, you return the number 2 in #getValue.
  • #setValue is called with the actual number from intValues (not the index). So if the user selects "Four" from the combobox, #setValue(4) will be called.

The Trouble with Harry time loop

I saw The Trouble with Harry (1955) a while back and it didn't have a big impression on me. But recently I rewatched it and was amazed a...