This is an old revision of the document!
Implementation of Custom UI Component
This article explains how to implement a custom SOLoist UI component.
Introduction
SOLoist library contains built-in UI components that enable UI programmers to create complex layouts using horizontal, vertical, table, absolute, flow, dock, and layered layout. In addition to that, SOLoist provides tabs, decks, disclosure panels, scroll panels, and dialogs. Second, it provides UI components for browsing (and editing) domain object space. These are lists, tables, trees, search components, etc. There is also a set of input controls and editor UI components that correspond to the supported OOIS UML built-in data types like Text, Integer, Real, Boolean, File, Picture, Currency, etc. These are special text boxes, combo boxes, suggest boxes, date pickers, color pickers, file/picture uploaders, and more. In order to embrace a bit of usual UI behavior and spare programmers from manual efforts in this area, SOLoist also offers a collection of so-called non-visual UI components like filters, logic components, transformers, buffers, relays, etc. They may perform some frequently used portions of UI behavior. Finally, SOLoist library provides a group of usual and simple components like labels, pictures, links, HTML components, buttons, menus, etc.
If a custom UI component is needed, it can be created by following the instructions below. A custom component can do arbitrary work on the client and/or on the server side of application. It can compensate for any type of functionality missing in the library of built-in UI components. For example, it can even embody an external widget (e.g., Google Maps or any other), or render its piece of HTML on the client on its own. Such custom component stays in line with the overall paradigm and communicates with other components in a controlled and uniform manner (via pins and bindings).
Architecture
There are five runtime constitutive elements of each UI component. They are:
- UI component class. This class resides on the server side and it has the usual SOLoist OOIS UML semantics. It is instantiated on the server. This class is responsible for maintaining the configuration parameters of the component in its attributes, as well as for serializing its configuration parameters into a so-called info structure that is transferred to the client.
- Info class. An object of this class serves as a carrier of UI configuration data (attribute values) for a particular UI component. This object is also responsible for creating an appropriate controller object when it reaches the web browser on the client.
- Controller class. An object of this class resides on the client (in the web browser) and, along with its widget, represents an incarnation of the UI component on the client. It is responsible of creating its widget instance, for managing it, for handling UI events captured by that widget instance, for handling events on input pins, for generating events on output pins, and for communicating with server.
- Widget interface. This interface is a façade of a widget instance. The controller object uses it to communicate with its widget. Its purpose is to keep the controller code independent from the UI implementation framework, which is GWT in this case. In other words, the controller object accesses the GWT widget through this interface.
- GWT widget class. An object of this class is the actual (usually, but not necessarily tangible and visible) widget. Its purpose is to provide visual information to the user of the application, as well as to capture user-generated events and forward them to its controller object. It accesses its controller object through a direct Java reference.
Figure 1 depicts the described architecture of the SOLoist GUI subsystem.
Implementation Procedure
To create a custom widget:
- Create the UI component class. Creating the UI component class is performed in the UML model of the application under construction. At least one UML package for custom UI components should be reserved and created in advance. This package should be stereotyped with
«domain». The new UI component UML class should be placed in that package. The process of creating a new UI component class is as follows:- Provide the class with an appropriate name, for example,
GUILabelComponent. - Derive it from the top-level SOLoist UI class
GUIComponent. Note that by extending theGUIComponentclass, the derived class inherits several attributes and pins. The desired behavior for events on those pins and attributes should be provided later on when implementing the behavior of the component under construction. For example, one of these attributes is the attributeenabled; the implemented behavior should ensure that the widget is disabled when this attribute is set to false. - If the UI component is to be configurable in terms of its appearance or functionality, a number of UML attributes should be modeled for the configuration.
- Each UI component communicates with other components via pins and wires. For each pin, a UML attribute stereotyped with
«input»or«output»depending on its purpose. The type of this attribute is irrelevant and can simply beText.
Figure 2 shows the example GUILabelComponent class with the abovementioned steps conducted. The attribute text is meant for holding the initial label’s text. The attribute textSize holds the value that defines the size of the label’s text in, let’s say, pixels. Furthermore, there is an input pin newText which is meant to accept a new arbitrary text so that GUILabelComponent can change it dynamically. Finally, the UI component is able to inform its surrounding UI components that its value (text) has changed, and the output pin textChanged is used for that.
