When creating a Model-View-Presenter triad, you will have decided whether the component can be built from a collaboration of other components or whether it is elemental in nature. This pattern discusses how to create Composite component once the underlying domain model class has been designed once you have already created a model class. presenter to handle the model.
Diagrammatic representation of a composite component triad
You will use the New Class pattern to create a new presenter class. First of all, you must decide where this is to be subclassed from. All composite presenters inherit from CompositePresenter in the class hierarchy. Follow these rules to decide on a suitable superclass.
#defaultModel -- Once you have created a presenter class you should add a #defaultModel class method to answer an object to use as the default model when an instance of this presenter component is created. This is normally a suitably initialized instance of your model class. If you have created a ValueDialog subclass you should wrap this in a ValueHolder by sending #asValue to the model object.
#defaultView -- A presenter must also support a #defaultView class method to answer the name of a resource that will yield a default view to be used when a instance of the presenter is created. You may choose to delay writing this method until after you have created a suitable view class and registered a named instance with the Resource Manager.
#createComponents -- a composite presenter should override the #createComponents method to create the sub-presenter's from which it is composed. New presenters are added to the composite using #add:name:. Each sub-presenter is given a textual name which will lay to be used to match against a same named view when the composite is opened into a window.
Example: MethodBrowser>>createComponents "Private - Create the presenters contained by the receiver"super createComponents. methodsPresenter := self add: MethodListPresenter new name: 'methods'. sourcePresenter := self add: SmalltalkWorkspace new name: 'source'.#createSchematicWiring -- this method should be overridden to register the composite presenter with any event notifications that are generated by its sub-presenters or their views. This method is called once the composite has been fully created and its view opened and attached.
Example: MethodBrowser>>createSchematicWiring "Private - Create the trigger wiring for the receiver"super createSchematicWiring. methodsPresenter when: #selectionChanged send: #onMethodSelected to: self; when: #selectionChanging: send: #onSelectionChanging: to: self; when: #actionPerformed send: #browseClasses to: self.self model when: #methodAdded: send: #onMethodAdded: to: self; when: #methodRemoved: send: #onMethodRemoved: to: self.#model: -- when a model is assigned to a composite presenter it is usually necessary to connect its sub-presenters up to the same model. Very often the sub-presenters will be value presenters and will be hooked up to aspects of the composite model using ValueAspectAdaptors.
Example: ResourceIdentifierDialog>>model: aResourceIdentifier "Set the model associated with the receiver."super model: aResourceIdentifier. classTree model: (self model aspectValue: #owningClass). resourceName model: (self model aspectValue: #name).
Obviously, you must add additional methods to the presenter class to perform manipulations of the model as required by the user. It's probably make sense to add these methods later once you have had a first pass at designing a view class and testing the entire MVP triad together.
Although you can create a view suitable for connecting to a composite presenter by creating a new View subclass, such views are almost invariably built using the View Composer. The View Composer works by allow you to build up an instance of a composite view by constructing it using view resources is held by the Resource Manager.
As you create a composite view to match a composite presenter you should be aware of the following:
Once you have created a suitable view in the View Composer, it must be saved down as a resource and associated with the presenter class with which it is intended to be used. Don't forget to complete a #defaultView class method for the presenter to identify one such view to be used by default.
The Dolphin development tools provide many examples of composite components. ClassBrowserShell is a composite descended from SmalltalkSystemShell. As such, it can only be used in a shell window and cannot be embedded within other composites.
MethodBrowser however, is a fine example of an embeddable composite component. We decided that we would need to embed a MethodBrowser within a ClassBrowserShell and therefore it had to be descended directly from CompositePresenter. The upshot of this was that an additional class, MethodBrowserShell, is needed to implement the version of a method browser that appears in a top-level window.