• No results found

A practical introduction

N/A
N/A
Protected

Academic year: 2021

Share "A practical introduction"

Copied!
43
0
0

Loading.... (view fulltext now)

Full text

(1)

Spring

Rich

Client

A practical

introduction

(2)

CONTENTS

Introduction ... 5

Overview ... 5

Getting our hands dirty ... 5

The Spring Rich Client framework, a quick dissection ... 8

Anatomy of a rich client application ... 8

Application windows ... 8

Views ... 9

Commands ... 9

Messages and icons ... 11

Other components ... 11

Applications ... 12

Application lifecycle ... 12

Hooking into a lifecycle ... 12

Application ... 12

Example: Adding login functionality to the application ... 12

Other possible uses ... 13

Playing with the statusbar ... 13

Elaborate example: Adding multiple toolbars to the screen ... 14

Commands ... 17

Why the abstraction ... 17

How to create a simple command ... 17

Configure a programmatically created command ... 17

Changing the command to a visual component ... 17

Command internationalization and images ... 18

Grouping commands ... 18

Building a command group in a Spring context ... 18

Getting a Spring configured command in code ... 19

Views ... 20

What is a view ... 20

View descriptors ... 20

(3)

Creating a view descriptor for a view ... 21

Showing the view in the application ... 21

Binding and forms ... 22

Formmodels and valuemodels ... 22

What is a valuemodel ... 22

What is a formmodel ... 22

The default formmodel ... 22

Buffering ... 22 Read-only manipulation ... 23 Validation ... 23 Creating formmodels ... 23 Binding ... 24 What is binding ... 24

How does binding work and what does it do ... 24

Binders ... 24

Binder examples... 24

Creating your own binder ... 24

Forms ... 26 What is a form... 26 Creating a form ... 26 Form builders ... 28 Binder selection ... 28 Internationalization... 29

Adding forms to forms, aka child forms ... 29

Form validation ... 29

Form component interceptors ... 30

Introduction ... 30

Creating your own interceptor ... 30

Configuration ... 30

Built-in interceptors ... 31

Validation ... 34

(4)

Validation choices ... 34

Rule validation ... 34

Using the rule framework ... 34

Constraints ... 34

Validation triggers ... 35

Dependent properties ... 35

Hibernate validator integration ... 35

Valang validation framework integration ... 35

integrating your own validation framework ... 35

Exception handling ... 36

Avoiding try-catch constructs ... 36

Registering an exception handler ... 36

Build-in exception handlers ... 37

Log silently ... 37

Show a message dialog ... 37

Hibernate validation exception handling ... 38

Custom exception handlers ... 38

Using the right exception handler for the right exception ... 38

Simple delegation ... 39

Unwrapping exceptions ... 39

Security ... 41

Integrating security in a GUI application... 41

Spring Security integration ... 41

Turning on security awareness of the GUI ... 41

Securing commands ... 42

Wizards ... 43

Why use wizards ... 43

Creating a wizard ... 43

(5)

INTRODUCTION

OVERVIEW

Rich clients are becoming increasingly more popular nowadays. A quick search through Google on “rich client framework java” return over 200.000 results.

These frameworks can be divided into 2 distinct categories:

The Swing or SWT based frameworks, designed for out-of-browser applications, to be used with technologies like Java Webstart.

The Rich Internet Application (RIA) frameworks, designed for providing a rich client experience within the confines of a web browser (such as Mozilla or Internet Explorer).

Today, RIA frameworks make up the bulk of the rich client frameworks on the market today. Among these you’ll find names like Flex, Google Web Toolkit, Ice Faces, … Their popularity is mainly caused by the ease of deployment: no installation is needed, almost every user already has a Web browser.

For Swing (or SWT) based application, the landscape is a bit different. There are only a handful of complete frameworks on the market:

Eclipse RCP, the platform on which the Eclipse IDE has been built Netbeans RCP, the platform on which the Netbeans IDE has been built

These frameworks are complete platforms, which have proven themselves through their respective IDE’s to showcase their possibilities.

However, these possibilities come at a steep cost. With Eclipse RCP, for example, you’ll be straying of the known Swing path and enter the world of SWT, and both don’t play well together. With Netbeans RCP, you’re mostly confined to the Netbeans IDE to do your development (that is, if you want to develop quickly).

Both platforms can be quite cumbersome and come with a complete baggage package bundled. It’s complexity can be overwhelming for a standard Swing developer and does not always promote effective, good programming style.

The Spring Rich Client framework does not promote itself as a complete platform. Instead, it provides developer a clear and easy way to build enterprise-class applications, without straying too far from the standard, well-known path, whilst ensuring enough flexibility to cope with the difficult issues coupled to the development of enterprise applications. Built on the strong foundations of the Spring Framework, it combines the best practices advocated by the Spring Framework with an component-based abstraction on top of Swing to ease development of Swing rich client applications.

This introduction will try to cover as much ground as possible to let you hit the ground running when starting with a Spring Rich Client application.

GETTING OUR HANDS DIRTY

We’ll start off the introduction with a concise example of a Spring Rich Client application.

As with all Spring applications, Spring beans need to be configured within the container. Currently in Spring Rich Client, only XML based configuration has been tested, although with the new Spring 2.5 release and it’s component-scanning abilities, it should be possible to narrow your configuration down to the essentials. This is something that will possibly be improved in future releases. <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

(6)

<constructor-arg index="0" ref="applicationDescriptor" /> <constructor-arg index="1" ref="lifecycleAdvisor" /> </bean>

<bean id="lifecycleAdvisor"

class="org.springframework.richclient.samples.simple.app.SimpleLifecycleAdvisor"> <property name="windowCommandBarDefinitions"

value="org/springframework/richclient/samples/simple/ui/commands-context.xml" /> <property name="startingPageId" value="initialView" />

<property name="windowCommandManagerBeanName" value="windowCommandManager" /> <property name="menubarBeanName" value="menuBar" />

<property name="toolbarBeanName" value="toolBar" /> </bean>

<bean id="initialView"

class="org.springframework.richclient.application.support.DefaultViewDescriptor">

<property name="viewClass" value="org.springframework.richclient.samples.simple.ui.InitialView" /> <property name="viewProperties">

<map>

<entry key="firstMessage" value="firstMessage.text" /> <entry key="descriptionTextPath" value="org/springframework/richclient/samples/simple/ui/initialViewText.html" /> </map> </property> </bean> <bean id="serviceLocator" class="org.springframework.richclient.application.ApplicationServicesLocator"> <property name="applicationServices" ref="applicationServices" />

