Todd has posted 1 posts at DZone. View Full User Profile

Table Row Editing in Apache Pivot

04.30.2009
| 13621 views |
  • submit to reddit

Conventional wisdom holds that there are two ways to edit table data.  You can either use an inline cell editor, or you can launch an edit dialog that lets you edit the whole record at a time.  Wouldn't it be neat if we could get the best of both worlds and edit the entire record inline?  As it turns out, Apache Pivot provides this type of table row editor out of the box.  What follows is a simple example of how to use this useful feature.

The following image shows a screen shot of the demo application that we'll be covering. A live example is available here. The application contains a small set of sample data that may be edited by double clicking on a row.

Sample Row Editing Application

The WTKX source for the demo is as follows:

<Window title="Row Editor Demo"
maximized="true"
xmlns:wtkx="http://incubator.apache.org/pivot/wtkx/1.1"
xmlns:collections="pivot.collections"
xmlns:content="pivot.wtk.content"
xmlns:demo="pivot.demos.roweditor"
xmlns="pivot.wtk">
<content>
<Border styles="{padding:0}">
<content>
<ScrollPane horizontalScrollBarPolicy="fillToCapacity">
<view>
<TableView wtkx:id="tableView" selectMode="single">
<columns>
<TableView.Column name="date" width="87" headerData="Date"/>
<TableView.Column name="type" width="125" headerData="Type"/>
<TableView.Column name="amount" width="75" headerData="Amount">
<cellRenderer>
<content:TableViewNumberCellRenderer numberFormat="¤#,##0.00"/>
</cellRenderer>
</TableView.Column>
<TableView.Column name="description" width="1*" headerData="Description"/>
</columns>
<tableData>
<collections:ArrayList>
<demo:CustomTableRow date="2009-03-28" type="Travel"
amount="1286.90" description="Ticket #145-XX-71903-09"/>
<demo:CustomTableRow date="2009-03-28" type="Meals"
amount="34.12" description="Took client out"/>
<demo:CustomTableRow date="2009-03-31" type="Meals"
amount="27.00" description=""/>
<demo:CustomTableRow date="2009-04-01" type="Meals"
amount="12.55" description=""/>
<demo:CustomTableRow date="2009-04-02" type="Meals"
amount="18.86" description=""/>
<demo:CustomTableRow date="2009-04-02" type="Parking"
amount="30.00" description="Cambridge Center parking"/>
<demo:CustomTableRow date="2009-04-03" type="Meals"
amount="20.72" description=""/>
<demo:CustomTableRow date="2009-04-06" type="Hotel"
amount="529.90" description="Marriott reservation #DF-9982-BRN"/>
</collections:ArrayList>
</tableData>
</TableView>
</view>
<columnHeader>
<TableViewHeader tableView="$tableView" styles="{headersPressable:false}"/>
</columnHeader>
</ScrollPane>
</content>
</Border>
</content>
</Window>

It contains a maximized, decorationless window with a Border as its content. The Border contains a ScrollPane containing the data.  For the purposes of the demo, I hard-coded sample data into the WTKX. There are four columns: date, expense type, amount, and description. For amount, I use a cell renderer that formats the number as currency.

The Main Application Class

Since Pivot includes a default table view row editor, there's really not much required to get this demo up and running. However, the default row editor will use TextInput instances for the individual cell editors unless we tell it otherwise. In this case, I wanted to make a few changes. For date, I wanted use a Spinner with a custom data model. For expense type, I wanted a ListButton that would let the user choose among the different enum values for expense type. Finally, for amount, I wanted a TextInput that would validate the text such that only valid currency values would be accepted.

The startup() method of the application is where most of the work lies; it is shown below:

public void startup(Display display, Dictionary<String, String> properties)
throws Exception {
WTKXSerializer wtkxSerializer = new WTKXSerializer();
window = (Window)wtkxSerializer.readObject(getClass().getResource("demo.wtkx"));
window.open(display);

TableView tableView = (TableView)wtkxSerializer.getObjectByName("tableView");
TableViewRowEditor tableViewRowEditor = new TableViewRowEditor();
tableView.setRowEditor(tableViewRowEditor);

// Date uses a Spinner with a CalendarDateSpinnerData model
Spinner dateSpinner = new Spinner(new CalendarDateSpinnerData());
dateSpinner.setSelectedItemKey("date");
tableViewRowEditor.getCellEditors().put("date", dateSpinner);

// Expense type uses a ListButton that presents the expense types
ListButton typeListButton = new ListButton
(new EnumList<ExpenseType>(ExpenseType.class));
typeListButton.setSelectedItemKey("type");
tableViewRowEditor.getCellEditors().put("type", typeListButton);

// Amount uses a TextInput with strict currency validation
TextInput amountTextInput = new TextInput();
amountTextInput.setValidator(new CurrencyValidator());
amountTextInput.getStyles().put("strictValidation", true);
amountTextInput.setTextKey("amount");
tableViewRowEditor.getCellEditors().put("amount", amountTextInput);
}

