Geertjan is a DZone Zone Leader and has posted 467 posts at DZone. You can read more from them at their website. View Full User Profile

Getting Even Further with Spring RCP (1)

07.07.2008
| 32263 views |
  • submit to reddit

Creating a Composite Dialog

In Getting Further with Spring RCP, we created a Customer Properties dialog. It extended the Spring RCP "TitledPageApplicationDialog" class. It displayed the content of one single Spring RCP "AbstractForm" class, the CustomerForm. However, what if you want to display multiple forms within the same dialog? Conceptualizing this is important—it underlines the difference between a dialog and a form, in the Spring RCP world, because they're not the same thing. You'll see, by the end of this section, that an "AbstractForm" can be seen as a display unit that is decoupled from the dialog that displays it.

To really understand this, I split my CustomerForm class into two separate form classes—one called "CustomerForm" and the other "AddressForm". For example, this is what the CustomerForm looks like now, with all address-related content removed into the separate "AddressForm" class, which contains nothing but address-related content:

public class CustomerForm extends AbstractForm {

private JComponent firstNameField;

public CustomerForm(Customer customer) {
super(customer);
setId("customer");
}

@Override
protected JComponent createFormControl() {
TableFormBuilder formBuilder = new TableFormBuilder(getBindingFactory());
formBuilder.setLabelAttributes("colGrId=label colSpec=right:pref");
formBuilder.addSeparator("General");
formBuilder.row();
firstNameField = formBuilder.add("firstName")[1];
formBuilder.add("lastName");
formBuilder.row();
return formBuilder.getForm();
}

public boolean requestFocusInWindow() {
return firstNameField.requestFocusInWindow();
}

}

 

However, now that we have TWO forms, how do we let the user work with both simultaneously? The answer is twofold—firstly, by means of the Spring RCP "TabbedDialogPage" class; secondly (alternatively), by means of the Spring RCP "TreeCompositeDialogPage" class. These are containers that organize other dialog pages into a tabbed structure or a tree structure. Let's first look at the code that relates to the "TabbedDialogPage" class. The result of that code will be a dialog with two tabs, each displaying one of the two forms, together providing one user interface for editing the data in question:

 

And here's the code:

private class PropertiesExecutor extends AbstractActionCommandExecutor {

private CustomerForm customerForm;
private AddressForm addressForm;
private CompositeDialogPage compositePage;
private TitledPageApplicationDialog dialog;

private void createDialog() {

customerForm = new CustomerForm(new Customer());
addressForm = new AddressForm(new Customer());

compositePage = new TabbedDialogPage("customerProperties");
compositePage.addForm(customerForm);
compositePage.addForm(addressForm);

dialog = new TitledPageApplicationDialog(
compositePage, getWindowControl(), CloseAction.HIDE) {

@Override
protected void onAboutToShow() {
customerForm.requestFocusInWindow();
setEnabled(compositePage.isPageComplete());
}

@Override
protected boolean onFinish() {
return true;
}

};

}

@Override
public void execute() {
if (dialog == null) {
createDialog();
}
customerForm.setFormObject(customerTable.getSelectedCustomer());
addressForm.setFormObject(customerTable.getSelectedCustomer());
dialog.showDialog();
}

}

 

To use the Spring RCP "TreeCompositeDialogPage" class instead, there's literally nothing more you need to do than change line 13 above to the following:

compositePage = new TreeCompositeDialogPage("customerProperties");

 

The result of the above, i.e., the result of changing ONE line of code, would be the following:

 

You wil notice, though, that when you use any of the above dialogs, and you make a change, the change is NOT stored. That's because we need to commit changes back to the model, which is the typical way in which Spring RCP works. The model is, normally, provided by the Spring RCP "FormModel" class. However, in this case, we're not dealing with forms anymore, we're primarily dealing with the container that contains those forms. Therefore, we need to introduce the Spring RCP "HierarchicalFormModel" class. Rewrite all the code above to the following, taking note of the "HierarchicalFormModel" class used in lines 3, 14, 16, 17, and 33:

