|
|
| Presenter | |||
|
|
In Rationale 3.1, a presenter is defined as an object that shows or displays a view to the application user. The presenter is also responsible for connecting the view to its corresponding model. A scalar presenter is one that presents a "scalar" view, which essentially corresponds to a GUI widget connected to a scalar model, a cell. Later we will look at composite presenters, which present composite views connected to composite models (structures). This distinction is blurred, however, by presenters such as the ListBox, which present a single widget connected to a composite model. Nevertheless, the ListBox will be described in this section, since it displays a single widget.
The general technique of evolving a framework was introduced previously. Here we more specifically evolve four presenters, and except for the Button presenter, each is developed in two phases: (1) making connections from the model/cell to the view, and (2) making connections to the model. The Button presenter, of course, has no associated model. As always, the definitions are displayed in boxes with a white background, while the unit tests are given a green background. For the most part, these are presented in the order in which they were originally investigated.
Since the investigation is carried out as a suite of unit tests, the module begins by importing the unittest module. The views needed are imported from the ui module, and the models are imported from the abstraction module as ab. This means that all view classes have the prefix ui. and all model classes the ab. prefix.
import unittest from donnal.thought import ui from donnal.thought import abstraction as ab
class TextField_000(ui.TextWidget): """Bare bones presenter; nothing but the view""" def __init__(self, parent=None): ui.TextWidget.__init__(self, parent)
class Test000(unittest.TestCase): """Evolving the TextField presenter: connection from model""" def test001(self): """pre TextField: bare view""" x = TextField_000() x.SetValue(4321) self.assertEqual(x.GetValue(), '4321')
...
class TextField_001(ui.TextWidget): """Minimal presenter, start evolution from here.""" modelType = ab.StringCell def __init__(self, parent=None): ui.TextWidget.__init__(self, parent) self._model = self.modelType() self._model.AddObserver(self) self.Update(self._model) def Update(self, source): """The presenter is an observer of the model.""" self.SetValue(self._model.value) def GetModel(self): return self._model
# class Test000 (continued)
def test002(self):
"""pre TextField: observes a default model"""
x = TextField_001()
m = x.GetModel()
m.value = 3344
self.assertEqual(x.GetValue(), '3344')
...
class TextField_002(TextField_001): """Pass a model instance as parameter to presenter""" def __init__(self, parent=None, model=None): ui.TextWidget.__init__(self, parent) self._model = model or self.modelType() self._model.AddObserver(self) self.Update(self._model)
# class Test000 (continued)
def test003(self):
"""pre TextField: observes a default model"""
x = TextField_002()
m = x.GetModel()
m.value = 3344
self.assertEqual(x.GetValue(), '3344')
def test004(self):
"""pre TextField: observes a given model instance"""
m = ab.StringCell()
m.value = 'at init'
x = TextField_002(model=m)
self.assertEqual(x.GetValue(), 'at init')
m.value = 3344
self.assertEqual(x.GetValue(), '3344')
class TextField_010(TextField_001): """Connect event trigger to event-handler method""" def __init__(self, parent=None, model=None): ui.TextWidget.__init__(self, parent) self._model = model or self.modelType() self._model.AddObserver(self) self.Update(self._model) ui.EVT_KILL_FOCUS(self, self.OnLoseFocus) def OnLoseFocus(self, event): """Public event handler, may be overridden if necessary""" self._model.Set(self.GetValue())
class Test010(unittest.TestCase): """Evolving the TextField presenter: connection to model""" def test001(self): """TextField: bi-directional connection""" m = ab.StringCell() x = TextField_010(None, m) # model m, presenter x # from model to view m.value = 'first' # this is the model value self.assertEqual(x.GetValue(), 'first') # view follows # from view to model x.SetValue('second') # this is the view value x.trigger1('evt') # textwidget has lost focus self.assertEqual(m.value, 'second') # model follows
class TextField_015(TextField_010): """Pass outside parameters to event-handler method""" def __init__(self, parent=None, model=None, *args, **kwds): ui.TextWidget.__init__(self, parent) self._model = model or self.modelType() self._model.AddObserver(self) self._args = args self._kwds = kwds self.Update(self._model) ui.EVT_KILL_FOCUS(self, self._handle_KILL_FOCUS) def _handle_KILL_FOCUS(self, event): """Private event handler to call public event handler""" self.OnLoseFocus(event, self._model, *self._args, **self._kwds) def OnLoseFocus(self, event, model): """Public event handler, may be overridden if necessary""" model.Set(self.GetValue())
# class Test010 (continued)
def test002(self):
"""TextField: passing no parameters works like before"""
m = ab.StringCell()
x = TextField_015(None, m) # model m, presenter x
# from model to view
m.value = 'first' # this is the model value
self.assertEqual(x.GetValue(), 'first') # view follows
# from view to model
x.SetValue('second') # this is the view value
x.trigger1('evt') # textwidget has lost focus
self.assertEqual(m.value, 'second') # model follows
....
class TextField_016(TextField_015): """Use outside parameter(s) passed to event-handler method""" def OnLoseFocus(self, event, model, other): other.Set(self.GetValue())
# class Test010 (continued)
def test003(self):
"""TextField: positional parameter used"""
m = ab.StringCell()
o = ab.StringCell()
x = TextField_016(None, m, o) # model m, other o
# from model to view
m.value = 'first' # this is the model value
self.assertEqual(x.GetValue(), 'first') # view follows
# from view to 'other'
x.trigger1('evt') # textwidget has lost focus
self.assertEqual(o.value, 'first') # other follows
def test004(self):
"""TextField: keyword parameter used"""
o = ab.StringCell()
x = TextField_016(other=o) # model m, other o
m = x.GetModel()
# from model to view
m.value = 'first' # this is the model value
self.assertEqual(x.GetValue(), 'first') # view follows
# from view to 'other'
x.trigger1('evt') # textwidget has lost focus
self.assertEqual(o.value, 'first') # other follows
class Button_001(ui.Button): """A simple presenter/controller (no model) using ui.Button""" def __init__(self, parent=None, *args, **kwds): ui.Button.__init__(self, parent) self._args = args self._kwds = kwds ui.EVT_BUTTON(self, self._handle_BUTTON) def _handle_BUTTON(self, event): """Private event handler to call public event handler""" self.OnClick(event, *self._args, **self._kwds) def OnClick(self, event, *args, **kwd): """Abstract event handler. Override in application""" pass class MyButton(Button_001): """Use outside parameter(s) passed to event-handler method""" def OnClick(self, event, other): other.Set('hello')
class TestButton(unittest.TestCase): """Test all aspects of the Button presenter. Not 'evolved'.""" def test_000_001(self): """Button: positional parameter used""" o = ab.StringCell() x = MyButton(None, o) # other o # from view to 'other' x.trigger1('evt') # button clicked self.assertEqual(o.value, 'hello') # other follows def test_000_002(self): """Button: keyword parameter used""" o = ab.StringCell() x = MyButton(other=o) # other o # from view to 'other' x.trigger1('evt') # button clicked self.assertEqual(o.value, 'hello') # other follows
class Choice_001(ui.Choice): """Minimal presenter, start evolution from here.""" modelType = ab.StringCell def __init__(self, parent=None): ui.Choice.__init__(self, parent, choices=None) self._model = self.modelType() self._model.AddObserver(self) for i in self._model.GetChoices(): self.Append(i) self.Update(self._model) def Update(self, source): """The presenter is an observer of the model.""" sel = self.FindString(self._model.value) if sel == -1: sel = 0 self.SetSelection(sel) def GetModel(self): return self._model class Choice_002(Choice_001): """Pass a model instance as parameter to presenter""" def __init__(self, parent=None, model=None): ui.Choice.__init__(self, parent, choices=None) self._model = model or self.modelType() self._model.AddObserver(self) for i in self._model.GetChoices(): self.Append(i) self.Update(self._model) class MyStringCell(ab.StringCell): choices = ['papa bear', 'mama bear', 'baby bear']
class Test000(unittest.TestCase): """Evolving the Choice presenter: connection from model""" def test001(self): """pre Choice: FindString""" y = Choice_001() y.Append('one') y.Append('two') self.assertEqual(y.FindString('one'), 0) self.assertEqual(y.FindString('two'), 1) self.assertEqual(y.FindString('three'), -1) def test002(self): """pre Choice: pass model to presenter""" x = MyStringCell() y = Choice_002(model=x) self.assertEqual(y.FindString('papa bear'), 0) self.assertEqual(y.FindString('mama bear'), 1) self.assertEqual(y.FindString('baby bear'), 2) self.assertEqual(y.FindString('no bear'), -1) self.assertEqual(y.GetSelection(), 0) x.value = 'baby bear' self.assertEqual(y.GetSelection(), 2)
class Choice_010(Choice_002): """Connect event trigger to event-handler method""" def __init__(self, parent=None, model=None): ui.Choice.__init__(self, parent, choices=None) self._model = model or self.modelType() self._model.AddObserver(self) for i in self._model.GetChoices(): self.Append(i) self.Update(self._model) ui.EVT_CHOICE(self, self.OnSelect) def OnSelect(self, event): """Public event handler, may be overridden if necessary""" self._model.Set(self.GetString(self.GetSelection())) class Choice_015(Choice_010): """Pass outside parameters to event-handler method""" def __init__(self, parent=None, model=None, *args, **kwds): ui.Choice.__init__(self, parent, choices=None) self._model = model or self.modelType() self._model.AddObserver(self) for i in self._model.GetChoices(): self.Append(i) self._args = args self._kwds = kwds self.Update(self._model) ui.EVT_CHOICE(self, self._handle_CHOICE) def _handle_CHOICE(self, event): """Private event handler to call public event handler""" self.OnSelect(event, self._model, *self._args, **self._kwds) def OnSelect(self, event, model): """Public event handler, may be overridden if necessary""" model.Set(self.GetString(self.GetSelection())) class OtherChoice(Choice_015): """Use outside parameter(s) passed to event-handler method""" def OnSelect(self, event, model, other): other.Set(self.GetSelection()) model.Set(self.GetString(other.value))
class Test010(unittest.TestCase): """Evolving the Choice presenter: connection to model""" def test001(self): """pre Choice: bi-directional connection""" m = MyStringCell() x = Choice_010(None, m) # model m, presenter x # from model to view m.value = 'baby bear' # this is the model value self.assertEqual(x.GetSelection(), 2) # view follows # from view to model self.assertEqual(m.value, 'baby bear') # starting value x.trigger1(1) # select second item self.assertEqual(m.value, 'mama bear') # model follows def test002(self): """pre Choice: passing extra paramenters, none given""" m = MyStringCell() x = Choice_015(None, m) # model m, presenter x # from model to view m.value = 'baby bear' # this is the model value self.assertEqual(x.GetSelection(), 2) # view follows # from view to model self.assertEqual(m.value, 'baby bear') # starting value x.trigger1(1) # select second item self.assertEqual(m.value, 'mama bear') # model follows def test003(self): """pre Choice: positional parameter used""" m = MyStringCell() o = ab.StringCell() x = OtherChoice(None, m, o) # model m, other o # from model to view m.value = 'baby bear' # this is the model value self.assertEqual(x.GetSelection(), 2) # view follows # from view to model self.assertEqual(m.value, 'baby bear') # starting value x.trigger1(1) # select second item self.assertEqual(m.value, 'mama bear') # model follows self.assertEqual(o.value, '1') # other follows def test004(self): """pre Choice: keyword parameter used""" m = MyStringCell() o = ab.StringCell() x = OtherChoice(other=o, model=m) # from model to view m.value = 'baby bear' # this is the model value self.assertEqual(x.GetSelection(), 2) # view follows # from view to model self.assertEqual(m.value, 'baby bear') # starting value x.trigger1(1) # select second item self.assertEqual(m.value, 'mama bear') # model follows self.assertEqual(o.value, '1') # other follows
class TestBoxStructure(ab.Structure): def Assemble(self): self.Add('something', ab.StringCell) def Get(self): return self.something.value class TestBoxTable(ab.Table): item = TestBoxStructure class ListBox_001(ui.ListBox): """Minimal presenter, start evolution from here.""" model = TestBoxTable sortkey = 'something' def __init__(self, parent=None): ui.ListBox.__init__(self, parent, choices=None) self._model = self.model() self._model.AddObserver(self) self.Update(self._model) def Update(self, source): """The presenter is an observer of the model.""" self.Clear() for i in self._model.GetSortedList(self.sortkey): self.Append(i[0], i[2]) # text, data; i[1] is name def GetModel(self): return self._model class ListBox_002(ListBox_001): """Pass a model instance as parameter to presenter""" def __init__(self, parent=None, model=None): ui.ListBox.__init__(self, parent, choices=None) if model == None: self._model = self.model() else: self._model = model self._model.AddObserver(self) self.Update(self._model)
class Test000(unittest.TestCase): """Evolving the ListBox presenter: connection from model""" def test001(self): """pre ListBox: default model, component values""" x = ListBox_001() m = x.GetModel() y = m.Add() y.something.value = 'bb' y.something.NotifyAncestors() self.assertEqual(x.GetString(0), 'bb') y = m.Add() self.assertEqual(x.GetString(0), 'bb') self.assertEqual(x.GetString(1), None) y.something.value = 'aa' y.something.NotifyAncestors() self.assertEqual(x.GetString(0), 'aa') self.assertEqual(x.GetString(1), 'bb') def test002(self): """pre ListBox: passing a given model instance""" m = TestBoxTable() y = m.Add() y.something.value = 'bb' y = m.Add() y.something.value = 'aa' x = ListBox_002(model=m) self.failUnless(m is x.GetModel()) self.assertEqual(x.GetString(0), 'aa') self.assertEqual(x.GetString(1), 'bb')
class ListBox_010(ListBox_002): """Pass a model instance as parameter to presenter""" def __init__(self, parent=None, model=None, *args, **kwds): ui.ListBox.__init__(self, parent, choices=None) if model == None: self._model = self.model() else: self._model = model self._model.AddObserver(self) self._args = args self._kwds = kwds self.Update(self._model) ui.EVT_LISTBOX(self, self._handle_EVT_LISTBOX) ui.EVT_LISTBOX_DCLICK(self, self._handle_EVT_DCLICK) def _handle_EVT_LISTBOX(self, event): """Private event handler to call public event handler""" self.OnSelect(event, *self._args, **self._kwds) def _handle_EVT_DCLICK(self, event): """Private event handler to call public event handler""" self.OnDClick(event, *self._args, **self._kwds) def OnSelect(self, event, *args, **kwds): """Abstract event handler. Override in application.""" pass def OnDClick(self, event, *args, **kwds): """Abstract event handler. Override in application.""" pass class MyListBox(ListBox_010): def OnSelect(self, event, first, second): """Public event handler.""" cd = self.GetClientData(event) if cd != None: val = cd.something.value else: val = '' first.something.Set(val) def OnDClick(self, event, first, second): """Public event handler.""" cd = self.GetClientData(event) if cd != None: val = cd.something.value else: val = '' second.something.Set(val)
class Test010(unittest.TestCase): """Evolving the ListBox presenter: connection to app""" def test001(self): """pre ListBox: controller aspect of presenter""" a = TestBoxStructure() b = TestBoxStructure() m = TestBoxTable() y = m.Add() y.something.value = 'bb' x = MyListBox(None, m, a, b) # from model to view y = m.Add() y.something.value = 'aa' y.something.NotifyAncestors() self.assertEqual(x.GetString(0), 'aa') self.assertEqual(x.GetString(1), 'bb') # from view to 'first' x.trigger1(0) self.assertEqual(a.something.value, 'aa') self.assertEqual(b.something.value, '') x.trigger2(1) self.assertEqual(a.something.value, 'bb') self.assertEqual(b.something.value, 'bb')
...
|
XHTML 1.0
© 2003 Donnal C. Walter,
This page updated 2003-12-11. See About this document for information on suggesting changes. |