It first instantiates a WTKX serializer to load the UI from the WTKX file. It then obtains a reference to the table view and sets the row editor on the table view. Finally, it makes the desired modifications to the row editor by creating three custom cell editor components and mapping them to their corresponding columns using the row editor's getCellEditors() method. Note that the row editor uses Pivot's data binding facilities to get the data from the row into the cell editor components and to get the data back out when it's time to save the user's edits. As such, notice how I set up the data binding keys on each custom cell editor that I created.

Supporting Classes

The final pieces of the puzzle are the supporting classes that I've used in the demo: CurrencyValidator, CustomTableRow, and ExpenseType. First, let's look at the validator:

public class CurrencyValidator implements Validator {
public boolean isValid(String text) {
boolean valid = true;

if (text.length() > 0) {
try {
BigDecimal numericAmount = new BigDecimal(text);
valid = (numericAmount.scale() <= 2
&& numericAmount.signum() >= 0);
} catch (NumberFormatException ex) {
valid = false;
}
}

return valid;
}
}

This validator simply ensures that the text in the amount text input can be represented as a positive BigDecimal with a decimal precision less than or equal to 2.

The source for CustomTableRow is as follows:

public class CustomTableRow {
private CalendarDate calendarDate = null;
private ExpenseType type = null;
private double amount = 0;
private String description = null;

public CalendarDate getDate() {
return calendarDate;
}

public void setDate(CalendarDate calendarDate) {
this.calendarDate = calendarDate;
}

public final void setDate(String calendarDate) {
setDate(new CalendarDate(calendarDate));
}

public ExpenseType getType() {
return type;
}

public void setType(ExpenseType type) {
this.type = type;
}

public final void setType(String type) {
setType(ExpenseType.valueOf(type));
}

public double getAmount() {
return amount;
}

public void setAmount(double amount) {
this.amount = amount;
}

public final void setAmount(String amount) {
if (amount == null || amount.length() == 0) {
setAmount(0);
} else {
setAmount(Double.parseDouble(amount));
}
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}
}

This is a simple value object with a few overloads. The first overload, setDate(String), is to support the creation of a CustomTableRow in WTKX. The second, setAmount(String), is to support binding a table row's amount to a TextInput.

Finally, let's take a look at the ExpenseType enum:

public enum ExpenseType {
Hotel,
Miscellaneous,
Meals,
Parking,
Travel;
}

For the sake of simplicity, I used human-readable values within the enum and presented the values using an EnumList set as the model of my ListButton. If this were a real-world application, I would have to consider localization and would have probably used a custom ListView.ItemRenderer on the list button.

Conclusion

So, building a table view row editor that allows the user to edit an entire record inline is very easy using Pivot, and it's a convenient new UI metaphor for editing table data. Note that Pivot's TableView.RowEditor interface does not preclude the application developer from building a more traditional editor (in fact, Pivot includes a stock TableViewCellEditor as well), leaving your options open as to which paradigm makes the most sense for you.

The full source for this demo is available here. For more information on Apache Pivot, visit http://incubator.apache.org/pivot.

 

Legacy
Article Resources: 
Published at DZone with permission of its author, Todd Volkert.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Zqudlyba Navis replied on Thu, 2009/04/30 - 1:48am

XML programming is bad bad bad.....it takes us back to the bad old days of spring xml configuration programming, struts 1.x xml configuration programming, hibernate configuration programming......and JSF. The world has moved on to expressive dynamic languages for doing RIA.

Otengi Miloskov replied on Thu, 2009/04/30 - 2:24am in response to: Zqudlyba Navis

Where is that RIA solutions with dynamic languages?. Im agree xml should not be used for development of GUI and another things but only for describe documents.

Greg Brown replied on Thu, 2009/04/30 - 7:39am in response to: Zqudlyba Navis

> The world has moved on to expressive dynamic languages for doing RIA

I have to respectfully disagree. The top two RIA platforms, Flex and Silverlight, use XML markup for UI construction (MXML and XAML, respectively). The web itself is based on HTML, another kind of markup language.

Note that in all of these cases, markup is used only to declare the structure of the UI. It's not for "configuration" or "programming". All logic is still implemented in code (ActionScript in Flex, C#/JavaScript in Silverlight, JavaScript in HTML, and Java in Pivot).

Greg Brown replied on Thu, 2009/04/30 - 7:41am in response to: Otengi Miloskov

