#include <sequence_mvc_muldex.hpp>
List of all members.
Detailed Description
template<typename T>
struct adobe::sequence_view_multiplexer< T >
OVERVIEW:
This entire header handles a single problem: How do you communicate to other model types (specifically here, a sequence_model) when all you have available to you is the property model library (Adam) to which you can hook up your widgets? In other words, given that the property model library is the only 'interface' you can use to send and receive information to/from your widgets, how do you get data to those widgets that is not well-handled by the property model?
A good example of this is the list widget. We have to account for issues with sequences that the property model library does not handle well. (e.g., lists with large item sets that are expensive to copy, sending notifications only about items in a list that have changed, and setting information about a subset of the items in the list and not the list as a whole.)
The solution here is to send sequence model/view/controller commands _through_ the property model library. We set aside two cells in the PML and farm commands through them: one cell is used to send commands from the model to the attached views, and the other cell is used to send commands from the attached controllers to the model.
One of the requirements placed on any solution is that the sequence model/view/controller components used should have no additional requirements placed on them in order to use the solution. In other words, the sequence model/view/controller components should not be able to tell the difference between being directly connected to other sequence MVC components or being connected to each other through a property model.
The solution provided here follows after the hardware design of a multiplexer/demultiplexer pairing, commonly called a _muldex_. All commands from the source to the destination are multiplexed to fit down a single 'line' (in this case, the property model cell), and are demultiplexed out the other side, where they are farmed out to the actual command recipients.
The first line, from model to view, looks something like this:
sequence_model --> view_proxy --> adam_cell --> model_proxy --> sequence_view [model] [mux] [PML] [demux] [view]
The first collection of components are the mux and demux of the above control flow diagram, along with some helper routines designed to wire the whole system together. The final routine of the collection is intended to do all the 'heavy lifting' for the client, so all they need specify is a sequence model, a sequence view, a property model sheet, a cell name within that sheet, and an assemblage where some heap-allocated objects may be collected for future deletion. Once the system is in place, view update commands are sent to the attached views through the property model using the muldex components implemented here.
The second line, from controller to model, looks something like this:
sequence_controller --> model_proxy --> adam_cell --> controller_proxy --> sequence_model [controller] [mux] [PML] [demux] [model]
The second collection of components are the mux and demux of the above control flow diagram, along with some helper routines designed to wire the whole system together. The final routine of the collection is intended to do all the 'heavy lifting' for the client, so all they need specify is a sequence controller, a sequence model, a property model sheet, a cell name within that sheet, and an assemblage where some heap-allocated objects may be collected for future deletion. Once the system is in place, model manipulation commands are sent to the attached model through the property model using the muldex components implemented here.
The solutions also meets the requirement that no extra burden is placed on the sequence MVC components that is not already asked of them by the sequence MVC concepts themselves.
USAGE CASE 1:
A tack to take, which will likely become the most common case, is demonstrated here. Usually when constructing the system one has the property model and the sequence model together at one point, and you want to bind the two together on the view and controller muldex lines. Later on in another piece of code you will have a widget and the same property model, and would like to bind the two together on both the view and controller muldex lines. In such a case there are two helper routines to call, one for the first instance and one for the second:
adobe::sequence_model<int> sequence_model;
adobe::sheet_t basic_sheet;
my_sequence_widget<int> my_sequence_widget; // models SequenceView and SequenceController
adobe::assemblage_t assemblage; // to cleanup pool allocations and call other functors
adobe::name_t view_line_cell_name;
adobe::name_t controller_line_cell_name;
... at one point in the code:
if (basic_sheet.count_interface(view_line_cell_name) &&
basic_sheet.count_interface(controller_line_cell_name))
attach_sequence_model_to_property_model(string_sequence_model,
basic_sheet,
view_line_cell_name,
controller_line_cell_name,
assemblage);
... then, in another point in the code:
if (basic_sheet.count_interface(view_line_cell_name) &&
basic_sheet.count_interface(controller_line_cell_name))
attach_sequence_widget_to_property_model(my_sequence_widget,
basic_sheet,
view_line_cell_name,
controller_line_cell_name,
assemblage);
Now that everything is attached the system can be used as expected.
my_sequence_widget.push_back(42); // calls proc passed to monitor_push_back
my_sequence_widget.insert(1, 42); // calls proc passed to monitor_insert
USAGE CASE 2:
Another tack to take is binding things together on a per-line basis. Each muldex 'line' (the entire collection of components from one end to the other) can be created with a call to a single API. There are two fundamental muldex lines per MVC system (one model-to-view, and one controller-to-model), each with its own API. Here is a sampling of what the code might look like to hook up these two muldex lines:
adobe::sequence_model<int> sequence_model;
adobe::sheet_t basic_sheet;
my_sequence_view<int> my_sequence_view; // models SequenceView
my_sequence_controller<int> my_sequence_controller; // models SequenceController
adobe::assemblage_t assemblage; // to cleanup pool allocations and call other functors
NOTE (fbrereto) : Make sure the assemblage is last on the list, so it is
destructed first. Thus the proper disconnections are
made prior to the destruction of the individual
components using those connections are destroyed.
... add cells in sheet for the two muldex lines. There are several ways
to do this. Here we take the most bare-bones approach:
adobe::any_regular_t dictionary_initializer;
dictionary_initializer = adobe::any_regular_t(adobe::dictionary_t());
basic_sheet.add_interface(adobe::static_name_t("line_in"), dictionary_initializer);
basic_sheet.add_interface(adobe::static_name_t("line_out"), dictionary_initializer);
attach_sequence_view_muldex(sequence_model,
my_sequence_view,
basic_sheet,
adobe::static_name_t("line_out"),
assemblage);
attach_sequence_controller_muldex(sequence_model,
my_sequence_controller,
basic_sheet,
adobe::static_name_t("line_in"),
assemblage);
Here, you can invoke controller commands in my_sequence_controller and
the corresponding muldex line will propagate the command down the sheet
cell to the model, which will then turn around and propagate the
appropriate notification to my_sequence_view via the other muldex line.
my_sequence_controller.push_back(42); // calls proc passed to monitor_push_back
my_sequence_controller.insert(1, 42); // calls proc passed to monitor_insert
CAVEAT(S):
The property model library (Adam) sheet implementation is not reentrant. This means that you will not be able to supply cells for both muldex lines on a single sheet, as setting one will trigger a model update, thus attempting to set the other before the first update has completed, and the reentrancy assertion will fail. From a design perspective, it is better to have these muldex line cells in the basic sheet instead of the property model sheet. The reason is that if they were in the property model sheet, the implication is that they are essential elements to the command being formed, which is not true. Since the line cells are temporary holding areas for the forwarding of API commands through the sheet-based model, they should reside in the layout sheet. Another reason why they belong in the layout sheet is simply that there should be a pair per dialog instance, as there is an MVC system per dialog instance, and sharing them in the property model does not make sense.
sequence_model -> **sequence_view_multiplexer** -> property_model
This structure is the glue between the sequence model and the property model. It models a sequence view and will receive view updates as such, at which point it bundles up (multiplexes, hence the name) all the parameters it gets into a dictionary. The dictionary is then piped out to the attached property model, of which this structure is a controller to a particular cell. The monitor callback routine will (under the hood) invoke an update of the property model, causing the recently-pushed dictionary to be propagated 'down the line' to the view waiting for it on the other side (see the sequence_view_demultiplexer_t below.)
Definition at line 237 of file sequence_mvc_muldex.hpp.
Member Typedef Documentation
Member Function Documentation