</bean> <bean id="applicationServices" class="org.springframework.richclient.application.support.DefaultApplicationServices" /> <bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster" /> <bean id="applicationDescriptor" class="org.springframework.richclient.application.support.DefaultApplicationDescriptor"> <property name="version" value="1.0" />

</bean>

<bean id="applicationObjectConfigurer" depends-on="serviceLocator"

class="org.springframework.richclient.application.config.DefaultApplicationObjectConfigurer"> </bean>

<bean id="lookAndFeelConfigurer"

class="org.springframework.richclient.application.config.JGoodiesLooksConfigurer"> <property name="popupDropShadowEnabled" value="false" />

<property name="theme">

<bean class="com.jgoodies.looks.plastic.theme.ExperienceBlue" /> </property>

</bean>

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>org.springframework.richclient.samples.simple.ui.messages</value> <value>org.springframework.richclient.application.messages</value> </list> </property> </bean>

<bean id="imageResourcesFactory" class="org.springframework.context.support.ResourceMapFactoryBean"> <property name="locations"> <list> <value>classpath:org/springframework/richclient/image/images.properties</value> <value>classpath:org/springframework/richclient/samples/simple/ui/images.properties</value> </list> </property> </bean>

(7)

<bean id="imageSource" class="org.springframework.richclient.image.DefaultImageSource"> <constructor-arg index="0" ref="imageResourcesFactory" />

<property name="brokenImageIndicator" Value="/org/springframework/richclient/images/alert/error_obj.gif" /> </bean> <bean id="formComponentInterceptorFactory" class="org.springframework.richclient.form.builder.support.ChainedInterceptorFactory"> <property name="interceptorFactories"> <list> <bean class="org.springframework.richclient.form.builder.support.ColorValidationInterceptorFactory"> <property name="errorColor" value="255,245,245" />

</bean> <bean class="org.springframework.richclient.form.builder.support.OverlayValidationInterceptorFactory" /> <bean class="org.springframework.richclient.text.TextComponentPopupInterceptorFactory" /> <bean class="org.springframework.richclient.list.ComboBoxAutoCompletionInterceptorFactory" /> </list> </property> </bean> <bean id="rulesSource" class="org.springframework.richclient.samples.simple.domain.SimpleValidationRulesSource" /> <bean id="conversionService" class="org.springframework.richclient.application.DefaultConversionServiceFactoryBean"> <property name="formatterFactory"> <bean class="org.springframework.richclient.samples.simple.ui.SimpleAppFormatterFactory" /> </property> </bean> </beans>

This sample is in fact on of the Spring Rich Client samples included in the sources, some minor adjustments not taken into account. When running the simple project, the output will look something like this:

(8)

THE SPRING RICH CLIENT FRAMEWORK, A QUICK DISSECTION

ANATOMY OF A RICH CLIENT APPLICATION

A Swing rich client in its basic form is quite simple:

An application consists of a application windows, which in most cases contains: The main content pane

One or more navigational structures, such as a menu bar or a toolbar A statusbar to show all sorts of messages to the user

These can be augmented with global search fields, help functions or other components that an application might require.

APPLICATION WINDOWS

An application window is the foundation on which every rich client is built. Without an application window, you don’t have a place to put the components that make up your screens.

In Spring Rich Client, the application window is represented by the ApplicationWindow class. The application window builds the visual window component and shows it to the user.

Application windows are not created individually in Spring Rich Client. A factory pattern, called ApplicationWindowFactory handles instantiation of an application window. This way windows are created in a clear and uniform way throughout the application, without bothering the developer.

In our hands-dirty example, you will not find this factory. Spring Rich Client does not need to have a ApplicationWindowFactory defined. If it is not configured, Spring Rich Client will fall back on a default implementation within the framework, consisting of a simple view area with a menubar, statusbar and toolbar.

You can, however, define your own application factory. To do this, you just need to implement an ApplicationWindowFactory and define a bean in your application context with your new class. Spring Rich Client will pick up the class and use it instead of the default implementation.

The above mechanism, also known as service location, is widely used throughout Spring Rich Client, to facilitate configuration for the developers.

Navigation

Content

(9)

You can for example create an application window factory that leaves out the toolbar, but creates a outlook-like bar or task-pane oriented navigation on the left side instead.

VIEWS

Application windows are containers for views. A view can be seen as an individual window representing a specific state within the application.

Views are the main view area of your applications and will contain the bulk of the user interaction, unless you’ve chosen for a dialog-based approach. You can for example have a flow of views representing a process within your application, or a view containing a table which, when double-clicked, shows a detail of the selected item.

In our first example, a view shows a HTML file together with a message from a resource bundle. Implementing a view is quite simple. When viewing the example view, you’ll see this:

public class InitialView extends AbstractView { // omitted for brevity...

/**

* Create the actual UI control for this view. It will be placed into the window according to the layout of * the page holding this view.

*/

protected JComponent createControl() {

// In this view, we're just going to use standard Swing to place a // few controls.

// The location of the text to display has been set as a Resource in the // property descriptionTextPath. So, use that resource to obtain a URL // and set that as the page for the text pane.

JTextPane textPane = new JTextPane();

JScrollPane spDescription = getComponentFactory().createScrollPane(textPane); try {

textPane.setPage(getDescriptionTextPath().getURL()); }

catch (IOException e) {

throw new RuntimeException("Unable to load description URL", e); }

JLabel lblMessage = getComponentFactory().createLabel(getFirstMessage()); lblMessage.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); JPanel panel = getComponentFactory().createPanel(new BorderLayout()); panel.add(spDescription);

panel.add(lblMessage, BorderLayout.SOUTH); return panel;

} }

AbstractView mandates that you implement the createControl method. This method can deliver any JComponent to show its contents. In most cases, this will be some sort of container or panel.

COMMANDS

The entire menu bar system (and derived navigational structures) are command based. In essence, this means you’ll never make a JMenu or JMenuItem manually again. Ever. Simply put, you’ll create a command, which contains code that needs to be executed (for example, change a view or print the current selected item). Spring Rich Client will handle the creation of the visual components and couple the command behavior to the visual component’s behavior.

(10)

In Spring Rich Client, the command context is a separate context that needs to be defined in the main application context lifecycle.

In our example, the command context looks like this: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="windowCommandManager" class="org.springframework.richclient.application.support.ApplicationWindowCommandManager"> </bean>

<bean id="menuBar" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members"> <list> <ref bean="fileMenu" /> <ref bean="windowMenu" /> <ref bean="helpMenu" /> </list> </property> </bean>

<bean id="toolBar" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members">

<list/> </property> </bean>

<bean id="fileMenu" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members"> <list> <bean class="org.springframework.richclient.command.support.ExitCommand" /> </list> </property> </bean>

