Adding SWT Input Validation the Easy Way

Dating an input mask

Dates have always been a difficult input type to deal with. The easiest way for us developers to deal with them are to use widgets that pop up a calendar from where the user can choose a day, and possibly a time as well. However, this way of dealing with dates are not always a favourite with touch-typing end-users. They prefer some masked field where they only need to fill in the bits of the date that matter. Using the mouse should be restricted as far as possible. Luckily the RCP Toolbox provides a way of specifying input masks, as well as specific implementations of validators and converters for dealing with Dates.

We want to create a field that only takes dates as input, where the date entered must be of the form yyyy-MM-dd HH:mm (e.g 2008-07-19 21:00), and fall in the date range starting at the current time and ending at the end of the year 2008.

	private void createDateField(Composite composite) {
new Label(composite, SWT.NONE).setText("Booking Time:");

final Date endYear = getEndYearDate();
//we create a Date field that takes input of form yyyy-MM-dd HH:mm
//and only allows values from now till the end of the year
final ValidatingField<Date> rangedDateField
= dateValToolkit.createTextField(composite,
new RangedDateFieldValidator(
DateFieldValidator.DATE_TIME_HHMM_DASH,
dateValToolkit.getStringConverter(),
new Date(), endYear),
true,
new Date());
GridData gd = new GridData(SWT.LEFT, SWT.CENTER, false, false);
gd.widthHint = DEFAULT_WIDTH_HINT;
rangedDateField.getControl().setLayoutData(gd);
}

Here we used the dateValToolkit instance to create the field as the contents of the field must be a java.util.Date. We specify an instance of RangedDateFieldValidator (provided by the framework) that makes use of the specified Date input mask pattern DateFieldValidator.DATE_TIME_HHMM_DASH (line 9) to validate the contents of the field. Other patterns are available, or custom ones can also be defined. The DateStringConverter specified when dateValToolkit was constructed will be used to convert from Dates to Strings and vice versa.

In line 11 we specify the valid date range for the field, from the current date and time to the end of the year, and in line 13 we set the initial value of the field to the current time.

Providing quick-fixes

I found that developers using Eclipse RCP to develop their applications like to make the experience for the end-user as good as possible. So we should not stop at just validating input; we must also try and help them quickly fix mistakes, where possible. In this example we can do that by specifying a IQuickFixProvider.

		//add at end of createDateField(..) method
//we add a quickfix that will set it to the current date
rangedDateField.setQuickFixProvider(new IQuickFixProvider<Date>(){

public boolean doQuickFix(ValidatingField<Date> field) {
field.setContents(new Date());
return true;
}

public String getQuickFixMenuText() {
return "Set to current time";
}

public boolean hasQuickFix(Date contents) {
//would typically first check contents to determine if quickfix
//is possible
return true;
}
});

The above is a very simple quick-fixer. It always says it has a quick-fix available (line 17), where a more complex provider will first check the contents of the field to determine if there is a quick-fix. When the user performs the quick-fix, it just sets the contents of the field to the current date and time (line 6).

When the validation framework detects there is an error condition on a field, it will see if there is a IQuickFixProvider available with a quick-fix. If this is the case, it will add the quick-fix option to a context-menu on the decorator icon with the text specified in line 11. All the user then needs to do is right-click on the decorator icon and select the quick-fix to perform.

Validating Combos

A Combo widget would be just the thing to use for capturing the number of persons for the booking. Our requirements say we must limit the number to a maximum of 10 people (and a minimum of 1 goes without saying). Once again we do not want to force the user to use numerous mouse-clicks or keystrokes to select the number, so we do not make the Combo read-only, and rather decide to add validation to it.

	private void createNumberPersonsField(Composite composite) {
new Label(composite, SWT.NONE).setText("Number of persons:");

final ValidatingField<Integer> numberPersonsField
= intValToolkit.createComboField(
composite, new StrictRangedNumberFieldValidator<Integer>(1, 10){
public String getErrorMessage() {
return "Bookings for groups bigger than 10 not allowed";
}

public String getWarningMessage() {
return null;
}

public boolean warningExist(Integer contents) {
return false;
}

},
true,
2,
new Integer[]{1,2,3,4,5,6,7,8,9,10});
GridData gd = new GridData(SWT.LEFT, SWT.CENTER, false, false);
gd.widthHint = DEFAULT_WIDTH_HINT;
numberPersonsField.getControl().setLayoutData(gd);
}

Here we make use of the intValToolkit.createComboField method to create a field containing a Combo widget with contents of type Integer. We specify a StrictRangedNumberFieldValidator (line 6) to ensure that the entered value only consists of digits and falls in the range 1 to 10. No warning conditions are checked. In line 22 we populate the Combo with a list of Integers from 1 to 10, and in line 21 we select a default value of 2. As easy as counting to 5.

And don't forget the telephone number

Freeform telephone number fields are used a lot, but unfortunately end-users can easily make mistakes in such fields. We want to force our user to input the telephone number in a specific form, thus at least preventing the cases where digits are missed. To do this, we make use of the framework's TelephoneNumberValidator. This validator allows telephone number to be entered in either international format (e.g. +44 (55) 555-5555) or in domestic format (e.g. (055) 555-5555).

	private void createTelephoneNumberField(Composite composite) {
new Label(composite, SWT.NONE).setText("Contact Telephone Nr:");

final ValidatingField<String> telephoneField
= strValToolkit.createTextField(
composite,
new TelephoneNumberValidator(true),
true,
"+44 (55) 555-4321");

GridData gd = new GridData(SWT.LEFT, SWT.CENTER, false, false);
gd.widthHint = DEFAULT_WIDTH_HINT;
telephoneField.getControl().setLayoutData(gd);
}

We are using strValToolkit to create the field, since the contents will be managed as a String. Then we specify a TelephoneNumberValidator as the validator in line 7, with the true parameter indicating that we want to use the international format. In line 9 we provide an initial value.

Conclusion

This article describes a very simple example of how to add validation to SWT widgets using the RCP Toolbox. In a real-world application the actual business validations to be done might be more complex, but if this validation framework is used, the UI code related to validation would remain as simple as the code in these examples.

This validation framework really made our development much easier, allowing us to concentrate on the business code. It is very easy to extend the framework with custom validators, converters, quick-fix providers and error handlers that ties into existing business code or other validation code, rules engines etc.

Note that the examples in this article need Eclipse RCP 3.3 or 3.4 as well as RCP Toolbox v1.0.1, created and distributed by www.richclientgui.com.

Subtitle: 
Using RCP Toolbox's Validation framework
Article Type: 
How-to
0
Average: 5 (1 vote)

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