Converting the Way Errors are Shown

By Joe Winchester

o implement visual part validation in VisualAge for Smalltalk, the abstract superclass AbtConverter provides support for converting strings to objects and vice-versa ( ref 1 ). To specify a converter for a text box, the settings page is opened and one is selected from the list of those available. When the converter object is given an invalid input that it is unable to convert correctly, it must indicate this to the user. For a text box, the supplied behavior is for the entry string to change to '** error **'. This can be confusing for users because they must tab back into the field to see the mistake they made. A more desirable behavior might be that when a text control has an invalid input, the background color changes to red and the original invalid input is left in the field. Figure 1 illustrates the supplied as well as our desired behavior.

Figure 1: Transaction Processing. Showing the default behavior in VisualAge to indicate an error has occurred in a text box together with the effect our change will have

In this article, I will describe how converters and text boxes work together to indicate an error has occurred. To implement the desired modification, any code changes should be non-intrusive on supplied class versions to protect from future base changes. Ideally, the change should be system wide without the need for any new custom view parts. This will allow it to be retrofitted instantly to existing applications without having to visit views and swop the class of all text boxes.

Converters and Text Boxes

The class AbtTextView is the text box that appears on the VisualAge palette. Each converter is a subclass of AbtConverter and indicates an error has occurred by specializing the method #primDisplayToObject: anInputString ifError: aOneArgErrorBlock. The actual task of modifying the text box to indicate an error exists is deferred to a third object - a converter manager. The converter manager is an example of the strategy pattern ( ref 2 ) where behavior that otherwise belongs to the text box is placed in a separate object allowing for easy extensibility. This pattern can be leveraged to create a new text box converter manager.

The Converter Manager

The converter manager used by AbtTextView is an instance of AbtTextConverterManager. We will create a subclass to introduce our change.

         AbtTextConverterManager subclass: #JrwTextConverterManager
		instanceVariableNames: ''
		classVariableNames: ''
		poolDictionaries: ''

The method that is responsible for updating the text box's display characteristics is #setWidgetDisplay. Specializing this allows us to make changes to the control's colors. A converter manager can access the control it is being used by with the message #view.

         JrwTextConverterManager>>#setWidgetDisplay

		self isUserInputInError
			ifTrue: [ 
				self view
					backgroundColor: 'red' ;
					foregroundColor: 'white' ]
			ifFalse: [ 
				self view
					backgroundColor: 'white' ;
					foregroundColor: 'black' ].

		super setWidgetDisplay

If there is not an error, we set the colors to black text on a white background. This is the default on some VisualAge operating Systems (e.g. Windows ) but on other Operating Systems it may be different ( e.g. OS/2 3.0 or less is black text on yellow background ). Each image will need to ensure it uses the correct default color arguments for the desired platform.

The next change is that instead of the text box's contents becoming the string '** error **', they remain unchanged. This is now possible because, having made the colors change, the field contents no longer need to be used as the error feedback mechanism to the user.

         JrwTextConverterManager>>#errorString

		^self userInputString

Affecting our change

Having created a new text converter manager class the requirement was that all text boxes use it. Instances of AbtTextView hold their converter manager in an instance variable which is lazy initialized in the method #converterManager. Changing this method is not possible without creating a new version of the class in an existing application and therefore affecting supplied base code. Ideally the change should be introduced via extension to the class.

Every part on a composition editor is instantiated by method #newPart being sent to the class. Specializing this provides the ability to force the converter manager to be an instance of JrwTextConverterManager before the lazy initialization code can be executed.

         AbtTextView class>>#newPart

		^super newPart setJrwConverterManager

An instance side method is added as follows.

         AbtTextView>>#setJrwConverterManager

		converterManager := JrwTextConverterManager forView: self.

Multi line edit control

The multi line edit control AbtMultiLineEditView is a subclass of AbtTextView and will inherit the change to #newPart. This is not desired behavior as multi-line edits have a specific converter manager designed for them. A modification is needed to ensure that they function correctly by making their #newPart method execute the base supplied behavior. We do this by creating a method on AbtTextView like so:

         AbtTextView>>#superNewPart

		^super newPart

In the multi-line edit view, we could execute this message with the receiver as self, but by using super instead, we will indicate to anyone in the future that our intention is to evoke the superclass method from the perspective of our superclass.

         AbtMultiLineEditView class>>newPart

		^super superNewPart

Conclusion

We have satisfied our original requirement to change how errors are shown in text boxes without having to affect any base code or versions of supplied classes. To see the scope of the change, select the menu option addPart from within a composition editor and enter an invalid class name in the text box of the dialog. The field will go red showing that our modification has even affected the base product itself.

I hope you find this change useful and look for other ways to leverage strategy patterns, both in supplied code and your own designs. I welcome all feedback.

Go to the completed code.

References

1 - Programmer's Guide to Building Parts for Fun and Profit Version 3. IBM. SC34-4496-01. Part# 62H8308

2 - Gamma et al. Design Patterns Adison Wesley 1995 ISBN 0-201-63361-2

Enjoy the article? Subscribe to Eye on Objects!

Joe Winchester has been working with VisualAge for Smalltalk since 1994. His area of interest is in client server applications to the IBM AS/400 and believes that building good applications is all about partitioning logic between implementation layers around a solid business model. To this end he eagerly awaits the day when the AS/400 might actually become an object server and Smalltalkers can focus all their energies on real problems, rather than ones created by technology mismatches. He currently works for Computec International Resources in Southern California and can be reached at JoeW@concentric.net or 103 276.233@compuserve.com."

Home Page