Sw4   >   Windows   >   Field Handling

Field Handling

The StudioWorks field handling classes provides you with the following benefits:

  1. The entry field which has the focus is highlighted with a colored border.

    Blue border for normal fields. Red border for lookup fields. Dashed border for uppercase only fields.

    The colored border makes it easier for the user to spot the current field, and hints to them if it is a lookup type ahead field. If the field is uppercase the dashed border hints to the user that they do not need to press the shift or caps lock key.
  2. Decorator types can be assigned to fields.
    click = cream color
    displayonly = grey color
    notes = blue color
  3. The decorator types can be mode sensitive.
    For example a clickedit decorator type will be:

    normal in new mode
    click in edit mode
    displayonly in view mode

    All fields are displayonly in view mode.
  4. The displayonly decorator type allows users to select text and copy it to the clipboard, but rejects any keystrokes which would modify the text.
  5. For windows where space is limited a notes decorator type can be used for entry fields that have lengthy text. The entry field in the window can be the size of a normal entry field. When the user clicks on the blue color notes field, the notes field handler opens a multi-line field/window for the user to edit or view the lengthy text. When the user leaves the large multi-line field the column in the data list is updated and the multi-line field/window is closed.
  6. Lookup fields which automatically find and display a list of matching lookup records as the user types in the lookup field. After the user selects a lookup record the lookup field handler automatically sets the foreign key and updates the related fields in the window.
  7. The notes and lookup fields work with complex grids. This is a big benefit!
  8. The decorator types are set in the SQL meta-data allowing the field handling and decoration to be controlled by the schema or query class which is being used for a particular window instance. You can override the schema class decorator type for a field in a query class that is used for a particular window.

FieldDecoratorTypes_new.gif

FieldDecoratorTypes_new.gif

Note

A new field handler structure and classes was introduced in the 2008-03 release of StudioWorks. The new field handling structure and classes make it easier for StudioWorks developers to override and customize field handling. The field handler classes are located in the Field Handling folder of swGui4.

Note

StartNewApp has a Field Handler Demo module with simple windows that demonstrate various aspects of the field handler. You can shift+click on buttons in the demo windows to look at the code behind the window and step through the field handler code.

Meta-Data Decorator Types

The easiest way to control field handling is by setting the Decorator Type under the Display Properties section of the SQL Meta-Data Editor.

The decorator types supported in StudioWorks are:

  1. normal (default) - white background, always enabled.
    If the decorator type is not set it defaults to normal.
  2. displayonly - grey background and disabled. User can click on the field to select and copy text to clipboard, but can not enter, delete, or paste text into the field. All fields default to displayonly in view mode.
  3. displayonlyedit - uses displayonly properties in edit mode. Default properties in new mode.
  4. click - cream forecolor and disabled. User can click on the field to enable the field.
  5. clickedit - uses click properties in edit mode. Default properties in new mode.
  6. clicknew - uses click properties in new mode. Other modes use displayonly.
  7. notes - blue forecolor and disabled. Pops opens a multi-line entry field in a frameless window for editing if the user clicks on the field. The frameless window is positioned over the notes field and looks and behaves like a simple multi-line entry field. The use can escape, tab, enter, or click elsewhere to close the frameless window.
  8. notesdisplay - has the same behavior as the notes field except the multi-line entry field in the frameless window is set to displayonly.
Note

The decorator type values can each field are listed in the decoratortype column of the SQL lists columns list. You can get the columns list from a StudioWorks SQL defined list from the $:ColsList property method.

Decorator Types List

The FieldHandlersFactory_Task provides oFieldHandlerController with a $:TypesList. The list has 4 columns:

  1. decoratortype - The SQL Meta-Data specified decorator types previously mentioned.
  2. handler_new - The field handler to be used in new mode.
  3. handler_edit - The field handler to be used in edit mode.
  4. handler_view - The field handler to be used in view mode.

For example a clickedit decorator type would have the following values:

  1. decoratortype = clickedit
  2. handler_new = normal
  3. handler_edit = click
  4. handler_view = displayonly
oFieldHandlerController uses the types list to set the handler_[mode] columns in its field properties list.

Field Properties List

The field properties list is a list of all the fields in a window instance which the field handler could be involved with.