<bean id="windowMenu" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members"> <list> <bean class="org.springframework.richclient.command.support.NewWindowCommand" /> <value>separator</value> <bean class="org.springframework.richclient.command.support.ShowViewMenu" /> </list> </property> </bean>

<bean id="helpMenu" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members"> <list> <ref bean="helpContentsCommand" /> <value>separator</value> <ref bean="aboutCommand" /> </list> </property> </bean>

<bean id="helpContentsCommand" class="org.springframework.richclient.command.support.HelpContentsCommand"> <property name="helpSetPath" value="help/simple.hs" />

</bean>

<bean id="aboutCommand" class="org.springframework.richclient.command.support.AboutCommand" /> </beans>

(11)

MESSAGES AND ICONS

Internationalizing your application can be quite an important part of your work, and sometimes also one of the most time-consuming too.

Spring Rich Client supports internationalization through resource bundles defined in the application context (see the messageSource bean). For example, Spring Rich Client provides a mechanism to set the title of your application through the application descriptor. If you set the key applicationDescriptor.title to some value, that value will show up as the title of your application.

Messages are found through MessageSource implementation, for which the resource bundle implementation is perhaps the most widely used.

The same is true for application icons and images in general. The key applicationDescriptor.icon sets the application’s icon. Like messages, the images are found through a ImageSource, which contains property files with the keys and the images that go with the keys, and the location where the images can be found (in the jar for example, or somewhere else).

OTHER COMPONENTS

Spring Rich Client also contains other components to make rich client programming easier. A form framework that handles easy form creation, undo functionality and validation. Exception handling to show visually attractive messages when your application goes down the drain. A wizard framework to make data input for the not-so-tech-savvy users simpler and much more.

(12)

APPLICATIONS

APPLICATION LIFECYCLE

The lifecycle in a Spring Rich Client application is what it says it is. It’s the behavior of the application through the time when it is running. What the application should do at startup, what it needs to show, how it should behave when it’s being closed… these are all aspects of the application lifecycle.

In Spring Rich Client, an ApplicationLifecycleAdvisor manages the lifecycle of the application. In our example, the lifecycle advisor handles the creation of the command context, what view should be showed initially, what command bean should be used for the menu, etc…

HOOKING INTO A LIFECYCLE

In the application lifecycle you can intervene on points within startup, shutdown or other events such as opening a window. These hooks are present in the ApplicationLifecycleAdvisor and can for example be used to ask data needed before startup. You could also stop an application from exiting (by asking a confirmation for example).

APPLICATION

An application in Spring Rich Client is comprised of 2 things: a lifecycle advisor (how it should behave) and a descriptor (what it should do).

The Application class is also the class that starts the actual application: it calls the startup hooks, and shows the initial window and view.

EXAMPLE: ADDING LOGIN FUNCTIONALITY TO THE APPLICATION

Logging into an application is quite common behavior. You’ll probably want to show the login dialog before showing your application window (you might want to personalize the application window based on who has logged in).

In Spring Rich Client, this means after the commands have been created (which is one step before the window gets created and showed). In this example, we’ll let a imaginary LoginHandler class check whether we can login or not. For the record, basic login functionality has been included into Spring Rich Client, but this would bring us out of scope for this example. We’ll discuss the security features later.

Assuming our handler will show a login screen and handle the login logic, we only need to hook it into the application lifecycle advisor:

public class LoginLifecycleAdvisor extends DefaultApplicationLifecycleAdvisor {

private LoginHandler handler;

public void setHandler(final LoginHandler handler) {

this.handler = handler; }

public void onCommandsCreated(final ApplicationWindow window) {

super.onCommandsCreated(window); handler.doLogin();

} }

(13)

As you can see, this is quite easy. Off course you’d want to know when a user is already logged in and just creates a new application window (which also triggers this method), so it doesn’t show this login window again, something like holding a security context within your application.

OTHER POSSIBLE USES

Lifecycle advisor subclassing can also be handy in other aspects. Any Spring Rich Client application knows which lifecycle advisor is used for its execution. You can ask this by calling

Application.instance().getLifecycleAdvisor()

You could for example create an application window factory that delivers different application window applications based on which lifecycle advisor was used:

public class DefaultApplicationWindowFactory implements ApplicationWindowFactory {

private static final Log logger = LogFactory.getLog(DefaultApplicationWindowFactory.class); public ApplicationWindow createApplicationWindow()

{

ApplicationLifecycleAdvisor lifecycleAdvisor = Application.instance().getLifecycleAdvisor(); if (lifecycleAdvisor instanceof OutlookNavigatorApplicationLifecycleAdvisor)

{

return OutlookNavigatorApplicationWindowFactory.create(); }

else if (lifecycleAdvisor instanceof TaskPaneNavigatorApplicationLifecycleAdvisor) {

return TaskPaneNavigatorApplicationWindowFactory.create(); }

return new DefaultApplicationWindow(); }

static class TaskPaneNavigatorApplicationWindowFactory {

public static ApplicationWindow create(boolean onlyOneExpanded) {

... } }

static class OutlookNavigatorApplicationWindowFactory {

public static ApplicationWindow create() {

... } } }

PLAYING WITH THE STATUSBAR

Changing the status bar can be done by calling the statusbar through the lifecycle advisor: Application.instance().getLifecycleAdvisor().getStatusBar();

Again, if you’re creating your own lifecycle advisor, you’re able to override this method and perhaps supply your own status bar implementation.

The standard status bar supports:

Displaying messages, normal messages as well as errors

Containing a progress monitor to track long-running processing (and cancelling them) Your status bar may hold a clock, the current logged in user, the connected server, …

(14)

ELABORATE EXAMPLE: ADDING MULTIPLE TOOLBARS TO THE SCREEN

In this example we’ll add multiple toolbar support in Spring Rich Client.

Management of the standard toolbar is done in three places:

The application lifecycle advisor manages the bean name of the toolbar The application window puts the actual toolbar on screen

The application window configurer manages the visibility of the toolbar For this example, I’ll create the first two (and an factory for the application window).

First, we’re going to extends the default lifecycle advisor with the ability to enter multiple toolbars, while maintaining backwards compatibility.

public class CustomApplicationLifecycleAdvisor extends DefaultApplicationLifecycleAdvisor {

private List toolBarBeanNames;

public void setToolBarBeanNames(List toolBarBeanNames) {

this.toolBarBeanNames = toolBarBeanNames; }

public void setToolbarBeanName(String toolbarBeanName) {

toolBarBeanNames = new ArrayList(); toolBarBeanNames.add(toolbarBeanName); }

public CommandGroup[] getToolBarCommandGroups() {

if(toolBarBeanNames == null || toolBarBeanNames.size() == 0) {

return new CommandGroup[] { new CommandGroup() }; }

else {

CommandGroup[] groups = new CommandGroup[toolBarBeanNames.size()]; for (int i = 0; i < toolBarBeanNames.size(); i++)

{ groups[i] = getCommandGroup(toolBarBeanNames.get(i).toString()); } return groups; } } }

