What are ridgets?
A ridget wraps an actual UI widget but offers a higher level of abstraction and it is independent from the UI toolkit (SWT). The idea is to separate the UI (view) from the logic behind it, which is moved to a view controller. The view controller interacts with the actual UI widgets through the ridgets. It should be possible to reuse a view controller with a view that is based on a different UI toolkit (e.g. Swing).
In effect, a ridget can be considered a mini-controller for a single UI control.
A ridget offers the most commonly-used functionality (like setText(String) of a text field) along with some extra convenience functionality like markers. A textfield can be marked as error by adding an ErrorMarker. The marking itself (changing color, setting icons, etc.) is handled by the Riena framework. Another example is the bindToModel(...) method for a simple databinding with a JavaBean.
The overall intention is to reduce the complexity for the application developer and to ensure a common look & feel across the application. If the functionality offered by the ridget's interface is not sufficient the developer can always access the actual UI widget. (Then of course he loses the independence from the UI toolkit). The set of ridgets is constantly getting bigger. If necessary it should be possible for applications to add its own ridgets.
In the view you create SWT controls as always and register them with Riena (addUIControl(...)). The ridgets will be injected into the controller, where you then have access to the corresponding ridgets.
(Adapted from a discussion on riena-dev.) See also Ridget Design Principles.
Riena application can provide and use its own ridgets (see issue #259937). This feature is meant for situations where a specific ridget (and corresponding widget) is not already present in Riena. To support a new custom ridget the following has to be done:
- For the widget, create a ridget class implementing as minimum interface IRidget (many examples for ridgets can be found in Riena, i.e. all subclasses of IRidget).
- — Comments by Elias: The default starting point would be extending AbstractRidget. However it will be easier to extend AbstractSWTRidget or AbstractValueRidget - even though they are internal. I believe in the long run, we may have to make them API to make implementing new Ridgets easier. Please provide feedback on the mailing list or newsgroup.
- Furthermore, a mapping from the widget class to the ridget class must be provided to create the corresponding ridget of a widget from the view for the controller at runtime. This is done by adding the desired mapping to the existing mappings of singleton SwtControlRidgetMapper using the following API methods:
- : .addMapping(CustomWidget.class, CustomRidget.class)
- : .addMapping(CustomWidget.class, CustomRidget.class, swtStyle)
- : .addMapping(CustomWidget.class, CustomRidget.class, new CustomMappingCondition())
- For more details look at the JavaDoc of class SwtControlRidgetMapper. The mapping may be added in the custom application's activator for use in that application afterwards. Custom ridgets can be provided for all SWT widgets. For example, ridgets may be built for widgets from Nebula. Their usage is demonstrated in the Snippets.
Ridget Design Principles
To better understand the existing code and some challenges involved when writing a ridget, here are some design principles we follow. This applies to all IValueRidget/AbstractValueRidget implementations.
Values and Bindings
- There are three values: value of the model, value in the ridget, value in the widget.
- When invoking bindToModel(...), the value of the model is bound to the value of the ridget. The value in the ridget is not changed when binding until ridget#updateFromModel is invoked (see below).
- Update from ridget to model is automatic. Update from model to ridget happens on request (ridget#updateFromModel())
- When a control is bound to the ridget (ridget#setUIControl(...) invoked by the framework), the value of the ridget is copied into the control. From that point the value of the control is bound to the value in the ridget. Update in both directions (ridget to control, control to ridget) is automatic.
Ridgets and Controls
- Ridgets do not require a control (=widget) to work correctly.
- Ridgets initially have no control (i.e. getUIControl() returns null).
- When invoking ridget setters that may affect the control (example setVisibile(...)), the state must be stored in the ridget. The state is applied to the control immediately (if a control is available) or later (when a control is introduced via setUIControl(...))
- A ridget can be unbound from a control (i.e. ridget#setUIControl(null)) or bound to a different control (i.e. ridget#setUIControl(otherControl)). In both cases listeners / bindings to the original control must be cleaned up. After this method returns, the ridget should not modify the original control anymore.
A ridget should be provided as an interface. Then it is possible to access it through that interface in the controller.