stlab.adobe.com Adobe Systems Incorporated

sequence_view_multiplexer< T > Struct Template Reference

#include <sequence_mvc_muldex.hpp>

List of all members.

Public Types

typedef
sequence_model_type::cow_value_type 
cow_value_type
typedef
sequence_model_type::key_type 
key_type
typedef dictionary_t model_type
typedef boost::function< void(const
model_type &)> 
proc_type
typedef sequence_model< T > sequence_model_type
typedef T value_type

Public Member Functions

void clear ()
void enable (bool)
void erase (const vector< key_type > &key_set)
void extend (key_type before, key_type key, cow_value_type value)
void extend_set (key_type before, const vector< key_type > &key_set)
void monitor (const proc_type &proc)
void refresh (key_type key, cow_value_type value)

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

Definition at line 243 of file sequence_mvc_muldex.hpp.

typedef boost::function<void (const model_type&)> proc_type

Definition at line 244 of file sequence_mvc_muldex.hpp.

Definition at line 240 of file sequence_mvc_muldex.hpp.

typedef T value_type

Definition at line 239 of file sequence_mvc_muldex.hpp.


Member Function Documentation

void clear (  )

Definition at line 302 of file sequence_mvc_muldex.hpp.

void enable ( bool   )

Definition at line 317 of file sequence_mvc_muldex.hpp.

void erase ( const vector< key_type > &  key_set )

Definition at line 289 of file sequence_mvc_muldex.hpp.

void extend ( key_type  before,
key_type  key,
cow_value_type  value 
)

Definition at line 260 of file sequence_mvc_muldex.hpp.

void extend_set ( key_type  before,
const vector< key_type > &  key_set 
)

Definition at line 275 of file sequence_mvc_muldex.hpp.

void monitor ( const proc_type proc )

Definition at line 314 of file sequence_mvc_muldex.hpp.

void refresh ( key_type  key,
cow_value_type  value 
)

Definition at line 246 of file sequence_mvc_muldex.hpp.

Copyright © 2006-2007 Adobe Systems Incorporated.

Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.

Search powered by Google