Next, we’re going to create an application window that is able to show the multiple toolbars public class MultipleToolbarApplicationWindow extends DefaultApplicationWindow {

private CommandGroup[] toolBarCommandGroups; protected void init()

{

super.init();

if(getAdvisor() instanceof CustomApplicationLifecycleAdvisor) {

this.toolBarCommandGroups = ((CustomApplicationLifecycleAdvisor) getAdvisor()).getToolBarCommandGroups(); }

else {

this.toolBarCommandGroups = new CommandGroup[] {getAdvisor().getToolBarCommandGroup()}; }

}

(15)

JPanel panel = new JPanel();

panel.setLayout(new GridLayout(toolBarCommandGroups.length, 1)); for (int i = 0; i < toolBarCommandGroups.length; i++)

{

CommandGroup toolBarCommandGroup = toolBarCommandGroups[i]; JComponent toolBar = toolBarCommandGroup.createToolBar();

toolBarCommandGroup.setVisible( getWindowConfigurer().getShowToolBar() ); panel.add(toolBar);

}

return panel; }

}Finally, a factory to create the new application window

public class MultipleToolbarApplicationWindowFactory implements ApplicationWindowFactory {

public ApplicationWindow createApplicationWindow() {

return new MultipleToolbarApplicationWindow(); }

}

Now, to configure the multiple toolbars, here are the beans you need to configure. First the application lifecycle in the main application context

<bean id="lifecycleAdvisor" class="org.springframework.richclient.test.CustomApplicationLifecycleAdvisor"> <property name="windowCommandBarDefinitions" value="ui/commands-context.xml" />

<property name="startingPageId" value="initialView" />

<property name="windowCommandManagerBeanName" value="windowCommandManager" /> <property name="menubarBeanName" value="menuBar" />

<property name="toolBarBeanNames"> <list> <value>toolBar</value> <value>toolBarCopy</value> </list> </property> </bean>

You also need to define the application window factory in your context, so it’ll use that one.

<bean id="appWindowFactory" class="org.springframework.richclient.test.MultipleToolbarApplicationWindowFactory"/> And then the toolbars in the command context

<bean id="toolBar" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members"> <list> <value>newCommand</value> <value>saveCommand</value> <value>printCommand</value> <value>separator</value> <value>propertiesCommand</value> </list> </property> </bean>

<bean id="toolBarCopy" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members"> <list> <value>newCommand</value> <value>saveCommand</value> <value>printCommand</value> <value>separator</value> <value>propertiesCommand</value> </list> </property> </bean>

(16)

That’s all there is to it. I’ve started from a project created with the maven archetype, so you can try it out if you want. The result will be something like this

(17)

COMMANDS

WHY THE ABSTRACTION

Creating an abstraction over an action-based operation is quite logical when you think about it. You have behavior, which can be visually represented in different ways in Swing: a menu, a button or even just a clickable label.

Managing this behavior can be cumbersome if you need to maintain it, especially when certain behavior is to be represented many times and in different ways.

HOW TO CREATE A SIMPLE COMMAND

Let’s make a simple command that shows a messagebox when executed: public class MessageBoxCommand extends ActionCommand

{

protected void doExecuteCommand() {

JOptionPane.showMessageDialog(Application.instance().getActiveWindow().getControl(), "Hello world!"); }

}

Creating a new command can be done by extending ActionCommand. This class mandates that you implement the doExecuteCommand method, which represents the behavior of the command.

CONFIGURE A PROGRAMMATICALLY CREATED COMMAND

Programmatically created commands need to be configured, since Spring Rich Client heavily relies on the Spring container to do the configuring. So when you create command objects in code, you’ll have to do the configuring yourself.

This can be done by calling the command configurer through the service locator in Spring Rich Client: MessageBoxCommand command = new MessageBoxCommand();

commandConfigurer = (CommandConfigurer) ApplicationServicesLocator.services().getService( CommandConfigurer.class);

commandConfigurer.configure(command);

After the command has been configured, it can be used to create components.

CHANGING THE COMMAND TO A VISUAL COMPONENT

After a command is configured, it can be used to create visual components. These can be: Menu items

Buttons

Creating a visual component from a command is easy. Every command has methods to create visual components, with the command’s behavior coupled to it.

For buttons this is

command.createButton(...); For menu items this is

command.createMenuItem(...);

Both methods have various parameter configurations, for more information on which to use in your scenario I refer to the JavaDoc documentation.

(18)

COMMAND INTERNATIONALIZATION AND IMAGES

A button needs a text label, perhaps an icon. We’ll now show you how you can put messages on your commands and link icons to them.

When configuring a command, Spring Rich Client sets a “face descriptor” on the command. This face descriptor manages how the command looks like. A face descriptor is put on the command by utilizing the id of the command. In a Spring configured command, this is the id of the Spring bean. Programmatically created commands need to set their command ids themselves. If you don’t set the command’s id, Spring Rich Client will fallback to the camel-cased class name of the command class. In our example, this will be the case, as we haven’t set the id.

The label of the command, and other text related messages for that matter, is found in the message source configured for the Spring Rich Client application. To find the label of a command, Spring Rich client searches for:

[face descriptor id].label = The label of the command

Similarly, you can put a caption on a command. In the case of a JButton, this will translate itself into a tooltip message: [face descriptor id].caption = The caption of the command

Commands can also have icons coupled to them. Spring Rich Client will look for the message keys and images in the image source configured for the application. To find the icon for a command, Spring Rich client will search for:

[face descriptor id].icon = some_icon.png

GROUPING COMMANDS

Commands can also be groups. Command groups in Spring Rich Clients are composite commands. They can be used to create menus, button stacks and other aggregate components.

Command groups behave similarly to commands (command groups are subclasses of commands), so the configuration works in the same way. They can also be configured in the Spring context, as well as programmatically. However, in the latter case, the same rules as commands apply.

Adding commands to a command group is easy, just call the add method.

Creating a visual component of a command group works the same way as commands. Spring Rich Client provides functionality for:

Menus

Vertical button stacks Horizontal button bars Toolbars

Popup menus

See the JavaDoc documentation for more information on the usage of these creation methods. With some effort, you can even make trees, taskpanes or outlook-bar style grouping.

BUILDING A COMMAND GROUP IN A SPRING CONTEXT

