Monday, February 25, 2008

Using boolean state actions in NetBeans RCP

This post can be categorized as a code snippet and shows how to work with CallableSystemAction and BooleanStateAction.

If you create a new action through the new action wizard your code looks something like:


public final class SomeAction extends CallableSystemAction {

public void performAction() {
// TODO implement action body
}

public String getName() {
return NbBundle.getMessage(SomeAction.class, "CTL_SomeAction");
}

@Override
protected String iconResource() {
return "path/to/your/icon.png";
}

public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}

@Override
protected boolean asynchronous() {
return false;
}
}


The action allows you to execute some code (in the performAction() method) when the used clicks the button.
On the other side, a boolean action is like a toggle button. Imagine a play button, it can be pushed to indicate the music is playing and in normal state (not pushed) indicating the player is stopped. This can be achieved with a BooleanStateAction instead of a CallableSystemAction. Modify the previous code to:


public final class SomeAction extends BooleanStateAction implements PropertyChangeListener
{

public SomeAction()
{
// Set the initial state
setBooleanState(true);

// Register as a property listener
addPropertyChangeListener(this);
}

public String getName()
{
return NbBundle.getMessage(SomeAction.class, "CTL_SomeAction");
}

@Override
protected String iconResource()
{
return "path/to/your/icon.png";
}

public HelpCtx getHelpCtx()
{
return HelpCtx.DEFAULT_HELP;
}

public void propertyChange(PropertyChangeEvent evt)
{
// Check if the boolean state has changed.
if(BooleanStateAction.PROP_BOOLEAN_STATE.equals(evt.getPropertyName())) {

Boolean state = (Boolean) evt.getNewValue();
if (state.equals(Boolean.TRUE)) {
// Button has been pressed
}
else {
// Button has been releases
}
}
}
}


How it works?
Both CallableSystemAction and BooleanStateAction are direct subclasses of org.openide.util.actions.SystemAction. When a system action is executed its abstract actionPerformed method is invoked.

// In SystemAction...
public abstract void actionPerformed(ActionEvent ev);


In the case of CallableSystemAction, the override method makes some work and finally invokes the performAction which is the method you need to code.

public void actionPerformed(ActionEvent ev) {
if (isEnabled()) {
org.netbeans.modules.openide.util.ActionsBridge.doPerformAction(
this,
new org.netbeans.modules.openide.util.ActionsBridge.ActionRunnable(ev, this, asynchronous()) {
public void run() {
performAction();
}
}
);
} else {
// Should not normally happen.
Toolkit.getDefaultToolkit().beep();
}
}


In the case of BooleanStateAction, this class maintains a property which represents the state of the button. When the override actionPerformed method is execute it changes the property state and fires a property change event to be cached by the BooleanStateAction listeners:

public void actionPerformed(java.awt.event.ActionEvent ev) {
setBooleanState(!getBooleanState());
}

public void setBooleanState(boolean value) {
Boolean newValue = value ? Boolean.TRUE : Boolean.FALSE;
Boolean oldValue = (Boolean) putProperty(PROP_BOOLEAN_STATE, newValue);

firePropertyChange(PROP_BOOLEAN_STATE, oldValue, newValue);
}


As you can see in the SomeAction code the tip resides in registering the class as its own listener and handle the state change in the propertyChange method.

Monday, February 18, 2008

Changing default action's icon in NetBeans RCP

If you are developing an application using NetBeans RCP probably you are using default actions like Delete, Cut or Save that uses its own icons. This post talks about two techniques so change the default icons associated to an existent action.

Branding
The first method to change the default icon is through the branding directory in your module suite. To allow this, you need to know in which Java package is stored the icon resource used by the action you want to change its icon. A good way to know this is downloading the NetBeans platform (or other module) source code, looking for the action code and get the icon's resource path.

For example, the Cut and Delete actions are in the package org.openide.action. If you want to override it with your own icons all you need to is is to create, in your module suite branding directory, a folder called org-openide-action.jar, create a subfolder hierarchy representing the package structure and put your own icons with the same name the action code uses.