> xml should not be used for development of GUI and another things but only > for describe documents

XML is actually an ideal way to describe the structure of a user interface, because its hierarchical nature closely parallels the component hierarchy employed by most UI toolkits. It makes it easy for a developer to visualize the resulting output.

Greg Brown replied on Thu, 2009/04/30 - 7:45am

I should also point out that the use of XML to construct interfaces in Pivot is entirely optional. The same results can be achieved programmatically (though, IMO, more verbosely).

Todd Volkert replied on Thu, 2009/04/30 - 9:37am in response to: Greg Brown

I'll just mirror what Greg said, as I was going to write basically the same response :)

Jacek Furmankiewicz replied on Thu, 2009/04/30 - 10:54am in response to: Greg Brown

I agree with the posters above that writing UIs in XML is a nightmare. It's like putting on weights on your ankles and expecting you to run.

I guess I gotta finally re-start that that Pivot JavaBuilder we prototyped a few months ago...YAML would suit Pivot perfectly.

Greg Brown replied on Thu, 2009/04/30 - 11:08am in response to: Jacek Furmankiewicz

> I agree with the posters above that writing UIs in XML is a nightmare

Well, to each his/her own. :-)

Let us know if there's anything we can do to help.

Todd Volkert replied on Thu, 2009/04/30 - 11:12am in response to: Jacek Furmankiewicz

Your point is well taken.  Note that WTKXSerializer is layered on top of the core windowing toolkit (it's not hard-wired in), and as such, any other declarative UI interpreter could be as well (who knows - maybe even one for JavaFX script!).

Jacek, you should join the pivot-dev list (see http://incubator.apache.org/pivot/lists.html) -- we'd love to see some work done on a YAM-based Pivot Builder.

Dominique De Vito replied on Sun, 2009/05/03 - 10:57am in response to: Jacek Furmankiewicz

I agree with the posters above that writing UIs in XML is a nightmare. It's like putting on weights on your ankles and expecting you to run.

Maybe. But it's a common and well-accepted UI definition: IMHO, quite like a (X)HTML flavor. So, the transition will be fine for most people.

But, I have a question about this XML definition. There are tag names in lower case like 'columns', in upper case like 'Border', with composed name like 'TableView.Column'...

What is the purpose of such diversity ?

Thanks.

 

 

Todd Volkert replied on Mon, 2009/05/04 - 10:37am in response to: Dominique De Vito

In WTKX, upper-case tags instantiate objects (the tag name is the class name), and lower-case tags represent bean properties of the containing tag's object. Thus:
<Window xmlns="pivot.wtk"> <!-- Create a pivot.wtk.Window object -->
    <content>  <!-- now we're setting the "content" bean property -->
        <Border>  <!-- create a pivot.wtk.Border, and call window.setContent(border) -->
            ...
        </Border>
    </content>
</Window>

Jose Maria Arranz replied on Tue, 2009/05/05 - 9:34am

I agree with tvolkert and Greg, in my opinion this is a correct use of XML , in this case the XML *describes* the static *hierarchy* of the UI components and programming is done in Java, a good match and good separation of concerns, XML is fine to describe tree based hierarchies.

If something similar had been standardized in Swing, visual editors would be more interoperable and visual edition would be compatible with code added by hand (like adding markup by hand using the Pivot analogy).

Windows has used this approach with something analogous to XML many years ago.

The case of XML in Spring or JSF is different, XML is used for programming.

In some way Pivot approach is like web development in client: pieces of HTML used as patterns and JavaScript and DOM APIs for dynamic behavior. The same is done in some Java server centric web frameworks like Wicket or  ItsNat (change JavaScript for Java), HTML code describes the static layout (the hierarchy) and visual patterns and Java code adds the dynamic behavior.

 

Jose Maria Arranz replied on Tue, 2009/05/05 - 9:40am

Anyway I see some attempt in Pivot to follow the wrong path (IMHO): adding more and more metaprogramming to XML description files. For instance I don't like very much the presence of <tableData> in a UI-centric file, this temptation of mixing everything in the same file is appeling but it breaks the basic separation of concerns.

 

Greg Brown replied on Wed, 2009/05/06 - 7:37am in response to: Jose Maria Arranz

Hi Jose,

> I don't like very much the presence of in a UI-centric file

That's a great point. This is just an example. In general, you wouldn't do this in a "real" application.

Greg

Kathy John replied on Tue, 2012/02/21 - 1:04pm

From the perspective of someone who is fairly new to Pivot and writing a decent-sized standalone app with it, I can say that Pivot's API is about 10,000 times cleaner than the other choices available for Java...If you need to give a Java app a nice UI with little fuss, I recommend Pivot wholeheartedly

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.