Given our hands-dirty example, we’ll look at a command group configured there:

<bean id="windowMenu" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members">

<list>

<bean class="org.springframework.richclient.command.support.NewWindowCommand" /> <value>separator</value>

(19)

<bean class="org.springframework.richclient.command.support.ShowViewMenu" /> </list>

</property> </bean>

As you can see, creating a command group is straightforward. You create a command group through a factory bean and set the members.

You may have noticed the “separator” value in the members. Spring Rich Client has facilitated adding separators to menus and toolbars by adding this as a shortcut.

Other shortcuts that can be used as values are: glue

Add a glue between commands command:xyz

Add a command with id xyz to the group. You could use this instead of bean references group:abc

Add a command group with id abc to the group. You could use this instead of bean references

Not only commands or shortcuts can be added. Also just ordinary JComponent can be added to command groups. This way you can easily add a textfield to a toolbar.

These command groups can then be referenced for example in the lifecycle advisor to be used as the application’s menu bar, tool bar or other navigation you might have implemented.

GETTING A SPRING CONFIGURED COMMAND IN CODE

Getting a command that you have configured in a Spring context can be done by searching for it based on its id: Application.instance().getActiveWindow().getCommandManager().getCommand(commandId);

This will return the command if it can find a command with that id, or null otherwise. You don’t need to configure this command after you’ve found it, Spring Rich Client has already handled this for you.

(20)

VIEWS

WHAT IS A VIEW

A view is a visual representation of concepts within your application. Everything you show in the main application window is contained within a view.

There can be multiple views on an application page, but only one view is visible at a time. View instances encapsulate the creation of and access to the visual presentation of the underlying control. A view's descriptor, which is effectively a singleton, can be asked to instantiate new instances of a single view for display within an application with multiple windows. In other words, a single view instance is never shared between windows.

VIEW DESCRIPTORS

Every view has a view descriptor. It’s metadata about a view; a view descriptor is effectively a singleton view definition. A descriptor also acts as a factory which produces new instances of a given view when requested, typically by a requesting application page. A view descriptor can also produce a command which launches a view for display on the page within the current active window.

View descriptors produce the page components (in this case views) that will be shown to the users.

CREATING VIEWS

Creating a new view is done through subclassing the AbstractView class. This class mandates you to implement one method: createControl. In our example, the initial view class looks like this:

public class InitialView extends AbstractView {

// omitted for brevity

protected JComponent createControl() {

// In this view, we're just going to use standard Swing to place a // few controls.

// The location of the text to display has been set as a Resource in the // property descriptionTextPath. So, use that resource to obtain a URL // and set that as the page for the text pane.

JTextPane textPane = new JTextPane();

JScrollPane spDescription = getComponentFactory().createScrollPane(textPane); try {

textPane.setPage(getDescriptionTextPath().getURL()); }

catch (IOException e) {

throw new RuntimeException("Unable to load description URL", e); }

JLabel lblMessage = getComponentFactory().createLabel(getFirstMessage()); lblMessage.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); JPanel panel = getComponentFactory().createPanel(new BorderLayout()); panel.add(spDescription);

panel.add(lblMessage, BorderLayout.SOUTH); return panel;

} }

(21)

CREATING A VIEW DESCRIPTOR FOR A VIEW

To show a view on screen, you need to create a view descriptor. For the initial view in the example, the following view descriptor was used:

<bean id="initialView" class="org.springframework.richclient.application.support.DefaultViewDescriptor"> <property name="viewClass" value="org.springframework.richclient.samples.simple.ui.InitialView" /> <property name="viewProperties">

<map>

<entry key="firstMessage" value="firstMessage.text" /> <entry key="descriptionTextPath"

value="org/springframework/richclient/samples/simple/ui/initialViewText.html" /> </map>

</property> </bean>

This is the standard view descriptor definition. You need to give the view class to be used to show the component. Additionally, you can set the properties on an instance of that view by populating the viewProperties map. These properties have to correspond to standard JavaBeans property setters. In this case, the view class has a setFirstMessage and a setDescriptionTextPath method.

SHOWING THE VIEW IN THE APPLICATION

Setting the current view is done by using a ShowViewCommand. This command sets the view of the application window in which the command is located.

To create such a command, use the following bean definition:

<bean id="initialCommand" class="org.springframework.richclient.command.support.ShowViewCommand"> <property name="viewDescriptor" ref=”initialView” />

</bean>

(22)

BINDING AND FORMS

FORMMODELS AND VALUEMODELS

WHAT IS A VALUEMODEL

A valuemodel provides a way for listening for changes on a property. In its simplest form, it is a property listener wrapper around a particular property. Its purpose is to track change, so that secondary functionality such as undo functionality and validation can be provided.

WHAT IS A FORMMODEL

A formmodel is a wrapper around a particular instance of an object. In essence, it is a consisting of valuemodels for the various properties of an object. It handles the overall state of the object.

THE DEFAULT FORMMODEL

The default formmodel in Spring Rich Client handles more than just the overall state of the object by managing its valueobject. It also provides :

Buffering of values, effectively providing undo functionality Dirty tracking

Validation possibilities through validators

Set certain properties of an object to read-only, even if they have setters Creating a formmodel of any given object can be done through this:

MyObject object = new MyObject();

ValidatingFormModel model = new DefaultFormModel(object);

From then on, you can set the values of the object through the valueobject. model.getValueModel(“someProperty”).setValue(“xyz”)

Valuemodels in formmodels are created on-demand. After creating a formmodel on an object, no valuemodels are present until you start calling for them. Spring Rich Client will then make these on-demand.

BUFFERING

Buffering provides the necessary plumbing needed for undo functionality. When changing values of property, a buffered valuemodel will still hold the old values and can revert to these if necessary.

MyObject object = new MyObject(); object.setXyz(“xyz”);

ValidatingFormModel model = new DefaultFormModel(object); model.getValueModel(“xyz”).setValue(“abc”);

// object hasn’t changed, object.getXyz() will return xyz model.commit();

// object has changed, object.getXyz() will return abc

Calling revert() before a commit on a formmodel will return all properties to their original values. Individual valuemodels can be reverted too by calling revert() on them.

(23)

READ-ONLY MANIPULATION

An entire formmodel can be set to be read-only by using the setReadOnly(…) method.

Setting individual properties read-only is a little bit more complicated. Out of the box, Spring Rich Client will inspect the object and determine whether a property is read-only, based on the existence of a setter method for that property.

However, there might be cases where you’d want to deliberately change the read-only behavior of a property, even if it has a setter. The fact whether a property is set as read-only is held by field metadata.

For any given property you can ask the formmodel for the field metadata by calling FieldMetaData meta = model.getFieldMetaData(“xyz”);