private class PropertiesExecutor extends AbstractActionCommandExecutor {

private HierarchicalFormModel ownerFormModel;

private CustomerForm customerForm;
private AddressForm addressForm;

private CompositeDialogPage compositePage;

private TitledPageApplicationDialog dialog;

private void createDialog() {

ownerFormModel = FormModelHelper.createCompoundFormModel(new Customer());

customerForm = new CustomerForm(FormModelHelper.createChildPageFormModel(ownerFormModel, null));
addressForm = new AddressForm(FormModelHelper.createChildPageFormModel(ownerFormModel, null));

compositePage = new TreeCompositeDialogPage("customerProperties");
compositePage.addForm(customerForm);
compositePage.addForm(addressForm);

dialog = new TitledPageApplicationDialog(compositePage, getWindowControl(), CloseAction.HIDE) {

@Override
protected void onAboutToShow() {
customerForm.requestFocusInWindow();
setEnabled(compositePage.isPageComplete());
}

@Override
protected boolean onFinish() {
ownerFormModel.commit();
return true;
}

};

}

@Override
public void execute() {
if (dialog == null) {
createDialog();
}
customerForm.setFormObject(customerTable.getSelectedCustomer());
addressForm.setFormObject(customerTable.getSelectedCustomer());
dialog.showDialog();
}

}

 

Now, when you click Finish, thanks to line 33 the changes will be saved to the model and reflected back in the view. Finally, let's look at the related "messages.properties" file. These are the key/value pairs that are relevant here:

customerProperties.title=Customer Properties

customerProperties.customer.title=Customer
customerProperties.customer.description=Changes customer properties

customerProperties.address.title=Address
customerProperties.address.description=Change address properties

 

Take careful note of the above. As with all Spring RCP messages, the "." in the key is significant. The first message uses the ID of the container (i.e., "customerProperties"), followed by the property ("title"). However, the others make use of two IDs: the ID of the container ("customerProperties"), followed by the ID of the form ("customer" or "address"), which is then followed by the property ("title" or "description").

Hurray, you've created your first Spring RCP "CompositeForm", making use of two separate form classes, decoupled from each other and from the dialog in which they're displayed. In this way, you can mix and match multiple forms, reusing them in different ways across different dialogs. Also, look at how easy it was to create completely different layouts—it took ONE change to switch from a tabbed view to a tree view. Bear these concepts in mind for the duration of this article, because it will come back again in a different context later.

 

AttachmentSize
figure-1.png23.7 KB
figure-2.png27.1 KB
figure-3.png17.91 KB
figure-4.png20.39 KB
figure-5.png12.4 KB
figure-6.png36.5 KB
figure-7.png24.6 KB
figure-8.png43.48 KB
Published at DZone with permission of its author, Geertjan Wielenga.

Comments

Andreas Mueller replied on Fri, 2009/10/09 - 5:35am

I'm starting to learn Spring RCP and I really want to thank you for your great tutorials.

But I'm having problems to compile the code after introducing the HierarchicalFormModel.

The lines

customerForm = new CustomerForm(FormModelHelper.createChildPageFormModel(ownerFormModel, null));
addressForm = new AddressForm(FormModelHelper.createChildPageFormModel(ownerFormModel, null));

have errors and I have no idea how to change the constructors of CustomerForm and AddressForm to make it compile.

Did I miss the source code for this?

Thanks!

Andreas Mueller replied on Fri, 2009/10/09 - 5:47am

Sorry,
I did not expect it to be so easy.
I changed the constructor of AddressForm to

AddressForm(ValidatingFormModel model) {
    super(model.getParent().getFormObject());
    setId("address");
 }

 and of CustomerForm to

CustomerForm(ValidatingFormModel model) {
    super(model.getParent().getFormObject());
    setId("customer");
  }

and that was it!

Great!

Andreas Mueller replied on Fri, 2009/10/09 - 6:07am

Obviously it is not as easy as I thought.

After making the abovementioned changes in the constructors the code compiles and the app runs, but changes in data are not saved to the model.

Any help available?

Comment viewing options

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