=== Top of the Swiki === Attachments ===

responsibilites of Model, View and Controller

"Inside Smalltalk II", by Lalonde and Pugh, is an old but still
very interesting book that describes the MVC classes of Smalltalk-80
version 2.x (the predecessor of ObjectWorks and of VisualWorks) which
was very similar to Squeak.

You may look at the development tools which are implemented with the help
of the MVC framework. For example, look at "Inspector open"

Here's some ad hoc information about the MVC framework. Don't expect too
much but this might be helpful for you. I'll try to explain the basics here.

Each gui object (widget or window) consists of a MVC triad.

The model ("M") implements the data part of the object, for example the
text shown in text pane of an inspector. The view ("V") defines how the
model is shown. Both model and view are connected. The view is a dependent
of the model and also directly knows the model. Every time the model
changes its values, the view will notice this and can update the display.
The controller ("C") is closely related to the view and controls the
behavior of the object. Actually, the controller handles user interaction.

There're two kinds of controllers: Scheduled controllers (windows) and
unscheduled controllers (all other widgets). The global variable
"ScheduledControllers" contains a ControlManager instance which maintains a
list of all displayed windows and knows which window is currently active.
The ControlManager looks for a window that should become active by sending
the message #isControlWanted to each window controller. If the controller
answers true, the ControlManager sends #startUp to that controller.

Other widgets work quite similar. They also react to #isControlWanted and
  1. startUp, but they're dispatched by other controllers. We'll see how this
happens in a minute.

The abstract class Controller defines the basic behavior of all
controllers. Each controller knows its view and its model. It also knows an
InputSensor which can be queried about mouse and keyboard state.

This methods implement the basic control loop:

startUp
Called if #isControlWanted answered true. Will initialize, run and
terminate the control loop. You'll probably never have to overwrite
this method. Any object that responds to #isControlWanted and #startUp
is considered as a controller. A scheduled controller must also respond
to #closeAndUnschedule.

controlInitialize
Called right after startup, before entering the controlLoop (see below).
Does nothing in Controller, but may be overwritten in subclasses. For
example, if you want to change the mouse cursor to an I-beam if the mouse
enters your widget, then this is the right place.

controlTerminate
Called after the controlLoop (see below) has been terminated. This is
an empty method in Controller, but my be overwritten in subclasses. To
continue to above example, this would be the place to reset the cursor
to its old form.

controlLoop
As long as the controller wants to keep control (#isControlActive
answers true) this method loops and calls #controlActivity. You'll
probably never have to overwrite this loop. Subclasses will however
customize the other two methods.

isControlWanted
Will answer true, if the controller wants control. By default, the
controller will be started up when the mouse cursor moves over the
display box of the controller's view without pressing any buttons.

isControlActive
Must answer true as long as the controller wants to keep control.
This can be the same condition as in #isControlWanted or something
very different. Let's think about push button which can be canceled
by moving the mouse away from the button while pressing the mouse.
(This is the default behavior of known GUI's, only Squeak doesn't
have this feature.) The button will get control if the mouse is
pressed over the widget, but it retains control as long as the button
is pressed, regardless of the mouse position.

controlActivity
This methods implements what will actually happen. It will be
overwritten in most subclasses of Controller. The default is to
pass the control to some child widget (#controlToNextLevel).
The MouseMenuController, for example, determines which mouse
button was pressed (red=left, yellow=middle, blue=right) and
branches to a special redButtonActivity, yellowButtonActivity or
blueButtonActivity method, which then can open a popup menu.

Let's look at the View class now. A view knows its controller and model and
is also a dependent of that model. The abstract class View is overloaded
with methods in Squeak. At least, a view has to implement the methods
  1. display, #update:, #containsPoint: and #subViewWantingControl. The View
also maintains a hierarchy of views, knowing a top view, sub views and
super views.

For no better reason, the view as chosen as the one that's responsible to
construct the MVC triad. It will create and assign a controller and will
add and remove the dependency to its model. Overwrite the method
  1. defaultControllerClass to answer the associated Controller subclass and
then assign a model using the message #model:.

It's a good idea to assign a display box to the view. Use #window: with a
rectangle object as argument. By default, the rectangle is relative to the
super view, that is, if you resize the top view, all sub views are scaled
as needed. It's however quite complicated code I confess I didn't really
understand. You can query the view for its display box using #displayBox
(including borders) and #insetDisplayBox (without borders). To assign a
border, use #borderWidth: or borderWidthLeft:right:top:bottom: if you want
to have different border sizes.

New widgets are added using addSubView: and friends. You can specify the
alignment of views, creating relative positioned views without worrying
about window rectangles.

The most important methods in detail:

display
Draw something that represents the view. It is always drawn on the
DisplayScreen instance which is assign to the global variable Display.
(This doesn't allow view display on more than one source, for example
in host windows, unfortunately. A better solution would be to have
a method "displayOn: aDisplayScreen.") The default implementation
first draws a border (#displayBorder), then draws the view itself
(#displayView) and finally draws the sub views (#displaySubViews).
There're also some methods to #emphasize and #deEmphasize views which
can be used to show the active widget or window. However, these
methods tend to cause display flickering because they draw views too
often.

update: aSymbol
This method is called when the dependent model calls its #changed
method. You can use the argument to specify the aspect that has
changed, for example to optimize redraw. Most often, however, the
view is redrawn, based on the new state of its model. (There's also
an implementation of #update in View, which seems to be dubious.)

containsPoint: aPoint
Answer true, if aPoint belongs to the view. You may want to overwrite
this method for non-rectangular views. The StandardSystemView, for
example, overwrites this method because it once had a non-rectangluar
shape because of its label.

There's some dubious and some obviously wrong methods in class View.


Model is the abstract class for all models. You don't however must use
subclasses of model, actually the just optimize dependency. Some other
methods like #topView or #arrowKey:from: are dubious IMHO.

A model need to implement just one method: #changed:

changed: aSymbol
Inform all dependencies about a change of the receiver. The argument
can be used to specify the aspect that has been changed.

addDependent: anObject
Add anObject as a dependent of the receiver. In the case of MVC, this
method is send by the View. The view also removes the dependency if
needed.

removeDependent: anObject
AnObject isn't a dependent of the receiver anymore.

okToChange
Send by a controller (the comment says, actually it nearly always
the model itself; don't trust comments) to ask whether the model
is ready to change its state. For example if you change a method in
a class browser and you haven't accepted the text pane yet, there's
a notifier triggered by this method.

canDiscardEdits
hasUnacceptedEdits
Two other methods sent to views, models or controllers (who knows)
to implement confirmations and notifications. I wish there'd be strict
protocol types the compiler could check. This would definitely help
in documenting interfaces!