The field properties list is defined from sFieldHandlerProperties_listdef. It has the following columns:

  1. objident - the $ident property of the field.
  2. objname - the $name property of the field
  3. rownum - Default zero (0). Greater than zero is used for complex grid exceptions.
  4. decoratortype - the decorator type specified by the meta-data.
  5. handler_new, handler_edit, handler_view - one column for each mode specifying the field handler to be used for the mode.
  6. lookup - true if the field's schema class is related to the base schema via a foreign key.

    Following the lookup column is a series of columns for all lookup related properties (lookuprefs, lookupsqlclassname, lookuprefsgroup, lookuprefssubgroup, lookupmandatory, lookupcaninsert, lookupstartchar, lookupwheretext, lookupcolname, lookupservertablename, lookupmaincolname, lookupsetcolslist, lookuplistfieldcalc, lookupcontains, lookupisnumber)

A window class can include a field properties list with the $initialize message it sends to oFieldHandlerController. To improve performance oConcretizer builds and stores a field properties list in the $userinfo property of a runtimized window class when it creates it.

If the field properties list is not supplied, oFieldHandlerController builds a list on-the-fly by sending a $retFieldPropertiesList message to the oFieldHandlerPropertiesList object.

If the data list of a window is based on a query class that joins multiple tables any field which is not part of the base schema of the query class is automatically assigned a decoratortype as follows:

  1. lookup - If the base schema has a foriegn key which references a column in the field's table. A parent record.
  2. displayonly - If the base schema does not have a foreign key referencing a column in the field's table. The table could be a grandparent, great-great grand parent...

When oFieldHandlerController receives an $event message, is searches the field properties list for a matching objident, then based on the current mode, it sends a message to the appropriate field handler object.

You can change the decoratortype for any field, add new fields, or add complex grid exceptions to the field properties list, using the $addsetFieldDecoratorType method of oFieldHandlerController.

You can modify the field properties list by getting it from the field handler controller, modifying the list, and then setting it back to the controller.

See the section on Overriding Field Handling for more details.

Field Handler Modes

The current mode affects which field handler object is called to handle a field's events. The handler_new, handler_edit, handler_view columns in the properties list specify which field handler object to use for the appropriate mode.

For a clickedit decorator type the handler_[mode] column values would be as follows:

  1. handler_new = normal
  2. handler_edit = click
  3. handler_view = displayonly

Each time the mode is set in the window class, the window must send a $setMode(pMode) message to the oFieldHandlerController.

If the value of pMode is different than the controller's current mode, the controller sets its internal iMode state to the specified mode, and then loops through the field properties list sending a $setField message to the appropriate field handler specified in the handler_[iMode] column.

When an $event message is passed to oFieldHandlerController it searches for the current field in the field properties list, and then forwards the message to the field handler type specified in the appropriate handler_[iMode] column.

With the clickedit decorator type example above the oFieldHandlerController will send messages to the following field handlers for the specified modes:

  1. new mode - send messages to oFieldHandler_normal
  2. edit mode - send messages to oFieldHandler_click
  3. view mode - send messages to oFieldHandler_displayonly

Field Handler Objects

The oFieldHandlerController delegates most of the field handling to field handler objects.

The field handler object naming syntax is: oFieldHandler_type

The following field handler objects can be found in swGui4.

The lookup and lookupclick field handlers are assigned to lookup fields by StudioWorks when the field properties list is built.

Field Decorator Objects

The field handler objects delegate field decoration to field decorator objects.

The field decorator object naming syntax is: oFieldDecorator_type

The following field decorator objects can be found in swGui4.

Normally a field is decorated by setting its $fieldstyle property. There are a series of StudioWorks field styles which you must have in the #STYLES class of your library in order for field decoration to work. The StudioWorks field styles are:

Tip

You can use the StudioTips SyncStyles utilities to copy the StudioWorks field styles from swGui4 to your library's #STYLES class.

Complex grids add a wrinkle to field decoration because you can not set the $fieldstyle for an individual cell. For complex grids we have to set each property separately to change the field decoration of each field. The StudioWorks field styles for complex grids are:

The oFieldDecorator_type objects will use the inset border or no border style based on which $fieldstyle the field is set to in the complex grid.

Field Handlers Factory

The FieldHandlersFactory_Task is a task class which is used to reduce memory use and improve performance. The StudioWorks field handling structure is based on the flyweight design pattern.

When oFieldHandlerController is initialized it checks for a task instance of the FieldHandlersFactory_Task. If found it uses the existing instance. If not found, it opens an instance.

