Saturday, July 29, 2006

Bird's Eye View of the GWT API

Last week, I wanted to "see" the whole picture, and put together this chart which shows the heirarchy of all of the user interface components that ship with GWT. Originally I wanted to include all of the interfaces as well, but I couldn't find a way to do it that wasn't totally confusing.

In the chart the orange rectangles represent abstract classes, and the while one are concrete classes. There are two classes which I put an orange border on, but did not color them in orange. These two are the Widget and TextBoxBase classes. The TextBoxBase does has a protected constructor, so I am not sure why it is not abstract. The Widget class on the other hand is a little more interesting. You can create a new instance of the Widget class, but since the setElement() method is protected you can't really do anything with it. I am assuming that this was an error and that the Widget class should have been made abstract.

Monday, July 24, 2006

See A Need, Fill A Need

The title refers to the animated movie Robots. In the movie Rodney, a robot with aspirations, goes to the big city to become an inventor. His motto is "see a need, fill a need". I have been trying to do the same thing with the GWT Widget Library, trying to fill the need where I know there is one. Based on some polling a few weeks ago the biggest need is for more widgets. 68% of those polled asked for more widgets above all else. With those results I started to focus my efforts on just widgets, and with some help from people like Adam Tacy, we have introduced quite a few in the last couple versions.

The question I want to ask is, what other widgets do you want to see added to the GWT-WL?

Please let us know what you want us to build, we need some more ideas. Leave a comment below and we will add it to the wish list.

Thanks.

Tuesday, July 04, 2006

CJD seeks FOL

Our world is a strange place. I started the GWT Widget Library with the intention of giving my code away for free. But I have found that it isn't quite that simple. You can't just give it away, you must license it.

I often find myself driving down the road, and see a pile of used baby toys with a sign that says "FREE". I now look at it a little differently. What I see is a lawsuit waiting to happen. Perhaps the person trying to get rid of the old toys (contributor) should have left a license next to the pile of junk, requiring a signature before a wanting individual (recipient) takes it away.

The cryptic title of this entry was meant to express a similar message as the wanted ads in the paper. In this case it means "Confused Java Developer seeks Friendly OpenSource Lawyer".

With the GWT Widget Library I have tried to protect myself by affixing the Apache 2.0 License, which allows for openness, and protects me from various litigation. The next problem is managing contributions to the library. I started looking at Individual Contributor License Agreements (ICLA), but from what I see, there aren't any agreements that I can just grab and reuse. Each agreement is specific in who is receiving the contribution, and in all cases that I have seen it is either a corporation or a foundation.

Do I need to start a foundation to allow for me to use ICLAs? Perhaps not, but then there is the issue with who's name appears as the copyright holder. Some contributors thus far have wanted there name to be there as a sort of recognition. I can understand this, after all, who want to look at a piece of source code that they contributed and at the top of the file see "Copyright Robert Hanson". I'll be honest, I don't want my name there. I feel that my name there takes away from the recognition that the original author deserves. But if I don't hold the copyright, how does that limit me down the road as other developers fix bugs and extend the contributed code.

It is a mess for sure. What can't "FREE" be free?

I have no solutions, only rants. I may decide to add a donation button to the GWT Widget Library SourceForge project so that I can pay for some legal advice, or maybe I will try to do some research myself (probably a bad idea).

So, with that said, I am open to suggestions... and donations... and free legal advice (with attribution of course).

Sunday, July 02, 2006

Calculator Widgets for GWT

One of the latest additions to the GWT Widget Library (GWT-WL) is a small set of calculator tools and widgets. This article will look at how you can use them in your project, beginning with the simplest use case and then working our way to building custom implementations.

PopupCalcButton

The PopupCalcButton is a widget that allows you to add a pop-up calculator tool to any TextBox. The code for this is very compact, so the easiest way to describe it's usage is to start with an example (or view the working demo).

TextBox calcTextBox = new TextBox();
Button showCalcBtn = new Button("Show Calc");
PopupCalcPanel calc =
new PopupCalcPanel(calcTextBox, showCalcBtn);

RootPanel.get().add(calcTextBox);
RootPanel.get().add(showCalcBtn);
RootPanel.get().add(calc);

We need to create a TextBox widget to recieve the calculated value, and a Button to activate the pop-up calculator. The flow of events starts when a user clicks the "Show Calc" button, which will display the calculator just below the TextBox widget. The user can use the calculator to calculate a result, then clicks a button in the calcluator labeled "DONE" to close the calculator and copy the result to our TextArea.

The PopupCalcPanel requires a reference to both the TextBox and Botton widgets. It will add event handlers to the Button for the calculator to appear, and uses the TextBox for positioning and to place the calculated total. The PopupCalcPanel provides no other options other than CSS tweaks.