Wrapping
The second method implies to create a new action that wraps the target action you want to change its icons.
The below present a little class WrapperCutAction that wraps the NetBeans CutAction. The idea is pretty simple, the wrapper action can have any desired icon and when it is executed only you need to do is redirect the event to the target action.


package yourpackage;

import java.awt.event.ActionEvent;
import org.openide.actions.CutAction;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallbackSystemAction;

public final class WrapperCutAction extends CallbackSystemAction {

public static final String ICON_PATH = "org/balloon/ui/icons/edit-cut.png";
// Wrap the target action
private CutAction ca = new CutAction();

public String getName() {
return NbBundle.getMessage(WrapperCutAction.class, "CTL_WrapperCutAction");
}

protected String iconResource() {
return ICON_PATH;
}

public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}

protected boolean asynchronous() {
return false;
}

// Wrap the target methods
public void actionPerformed(ActionEvent e) {
ca.actionPerformed(e);
}

public Object getActionMapKey() {
return ca.getActionMapKey();
}
}

Sunday, February 17, 2008

R2D2 Translator

I have just received an email from a friend with an amazing feature: the R2D2 translator.

If you are a friki, freak, nerd or geek (like me?) probably this like you a lot.

Wednesday, January 30, 2008

A quieter theme for the eyes

I found this post (via DZone) pointing to a new NetBeans editor color theme, called Aloha, that is more quiet, not as highlighted as the default but similar to norway today theme.

Tuesday, January 29, 2008

A file format repository

Today, via Black Byte I found wosit.

The Wosit slogan is The programmer's file and data resources. It contains a lot of file format specifications categorized on different areas: music, GIS, image, etc.

Probably you can read many of these file formats through a library but if you are who program the library you are welcome to take a look.

Tuesday, January 22, 2008

Some notes on GlassFish v2, JDK6 and JDBC4 (PostgreSQL)

These are my today experiences (really my today headaches) porting a couple of applications from GlassFish v1 running with JDK5 to GlassFish v2 running with JDK6.

The applications was developed with NetBeans 5 and consist of a couple of EJB modules and a couple of web applications using the VisualWebPack in the NetBeans 5 (JSF).

First, I downloaded and installed JDK6 and GlassFish v2.

Before deploying the application you must take into account that my JDBC driver in GF1 (running JDK5) was a JDBC3 PostgreSQL driver. This driver is compiled for JDK5, thus I need to download and install (in the GF2 server) the JDBC4 version (not completed yet).

Next, I have created some database resources using the JDBC4 drivers. This works but generates a lot of warnings when application runs. To avoid them you need to put this option in your resources JDBC30DataSource=true.

Finally I have developed the applications. I this step I found strange behaviors and some server crashing problems. After trying 1000 thing I found that the problem was in a hyperlink in a JSF page. For an unknown reason, changing the hyperlink by a button (mantaining the same action) resolve the problem.

If you are working, like me, with PostgreSQL I would like to point this link about sequences:
http://wiki.glassfish.java.net/Wiki.jsp?page=FaqPostgresSequences

Monday, January 07, 2008

Wikia is here !!!

Wikia is the wiki search engine of wikipedia author. The results of the searches are based on people , in the same way the wikipedia is based on people.
Wikia's search engine concept is that of trusted user feedback from a community of users acting together in an open, transparent, public way. Of course, before we start, we have no user feedback data. So the results are pretty bad. But we expect them to improve rapidly in coming weeks, so please bookmark the site and return often.