The FieldHandlersFactory_Task finds and creates a single instance of each oFieldHandler_type object class and a single instance of each oFieldDecorator_type object class. Object reference datatypes are used to ensure that just one instance of each of these object classes is created. The object reference to each of these instances are stored in an iHandlersRow and an iDecoratorsRow in the FieldHandlersFactory_Task.

The handler and decorator type suffix is used for the row column name.

iHandlersRow would have columns named: click, displayonly, lookup, notes, notesdisplay

iDecoratorsRow would have columns named: click, displayonly, hasfocus, normal, notes

When oFieldHandlerController is initialized it gets these rows from the FieldHandlersFactory_Task by sending it a $:HandlersRow message and a $:DecoratorsRow message. Each column in the row has a pointer to the single instance of the respective handler or decorator. All instances of oFieldHandlerController point to the exact same instance of each handler and decorator.

Developers can create their own oFieldHandler_type and oFieldDecorator_type classes in their main library. Handlers and decorators found in the main library take priority over ones by the same name in swGui4. As long as your handler has the same methods and parameters at those found in swGui4 you are free to tweak your handler or decorator code to suit your application's needs.

Warning

One potential design flaw in the FieldHandlersFactory_Task is that a single task instance of the factory is used for all StudioWorks applications open under the same instance of Omnis Studio. When a second StudioWorks app is opened it finds and uses the existing task instance of the factory. If the second StudioWorks app has custom field handlers or decorators they will be ignored. The solution is to have each StudioWorks app open its own task instance of the factory. This is relatively easy to implement, but it uses more memory, and will likely never be an issue for 99% of StudioWorks developers.

If you add custom handlers or decorators you need to quit Omnis Studio and reopen it in order to destroy the factory task instance. Just closing and reopening the StudioWorks app won't destroy the factory task instance.

Field Handling with Complex Grids

StudioWorks normally decorates fields by changing the $fieldstyle of the field to the appropriate type.

For a click field, the $fieldstyle is set to swFieldNoFocus_click, until the user clicks on the field as which time the $fieldstyle is set to swFieldFocus

Complex grids increase the complexity of field handling because you can not set the $fieldstyle for individual cells of a complex grid. To decorate a field in a cell of complex grid we must set each field property individually, and we must specify the row number in the complex grid for each property we set.

The oFieldHandler_type and oFieldDecorator_type series objects check if the specified field is inside a complex grid and if so, executes complex grid friendly handler and decorator code.

One advantage of the StudioWorks field handling structure is that lookups and notes decorator type fields automatically work in complex grids. This is a big benefit!

FieldHandlerComplexGrid.gif

Field Handling Sequence of Events

The field handler classes are located in the Field Handling folder of swGui4.

The oFieldHandlerController object is instantiated by the ivar ifld in the window instance. There will be one instance of oFieldHandlerController for each window (subwindow) instance.

When the window is instantiated the following sequence of events relating to field handling normally takes place:

  1. Omnis Studio sends a $construct message to the window instance.
  2. The $construct method of the window class sends an $initialize message to oFieldHandlerController passing in a reference of the window instance, the window's main data list, and optionally the field properties list.

    Note

    Runtimized window have the field properties list stored in the $userinfo property of the runtimized window class.

  3. If a field properties list is not passed from the window to the controller, the controller builds the field properties list by sending a $retFieldPropertiesList message to the oFieldHandlerPropertiesList object class.
  4. The window instance receives a $_setMode message from StudioWorks.
  5. The $_setMode methods sends a $setMode(pMode) message to oFieldHandlerController. If pMode is different that the current mode state of oFieldHandlerController it loops through the field properties list and decorates all of the fields for the specified mode.

    Field decoration is accomplished by sending a $setField message to the appropriate oFieldHandler_type object class which then delegates decoration to the appropriate oFieldDecorator_type object class.
  6. The window instance receives a $setCurrField message from StudioWorks.
  7. The $setCurrField methods sends a $retFirstEnabledEntryFieldName message to the field handler controller which then searches the field properties list for the first enabled field and returns the field name to the sender, who then set the current field by issuing a Queue set current field {FieldName}.
  8. The currrent field receives an $event message from Omnis Studio with the pEventCode = evBefore.
  9. The field allows the event to pass up to the window's $control method.

    Note

    Note: If you have an On evBefore in the field $event method, the event will not pass to the window's $control method. If you want StudioWorks field handling for the field you must either remove the On evBefore or end it with Quit event handler (Pass to next handler). The same goes for evAfter, evClick, and evKey. For evKey the field or library's $keyevents property must be set to kTrue.

  10. The $control method of the window class sends an $event message to oFieldHandlerController which then searches for the field in the field properties list and delegates the $event message to the appropriate oFieldHandler_type object class for the current mode. The delegate field handler does the appropriate event handling and then delegates field decoration to the appropriate oFieldDecorator_type object class.
  11. If the field is a lookup type field, oFieldHandlerController then sends a $control message to oFieldHandlerLookupTypeAhead which takes care of all the lookup related work.
  12. When the user is in the field each keystroke generates an evKey $event message which is passed on to oFieldHandlerController. For displayonly fields the handler discard keystrokes which would change the contents. For lookup fields oFieldHandlerLookupTypeAhead use the keystrokes to find and display matching lookup records.
  13. When the user leaves the field Omnis Studio sends an evAfter $event message to the field. The field handler controller forwards the $event message to the appropriate field handler which then reverts the field to its no focus state.