Through this field metadata, you can set the read-only property of a property meta.setReadOnly(true);

Obviously, trying to set a property that has no setter to writable will cause an exception when the valuemodels are committed (and the respective setters are called).

VALIDATION

The default form model also contains functionality for validating the enclosed values. The validation is done through Spring Rich Client’s own validation subsystem by utilizing validators. We’ll discuss the details of these validators in detail later.

When a property is changed, the validator will be called to check whether the object is still in a consistent state. If not, the validator will produce validation errors, which then can be showed to the user through various means.

Setting a validator on a formmodel is done through model.setValidator(someValidator)

After that, the validation is automatically turned on. If you needed to, you could turn it off by calling model.setValidating(false)

A model can be validated at any time. A model is aware whether has validation errors, and if so, contains a collection of these. For more information on this, I refer to the JavaDocs on ValidatingFormModel and DefaultFormModel

CREATING FORMMODELS

To create a formmodel, Spring Rich Client has provided a factory class that can create various formmodels. This class is called FormModelHelper.

For example, if you want to create a formmodel of an object, the simplest way would be: FormModelHelper.createFormModel(new SomeObject(), “formModelId”);

With the FormModelHelper, you can create:

Default formmodels (with validation and buffering) Unbuffered formmodels

Child formmodels of existing formmodels

Formmodels, at this time, are object based. To create a formmodel, you need to be able to create an object of the class to be utilized by the formmodel.

(24)

There are implementations on the way to make these class-based, but these are still in development and shaky at best at the moment.

BINDING

WHAT IS BINDING

Binding in Spring Rich Client encompasses the connection between a visual component and the state of a certain property.

HOW DOES BINDING WORK AND WHAT DOES IT DO

Binding is done through a valuemodel. A binding covers only one property at a time, most of the time (a binding could be done by aggregating different valuemodels, but that’s way out of scope for this introduction).

A binding will transfer all property changes to the object behind it, and vice versa. It’s bound to a particular formmodel and property (and therefore, a valuemodel), and is responsible for creating the visual component

BINDERS

Binders a factories for bindings. Generally, for each sort of binding you’ll use in your application, you’ll have one (or more, if there are specific variants of certain bindings that may be occurring).

BINDER EXAMPLES

In Spring Rich Client, a number of binders have been implemented out of the box. TextComponentBinder: can handle text-type variables like strings CheckBoxBinder: can handle Boolean-type variables

ListBinder: can handle lists And many more…

For Java 5+ there is even a binder available for enums, which visually is represented by a combobox.

CREATING YOUR OWN BINDER

Say we want to create a binder for JodaTime’s classes. Java’s standard date classes are bad to work with, so this example may even be somewhat useful.

We start of by creating a the binder. A binder is able to bind any JComponent to a value, so we’ll use SwingX’s JXDatePicker class to visually represent the date.

public class JodaTimeDateTimeBinding extends CustomBinding implements PropertyChangeListener {

private final JXDatePicker datePicker; private final boolean readOnly; private boolean isSettingText = false;

public JodaTimeDateTimeBinding(FormModel model, String path, JXDatePicker datePicker, boolean readOnly) {

super(model, path, DateTime.class); this.datePicker = datePicker; this.readOnly = readOnly; }

@Override

protected void valueModelChanged(Object newValue) {

(25)

setDatePickerValue((DateTime) newValue); readOnlyChanged();

isSettingText = false; }

private void setDatePickerValue(DateTime dateTime) { if (dateTime == null) { datePicker.setDate(null); } else { datePicker.setDate(dateTime.toDate()); } } @Override

protected JComponent doBindControl() {

setDatePickerValue((DateTime) getValue());

datePicker.getEditor().addPropertyChangeListener("value", this); return datePicker;

}

public void propertyChange(PropertyChangeEvent evt) {

if (!isSettingText && !isReadOnly())

controlValueChanged(new DateTime(datePicker.getDate())); }

@Override

protected void readOnlyChanged() {

datePicker.setEditable(isEnabled() && !this.readOnly && !isReadOnly()); }

@Override

protected void enabledChanged() {

datePicker.setEnabled(isEnabled()); readOnlyChanged();

} }

As you can see the class does the 2 way binding. This part @Override

protected void valueModelChanged(Object newValue) { isSettingText = true; setDatePickerValue((DateTime) newValue); readOnlyChanged(); isSettingText = false; }