The GWT-WL includes a single default CSS stylesheet for all calculator widgets shipped with the library. The stylesheet includes all of the style classes used by the widgets. To use the default you will need to add the following in the of your HTML code.

<link rel="stylesheet" type="text/css"
href="style/gwl-calcPanel.css">

SimpleCalcPanel

The SimpleCalcPanel uses a variation of the Template design pattern, and is meant to allow for easy customization by extending the class. By default it will render a TextBox, the calculator display, and a simple calculator keypad. You may make come cosmetic changes to the calculator using CSS without having to write your own subclass.

SimpleCalcPanel calcPanel = new SimpleCalcPanel();
RootPanel.get("example").add(calcPanel);

The SimpleCalcPanel has two public methods, getValue() and clearValue(). All other methods are protected, and cannot be accessed without subclassing the widget.

Extending SimpleCalcPanel

You can customize the SimpleCalcPanel by subclassing it and overriding one or more of it's methods. When the class is created it internally calls the init() method. You may override the init method, but in most case this is not recommended. The init() method for SimpleCalcPanel is below.

protected void init ()
{
TextBox textDisplay = createTextDisplay();
createCalc(createDisplayListener(textDisplay), textDisplay);
setKeyboardListener(textDisplay);
initComplete();
}

The init() method itself does very little work, and delegates the setup work to other methods in the class. Depending on what you are trying to do, you will override the methods that init() calls so that you can customize some part of the setup. You may, for example, want to use your own KeyboardListener for custom shortcuts, or use a text display other then a simple TextBox so that you can color the output red for negative numbers.

One of the methods that can be overridden is the buildCalcLayout(CalcEngine, TextBox) method. This method is called as part of the initialization, but not by init() directly. It is called as part of the createCalc() call. This method allows you to create the widgets that make up the display, including buttons, panels, and any other widgets you need. The only widget that you won't create is the TextBox calculator display, which is passed to the method. If you override this method you will need to add the TextBox to the panel yourself, or call the method in the super class.

Here is an extended example which extends the SimpleCalcPanel by adding a Hex/Decimal selector. This requires a custom TextBox for the display which can be toggled to show hex or decimal values. We also override the buildCalcLayout method so that we can add the new controls.


package org.hanson.gwt.client;

import org.gwtwidgets.client.ui.SimpleCalcPanel;
import org.gwtwidgets.client.util.CalcEngine;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;


public class MyApplication implements EntryPoint
{

public void onModuleLoad ()
{
RootPanel.get().add(new HexCalcPanel());
}


class HexCalcDisplay extends TextBox
{
public boolean isHexMode = false;

public void setText (String text)
{
if (isHexMode) {
double num = Double.parseDouble(text);
String hexString = Integer.toHexString((int) num);
hexString = hexString.toUpperCase();
super.setText(hexString);
}
else {
super.setText(text);
}
}
}

class HexCalcPanel extends SimpleCalcPanel
{
private HexCalcDisplay textBox;

protected TextBox createTextDisplay ()
{
textBox = new HexCalcDisplay();
textBox.setStyleName("simpleCalcDisplay");
return textBox;
}

protected void buildCalcLayout (
final CalcEngine calcEngine,
TextBox textDisplay)
{
RadioButton dec = new RadioButton("output", "Dec");
dec.setChecked(true);
dec.addClickListener(new ClickListener(){
public void onClick (Widget sender)
{
textBox.isHexMode = false;
calcEngine.refreshDisplay();
}
});

RadioButton hex = new RadioButton("output", "Hex");
hex.addClickListener(new ClickListener(){
public void onClick (Widget sender)
{
textBox.isHexMode = true;
calcEngine.refreshDisplay();
}
});

HorizontalPanel opts = new HorizontalPanel();
opts.add(dec);
opts.add(hex);
add(opts);

super.buildCalcLayout(calcEngine, textDisplay);
}
}
}



The CalcEngine

In some cases you will need to customize the control beyond what the SimpleCalcPanel allows. At the very heart of the calculator is the CalcEngine. The CalcEngine keeps track of the state of the calculator, the contents of the display, and the contents of the total register. It allows you to override methods for many of the operators, and gives you a programmatic way to refresh the display. It also has utility methods to adding number and operator buttons to your display. It is in every sense the heart of the system.

I believe that in most cases you will not need to override any of the CalcEngine methods, more likely you will use it as the core of your own calculator panel. In the future you can expect to see new functions added here in the core, which can then be used by calculator panels. The obvious enhancements include the addition of trigonometric and algebraic functions.

Conclusion

The calculator widget and engine set allows for ease of use, ease of extension, and the ability to create highly customized calculators. Future extensions will expand on it's potential, hopefully leading to productive components.