Overrriding Field Handling

Overriding field handling and decorating is relatively easy. Knowing the sequence of events, you can decide where to best intercept and modify the field handling.

  1. Meta-Data - If possible, control field handling and decorating in the meta-data. You set the decoratortype for a column in the schema class. If you want a different decoratortype for a particular window, create a query class for the window, and in the meta-data editor for the query class right-click and Override the schema class decoratortype and set it to the whatever decorator you want for that query/window.
  2. $event method - You can intercept any event in the $event method of the field. You can trap any event with the On series of commands (On evBefore, On evAfter, On evKey, On evClick) The event you trap will not get to oFieldHandlerController unless you end with Quit event handler (Pass to next handler). This gives you full control over event handling.

    You can manually decorate a field from the $event method by sending a $decorateField(prField,pDecoratortype) message to oFieldHandlerController. This only decorates the field, it does not affect the field handling.
  3. Field Properties List - You can modify the field properties list which oFieldHandlerController uses.

    To add a field or set an existing field in the field properties list you can send a $addsetFieldDecoratorType message to the field handler controller. This method is particularly useful if you want to set special complex grid exceptions.

    ; Set the OrderID field in row 2 of the complex grid to 'displayonly'
    ; (prField,pDecoratorType,pRowNum_opt)
    Do ioFieldHandlerController.$addsetFieldDecoratorType($cinst.$objs.OrderID,'displayonly',2)

    ; Add a displayonly Status field.
    ; (prField,pDecoratorType,pRowNum_opt)
    Do ioFieldHandlerController.$addsetFieldDecoratorType($cinst.$objs.Status,'displayonly')



    To modify the entire field properties list you can get it from the field handler controller by sending a $:FieldPropertiesList message to the controller, modify the list, then assign it back to the controller using the $:FieldPropertiesList.$assign method.

    ; Get the field properties list and add a special 'approved' mode.
    Do ioFieldHandlerController.$:FieldPropertiesList() Returns List
    Do List.$cols.$add('handler_approved',kCharacter,kSimplechar,50)

    ; Set the handler to click for any displayonly fields.
    Do List.$sendall($ref.handler_approved.$assign('click'),List.handler_edit='displayonly')

    ; Assign the modified field properties list back to the field handler controller.
    Do ioFieldHandlerController.$:FieldPropertiesList.$assign(List)

  4. Field Handler and Decorator Object Classes - You can copy or subclass any of the StudioWorks field handler and decorator object classes to your main library and override the code in those objects in your main library. When the FieldHandlersFactory_Task is instantiated it looks for field handlers and decorators in your main library and uses yours ahead of the ones by the same name in swGui4.

You can also create additional field handlers and decorators. As long as you following the naming convention syntax for field handlers and decorators, the FieldHandlersFactory_Task will find and add them to the handlers row and the decorators row. If you get to this level of overriding StudioWorks field handling you will likely need to also take over the FieldHandlersFactory_Task. Ask questions via the StudioWorks members list if you get to this stage.

Note

StartNewApp has a Field Handler Demo module with simple windows that demonstrate various aspects of the field handler. You can shift+click on windows in the demo to look at the code behind the window and step through the field handler code