The ENABLED idiom
Inherit state information via the GUI hierarchy.
RAD environments provide very limited or no support in this area. (Note: we are not discussing the class hierarchy but rather the GUI tree)
Lets explore the inheritance of the enabled and disabled state of a control. It is a very common and easily understood attribute.
If a control is disabled, the visual appearance of the control becomes faded or ‘grayed out’ and the user would be unable to interact with this control. Once it is enabled, the control becomes visually brighter or color enhanced and the user would be able to interact with the control.
This behavior is intuitive and well understood, however only a few frameworks take full advantage of it. We will use it to demonstrate how failing to incorporate a hierarchy of inheritance of state within the GUI tree would have negative consequences on the development of a robust and elegant applications produced in a timely fashion.
Imagine a panel that contains 3 listboxes and a few buttons. During the update of this panel (loading new data into listboxes) we would like to disable the panel and all of its children controls to prevent the user from potentially corrupting data via his interactions.
Once the update completes (or times out), we would like to re-enable the panel and all its children controls.
This scenario is based on an actual software development project, using Bongo (java GUI framework, predates Swing).
The developer in question was a senior developer and was assigned the responsibility to disable and enable controls in a given panel. He was unable to just disable the panel, and by doing so have all his children controls disabled. These were the steps taken by the developer to remedy the situation.
ONE: create a data structure and map the state of the enabled attribute of all the panels’ children
TWO: get the enabled attribute of all the controls by recursively traversing the panel’s children controls.
THREE: disable all controls by recursively traversing the panel’s children controls.
FOUR: update the panel
FIVE: enabled the panel back to its previously stored state.
Did this algorithm solve our problem?
All entry points into the panel during its update are not caught.
Also upon updating the panel, new controls are sometimes generated. Thus the controls were enabled, allowing the user an ability to interact on an incomplete data set, which potentially would corrupt his data. Updating step four to catch, save and disable newly generated controls before adding them to the panel would solve this problem. However this is an inflexible design decision that greatly inhibits the flexibility and adaptability of an application.
This is a classically complex solution, difficult to maintain, unwieldy to enhancements and prone to be buggy (they always seem to require attention). They are time consuming to develop, hard to debug and difficult to maintain (and as an added bonus, maintenance is usually handled by junior programmers)
One, there are no compelling arguments of allowing children controls to be enabled while their parents are disabled. And two, is there an elegant solution to this problem (low overhead, fast and atomic)
The rule: If a parent control is disabled then so are their children.
It is the responsibility of the object (in this case the control), to handle queries about its state. Thus the implementation: Upon calling the method isEnabled,
“IF my parent is disabled THEN return FALSE
ELSE return enabled_state.”
This IS an elegant solution.
A single IF statement added to the method ‘isEnabled’ simplifies the framework and removes this burden from the application developer of managing potentially conflicting designs and interactivity to his applications which otherwise should be a standardized metaphor.
Programmers note: This is not an example of recursion! This is a tree-traversal solution.
This may be a simple solution, but that is EXACTLY the point.