It has a lot of interesting things, like the miniarticles, people matching the same search, different indexes and the "next results button" (usually we don't see far away than the first ten o twenty entries).

Friday, January 04, 2008

NetBeans and the suite chaining

Lately I was fighting with the suite chaining concept. Although you need to do some thing manually (there is no automatic task in NB) it is very straightforth to do it.
Sorry, but I think for reading the next lines you must be familiarized with the NetBeans jargon. It is not too much complex but sounds you as a foreign language you can't understand. You can start reading this first.

As the documentacion in the $NETBEANS/harness/README file says:
Suppose you have one platform P1, say the bare NetBeans Platform. Then you have a module suite S1 with modules M1a...M1z which uses P1. Now it may happen that you want another suite S2 with modules M2a...M2z to depend on S1 as well as P1. This is possible, though not yet trivial to set up. Basically, you will make a new platform P2 by building S1 + P1.

The idea is create a module suite S2, instead of based in the NetBeans platform, based on a derived platform build from a previous module suite S1.

Ok, that sounds easy but what about a real study case? Well, to explain it I prefer to point this post in the Fabrizzio's blog: NetBeans RCP - beyond suite chaining.

Friday, December 21, 2007

Emulating a click event on XWindow

A couple of weeks ago I found this old peace of code to emulate a mouse click button event on XWindows systems.
If somebody has programmed with IDL or executed a distributed program with its virtual machine, you'll have noticed that you must click obligatory in the eternal IDL splash srceen.
Well, this code makes this for you. You can create an script that launch your IDL program and a few second later execute this little program.


/path_to_idl/idl -vm=you_program.sav
sleep 3
xboton


I want to point that the next code has HTMLified thanks to C++2HTML:


/* Name: xboton
* Author: Antonio Santiago [asantiagop(at)gmail(dot)com]
* Description: xboton emulates a click with a mouse pointer in the middle
* of screen.
* Compile: gcc -o xboton xboton.c -lX11 -L/usr/X11R6/lib
*/


#include <stdio.h>
#include <string.h>

#include <X11/Xlib.h>
#include <X11/Xos.h>
#include <X11/Xutil.h>

int
main() {

Display *display;

Window root, win, subwin;
XEvent event;
XWindowAttributes attrib;
unsigned int
width, height;


/* Open a display connection and get root window size. */

display = XOpenDisplay(NULL);
root = RootWindow(display, DefaultScreen(display));

if
( XGetWindowAttributes(display, root, &attrib) == 0 )

printf("Error: Can't retrieve root window size\n");

width = attrib.width;
height = attrib.height;


/* Move mouse pointer to middle if screen and get the ID of
* the window at this point.
*/

XWarpPointer(display, None, root, 0,0,0,0, width/2, height/2);

bzero(&event,sizeof(XEvent));

event.type = ButtonPress;

event.xbutton.button = Button1;
event.xbutton.same_screen = True;


XQueryPointer(display, root,
&
event.xbutton.root, &event.xbutton.window,
&
event.xbutton.x_root, &event.xbutton.y_root,
&
event.xbutton.x, &event.xbutton.y,
&
event.xbutton.state);

event.xbutton.subwindow = event.xbutton.window;
event.xbutton.state = Button1Mask;



/* Walk down through window hierachy to find youngest child */

while
(event.xbutton.subwindow) {
event.xbutton.window = event.xbutton.subwindow;

XQueryPointer(display, event.xbutton.window,
&
event.xbutton.root, &event.xbutton.subwindow,
&
event.xbutton.x_root, &event.xbutton.y_root,
&
event.xbutton.x, &event.xbutton.y,
&
event.xbutton.state);
}


/* Send a ButtonPress and ButtonRelease (of button 1) to the middle screen window */

if
( XSendEvent(display, event.xbutton.subwindow, True, ButtonPressMask, &event) == 0)

printf("Error: XSendEvent error on ButtonPress event\n");
XFlush(display);

event.type = ButtonRelease;

event.xbutton.state = Button1Mask;
if
( XSendEvent(display, event.xbutton.subwindow, True, ButtonPressMask, &event) == 0)

printf("Error: XSendEvent error on ButtonRelease event\n");
XFlush(display);
}




Be happy don't worry.

Saturday, December 15, 2007

Working with wizards

Looking for information about how pass data among the panels of a wizards, I found these links posts in the Geertjan's Weblog about how wizards works in NB:

How wizards work: part 1, 2, 3, 4 and 5.