PageRenderTime 31ms CodeModel.GetById 12ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/GUI/Generic/Models.py

https://bitbucket.org/alsh/pygui-mirror
Python | 88 lines | 70 code | 7 blank | 11 comment | 0 complexity | bcea77250ae0a095ea83cbaa9e9fc108 MD5 | raw file
 1#
 2#		Python GUI - Models - Generic
 3#
 4
 5import weakref
 6from Properties import Properties, overridable_property
 7
 8#  List of views for a model is kept separately so that models
 9#  can be pickled without fear of accidentally trying to pickle
10#  the user interface.
11
12_model_views = weakref.WeakKeyDictionary() # {Model: [object]}
13
14class Model(Properties):
15    """A Model represents an application object which can appear in a View. 
16    Each Model can have any number of Views attached to it. When a Model is 
17    changed, it should notify all of its Views so that they can update
18    themselves."""
19    
20    views = overridable_property('views', 
21        "List of objects observing this model. Do not modify directly.")
22
23    def __init__(self, **kwds):
24        Properties.__init__(self, **kwds)
25
26    def destroy(self):
27        """All views currently observing this model are removed, and their
28        'model_destroyed' methods, if any, are called with the model as
29        an argument."""
30        for view in self.views[:]:
31            self.remove_view(view)
32            self._call_if_present(view, 'model_destroyed', self)
33
34    #
35    #		Properties
36    #
37
38    def get_views(self):
39        views = _model_views.get(self)
40        if views is None:
41            views = []
42            _model_views[self] = views
43        return views
44     
45    #
46    #		Adding and removing views
47    #
48    
49    def add_view(self, view):
50        """Add the given object as an observer of this model. The view will
51        typically be a View subclass, but need not be. If the view is not 
52        already an observer of this model and defines an 'add_model' method,
53        this method is called with the model as an argument."""
54        views = self.views
55        if view not in views:
56            views.append(view)
57            self._call_if_present(view, 'add_model', self)
58    
59    def remove_view(self, view):
60        """If the given object is currently an observer of this model, it
61        is removed, and if it defines a 'remove_model' method, this method
62        is called with the model as an argument."""
63        views = self.views
64        if view in views:
65            views.remove(view)
66            self._call_if_present(view, 'remove_model', self)
67
68    #
69    #		View notification
70    #
71
72    def notify_views(self, message = 'model_changed', *args, **kwds):
73        """For each observer, if the observer defines a method with the name of the
74        message, call it with the given arguments. Otherwise, if it defines a
75        method called 'model_changed', call it with no arguments. Otherwise,
76        do nothing for that observer."""
77        for view in self.views:
78            if not self._call_if_present(view, message, self, *args, **kwds):
79                self._call_if_present(view, 'model_changed', self)
80    
81    def _call_if_present(self, obj, method_name, *args, **kwds):
82        method = getattr(obj, method_name, None)
83        if method:
84            method(*args, **kwds)
85            return 1
86        else:
87            return 0
88