handles the propagation of changes in the formmodel to the actual component, whereas the property change listener (which in this case is the binder itself, handled by

public void propertyChange(PropertyChangeEvent evt) {

if (!isSettingText && !isReadOnly())

controlValueChanged(new DateTime(datePicker.getDate())); }

The isSettingText flag is there to prevent cyclic calls (formmodel changes component, which change the formmodel, which changes, …).

(26)

Binding the control to the value is done through the doBindControl() method. This method is called to wire the component to the binding and prepares all the plumbing to make the binding work.

Creating the binder is most of the time the easiest job of the two.

public class JodaTimeDateTimeBinder extends org.springframework.richclient.form.binding.support.AbstractBinder {

private boolean defaultsSet = false; private boolean readOnly = false; public JodaTimeDateTimeBinder() {

super(DateTime.class); }

public void setReadOnly(boolean readOnly) {

this.readOnly = readOnly; }

@SuppressWarnings("unchecked")

protected JComponent createControl(Map context) {

JXDatePicker datePicker = new JXDatePicker(); datePicker.setEditor(new DateTextField()); return datePicker;

}

@SuppressWarnings("unchecked")

protected Binding doBind(JComponent control, FormModel formModel, String formPropertyPath, Map context) {

if (!defaultsSet) {

Map<Object, Object> defaults = UIManager.getDefaults(); defaults.put("JXDatePicker.longFormat", "EEE dd/MM/yyyy"); defaults.put("JXDatePicker.mediumFormat", "dd/MM/yyyy"); defaults.put("JXDatePicker.shortFormat", "dd/MM"); defaultsSet = true;

}

return new JodaTimeDateTimeBinding(formModel, formPropertyPath, ((JXDatePicker) control), this.readOnly); }

}

The createControl() method creates the control that is to be used in bindings. Every time a binding is done, a new control will be created through this method.

The actual binding is done through the doBind(). It will create a binding, do some specific behavior in some case (here we’re manipulating some UI properties to alter the JXDatePicker’s appearance.

FORMS

Now that we have covered the formmodels and the binding, we can now cover the combination of the both.

WHAT IS A FORM

Whereas a binding covers a single property, a form covers an entire object. It can contain many bindings, backed up by a formmodel that wrapped the form’s object.

CREATING A FORM

Forms are created for a specific purpose and specific objects. Say we have the following object: public class TestObject

(27)

{

private String field1; private String field2; public String getField1() {

return field1; }

public void setField1(String field1) {

this.field1 = field1; }

public String getField2() {

return field2; }

public void setField2(String field2) {

this.field2 = field2; }

}

If we want to make a form for this, we’ll might be using something like this public class TestForm extends AbstractForm

{

public TestForm() {

super(FormModelHelper.createFormModel(new TestObject(), "testForm")); }

protected JComponent createFormControl() {

JPanel content = new JPanel();

content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); content.setLayout(new FormLayout( new ColumnSpec[] { FormFactory.DEFAULT_COLSPEC, FormFactory.LABEL_COMPONENT_GAP_COLSPEC, FormFactory.DEFAULT_COLSPEC }, new RowSpec[] { FormFactory.DEFAULT_ROWSPEC, FormFactory.LINE_GAP_ROWSPEC, FormFactory.DEFAULT_ROWSPEC } ));

TextComponentBinder binder = new TextComponentBinder(); Map map = new HashMap();

content.add(new JLabel("Field 1"), new CellConstraints(1, 1));

content.add(binder.bind(getFormModel(), "field1", map).getControl(), new CellConstraints(3, 1)); content.add(new JLabel("Field 2"), new CellConstraints(1, 3));

content.add(binder.bind(getFormModel(), "field2", map).getControl(), new CellConstraints(3, 3)); return content;

} }

This will result in a panel with 2 text fields next to each other, that represent the 2 fields of the object. This form can then be used to show in a view or a dialog. Currently, there is no default view descriptor for forms, since these are mostly contained in views in which they only make up a part of the screen (for example, in combination with a table).

(28)

FORM BUILDERS

As shown in the example above, forms can be created by using binders and bindings directly. However, for more elaborate form, this method is not really usable (or readable for that matter).

To tackle this problem, Spring Rich Client has created form builders. Form builders make form creation a lot easier by providing simple addition of properties, labels and other component to forms. Form builders use the binding factory facilities built into Spring Rich Client.

The binding factory system can set default binders for certain types, so that you don’t need to worry how something should look. It can also provide aliases for binders defined in the context, so that you can use these swiftly.

Building the same form with a form builder would result in public class TestForm extends AbstractForm

{

public TestForm() {

super(FormModelHelper.createFormModel(new TestObject(), "testForm")); }

protected JComponent createFormControl() {

TableFormBuilder builder = new TableFormBuilder(getBindingFactory()); builder.add("field1");

builder.row();

builder.add("field2");

JPanel panel = (JPanel) builder.getForm();

panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); return panel;

} }

Much simpler and easy to read, isn’t it?

An additional advantage in using a form builder is that internationalized labels are supported out of the box. In the form builder example no labels are coded, but the form builder will add them automagically.

Currently there is a form builder that works with JGoodies FormLayout named TableFormBuilder, and there is also one that supports Java’s GridbagLayout. You can always create your own form builder by extending AbstractFormBuilder.

BINDER SELECTION

Spring Rich Client has a mechanism to automatically choose binders based on property names, types or even the used Swing components. This is done through BinderSelectionStrategy implementations.

The standard implementation is the SwingBinderSelectionStrategy, which already has support for String and Boolean type fields. If you want to expand this automatical binder selection, you can configure your own BinderSelectionStrategy in your Spring context (which will be picked up by the service locator), and set for example the bindersForPropertyTypes map property. This map matches property types to specific binders that you also have configured in your Spring context.

For example, if you want to change support String, Boolean and Date fields, you can define your selection strategy like this <bean id="binderSelectionStrategy"

class="org.springframework.richclient.form.binding.swing.SwingBinderSelectionStrategy"> <property name="bindersForPropertyTypes" ref="propertyTypeBinders"/>

(29)

<util:map id="propertyTypeBinders" key-type="java.lang.Class"> <entry key="java.lang.String" value-ref="stringBinder"/> <entry key="java.util.Date" value-ref="dateBinder"/> <entry key="java.lang.Boolean" value-ref="booleanBinder"/> </util:map>

INTERNATIONALIZATION

Remember the id you can give to your formmodel? This is the part where it’s needed. Spring Rich Client will use the formmodel’s is to create the key it’ll use to look up the label’s text.

Say your formmodel is named “personForm” and you have a field called “firstName”. Then in your message bundle you’ll have to provide something like this:

personForm.firstName.label = First name

If no value is found for a key, Spring Rich Client will show the key instead. This way you can easily spot missing keys (and don’t need to guess how they are named).

ADDING FORMS TO FORMS, AKA CHILD FORMS

Forms are just plain components. They can be added to forms as any other component. However, when creating a child form, you need to make sure the formmodel of the child form is also a child of the formmodel of that form’s parent. That way, events are carried over correctly.

Child forms can also be added by using the addChildForm(…) method on a form. This way, the formmodels between the two are automatically linked. Bear in mind though, a setFormObject on a parent form does not cause a setFormObject on its children. This is something you’ll have to handle yourself.

FORM VALIDATION

Form validation is done through the validation subsystem by validating the formmodel (and underlying valuemodels). Form component interceptors such as the OverlayValidationInterceptorFactory can then show the validation errors to the user. For more information on interceptor, read the next part.

(30)

FORM COMPONENT INTERCEPTORS

INTRODUCTION

Form component interceptors provide a way to intercept and add extra functionality to input components on a form.

The application context specifies the list of interceptors to attach to controls constructed by the platform. This allows for a declarative model for specifying "additional" functionality to be added to various components.

Examples are interceptors to overlay validation error images and background color changes, provide popup menus in text fields, and autocompletion (as you type) for comboboxes.

CREATING YOUR OWN INTERCEPTOR

To create your own FormComponentInterceptor, you have to provide both a FormComponentInterceptor and a

FormComponentInterceptorFactory implementation. public interface FormComponentInterceptor {

public void processLabel(String propertyName, JComponent label);

public void processComponent(String propertyName, JComponent component); }

CONFIGURATION

The configuration of the interceptors in the application context is done by defining the

FormComponentInterceptorFactory. Sample configuration: <bean id="formComponentInterceptorFactory" class="org.springframework.richclient.form.builder.support.ChainedInterceptorFactory"> <property name="interceptorFactories"> <list> <bean class="org.springframework.richclient.form.builder.support.ColorValidationInterceptorFactory"> <property name="errorColor" value="255,200,200"/>

</bean> <bean class="org.springframework.richclient.form.builder.support.OverlayValidationInterceptorFactory"/> <bean class="org.springframework.richclient.form.builder.support.DirtyIndicatorInterceptorFactory"/> <bean class="org.springframework.richclient.text.TextComponentPopupInterceptorFactory"/> <bean class="org.springframework.richclient.list.ComboBoxAutoCompletionInterceptorFactory"/> </list> </property> </bean>

(31)

BUILT-IN INTERCEPTORS

There are a number of built-in interceptors provided with the framework. We’ll quickly explain them.

ERROR OVERLAY IMAGE

Shows an error image in the lower left corner of the component if the contents of the component is invalid. The image also has a tooltip showing the validation message.

This class has been specifically made to work with Spring Rich Client’s validation framework and will show the errors coming from that framework

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.OverlayValidationInterceptorFactory" />

ERROR BACKGROUND COLOR

Changes the background color of the form component when an invalid value is entered. Properties:

errorColor: the background color

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.ColorValidationInterceptorFactory"> <property name="errorColor" value="255,200,200"/>

</bean>

TEXT EDITING POPUP (COPY, PASTE, UNDO,...)

Adds more advanced text editing functionality to text components. It adds a popup menu with "undo/redo/cut/copy/paste/select all" items. It also adds the standard keyboard accelerators for these commands to the component.

To configure this interceptor, you need to use this interceptor factory:

(32)

COMBOBOX AUTOCOMPLETION

Adds auto completion to a combobox.

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.ComboBoxAutoCompletionInterceptorFactory" />

OVERLAY IMAGE INDICATING A CHANGED VALUE

Shows an image in the top left corner of the component if the contents of the component has been changed by the user. The image also has a tooltip showing the original value. To the right of the image is a small revert button. Pushing this button restores the original value in the component.

Properties:

includedFormModelIds: list of form models that should display the Dirty Indicator. Only one of includedFormModelIds or excludedFormModelIds can be specified. excludedFormModelIds: list of form models that should not display the Dirty Indicator Only one of includedFormModelIds or excludedFormModelIds can be specified. To configure this interceptor, you need to use this interceptor factory:

<!-- The login form will not show the Dirty Indicator -->

<bean class="org.springframework.richclient.form.builder.support.DirtyIndicatorInterceptorFactory"> <property name="excludedFormModelIds"> <list> <value>loginForm</value> </list> </property> </bean>

SELECT ALL TEXT

Selects all the text in text fields and spinners when they receive focus.

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.SelectAllInterceptorFactory" />

SETTING THE CARET TO THE BEGINNING OF THE FIELD

If the text is set in a text component, the caret position is set to the end of the text.

This means the beginning of the text will not be visible if the text is too long to fit in the text component. This FormComponentInterceptor "fixes" this behavior, and sets the caret to position 0.

(33)

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.TextCaretFormComponentInterceptorFactory" />

SHOWING A TOOLTIP

If a form property has a caption defined in the messages.properties file it will be used as the tooltip for the form component. Properties:

processComponent: default is true, determines whether the tooltip of the component is set. processLabel: default is true, determines whether the tooltip of the label is set.

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.ToolTipInterceptorFactory" />

CHANGING THE RENDERING OF A CHECKBOX

Allows customization on how a CheckBox form property is rendered. Properties:

showLabel: default is true, determines whether the label will be shown.

showText: default is false, determines whether the label text will be used as text for the checkbox itself. textKey: default is "text", the key used to fetch the text to show.

To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.CheckBoxFormComponentInterceptorFactory" />

SHOW THE CAPTION OF THE CURRENTLY FOCUSED COMPONENT IN THE STATUSBAR

Shows the caption of the form component in the statusbar when the component is focused. To configure this interceptor, you need to use this interceptor factory:

<bean class="org.springframework.richclient.form.builder.support.ShowCaptionInStatusBarInterceptorFactory" />

SHOW THE DESCRIPTION OF THE CURRENTLY FOCUSED COMPONENT IN THE STATUSBAR

Shows the description of the form component in the statusbar when the component is focused. To configure this interceptor, you need to use this interceptor factory:

(34)

VALIDATION

WHY VALIDATION

Users make mistakes. They won’t admit it, but they do. As GUI developers, our task is to make sure that their mistakes don’t crash or cripple our system. Input validation can help a great deal with this. Spring Rich Client supports validators for various input. These are all subclasses of RichValidator.

VALIDATION CHOICES

Spring Rich Client has multiple validation strategies: The built-in rules system

Using Hibernate Validator

Using Spring Modules’ Valang validation framework A combination of any of the above

RULE VALIDATION

USING THE RULE FRAMEWORK

Spring Rich Client has created their own validation framework, which is rule based. A change to a value it put through a number of checks, which are contained within a rule, and results in a success or a validation error.

The FormModelHelper can create formmodel with rule validation by providing a RulesSource in one of its factory methods. A rule source contains different rules for a certain object type. If, for example, we want to validate that the field1 property of the TestObject class is never empty, we can create a rulesource like this:

DefaultRulesSource source = new DefaultRulesSource(); Rules rules = new Rules(TestObject.class);

Constraints c = new Constraints(); rules.add(c.required("field1")); source.addRules(rules);

CONSTRAINTS

Constraints contain the actual logic that checks the values.

The Constraints class contains a lot of predefined constraints. Among these you can find Maximum length of string

Maximum value Not null Minimum value …

Creating your own constraint is done by implementing the Constraint interface, which consists of one method public interface Constraint

{

boolean test(Object argument); }

This constraint will test any object. Most of the time, we’ll want to split up functionality to check individual properties, so that we can reuse this logic elsewhere. Remember, the constraints you add to a rules source always need to be coupled to a property.

References

Related documents

think you are measuring. National Laboratory for Tourism &amp; eCommerce, Temple University.. Challenges with computational social science. Nature of

About 85% of the reforestation areas in West and North Norway consist of Norway spruce plantations (c. 250,000 ha), about 45,000 ha Sitka spruce (includ- ing a minor part in

daggers were on the table next to their beds. I took the daggers and walked to the king’s bed. And then I killed the king! Later I kil led his servants, too. Everyone is going to

Hillier, Matthew and Sutton, Louise and James, Lewis and Mojtahedi, Dara and Keay, Nicola and Hind, Karen (2019) 'High prevalence and magnitude of rapid weight loss in mixed

The current study examines cumulative and contextual effects of reducing environments, as well as non-contextual frequency measures, on the reduction of word- initial

When the temperature is higher than 200 K, with the temperature increasing, dislocation slip is the dominant deformation mechanism for polycrystalline nanowires,

This assumption is incorrect (as these categories are purely anecdotal) and, as a result, in studies that utilize these existing generational categorizations,

After you have registered with your Learning Partner, you will receive a login email no later than two days before the submission period opens – this will provide you with the