diff --git a/src/gtkmvc/__init__.py b/src/gtkmvc/__init__.py index fe39d3d..6dfbcbd 100644 --- a/src/gtkmvc/__init__.py +++ b/src/gtkmvc/__init__.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2005 by Roberto Cavada # @@ -18,13 +18,13 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . -__all__ = ["model", "view", "controller", "observable", "observer"] +__all__ = ["model", "view", "controller", "observable", "observer", "support"] -__version = (1,2,1) +__version = (1,2,2) from model import Model, TreeStoreModel, ListStoreModel, TextBufferModel from model_mt import ModelMT diff --git a/src/gtkmvc/adapters/__init__.py b/src/gtkmvc/adapters/__init__.py index 1dbb3d2..b843b72 100644 --- a/src/gtkmvc/adapters/__init__.py +++ b/src/gtkmvc/adapters/__init__.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2007 by Roberto Cavada # @@ -18,8 +18,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . from gtkmvc.adapters.basic import Adapter, UserClassAdapter, RoUserClassAdapter from gtkmvc.adapters.containers import StaticContainerAdapter diff --git a/src/gtkmvc/adapters/basic.py b/src/gtkmvc/adapters/basic.py index a24910d..9d0664c 100644 --- a/src/gtkmvc/adapters/basic.py +++ b/src/gtkmvc/adapters/basic.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2007 by Roberto Cavada # @@ -18,8 +18,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . import types @@ -142,7 +142,7 @@ class Adapter (Observer): def update_model(self): """Forces the property to be updated from the value hold by the widget. This method should be called directly by the - user in very unusual coditions.""" + user in very unusual conditions.""" self._write_property(self._read_widget()) return @@ -150,7 +150,7 @@ class Adapter (Observer): """Forces the widget to be updated from the property value. This method should be called directly by the user when the property is not observable, or in very unusual - coditions.""" + conditions.""" self._write_widget(self._read_property()) return @@ -218,8 +218,8 @@ class Adapter (Observer): def _get_property(self): """Private method that returns the value currently stored into the property""" - #return getattr(self.get_model(), self._prop_name) - return self._prop + return getattr(self.get_model(), self._prop_name) + #return self._prop # bug fix reported by A. Dentella def _set_property(self, val): """Private method that sets the value currently of the property.""" @@ -269,7 +269,7 @@ class Adapter (Observer): self._itsme = True try: setter = self._wid_info[self._wid][1] - wtype = self._wid_info[self._wid][2] + wtype = self._wid_info[self._wid][2] if wtype is not None: setter(self._wid, self._cast_value(val, wtype)) else: setter(self._wid, val) finally: @@ -308,8 +308,7 @@ class Adapter (Observer): def _on_prop_changed(self): """Called by the observation code, when the value in the observed property is changed""" - if self._itsme: return - self.update_widget() + if not self._itsme: self.update_widget() return pass # end of class Adapter diff --git a/src/gtkmvc/adapters/containers.py b/src/gtkmvc/adapters/containers.py index 73bebdc..b2d6341 100644 --- a/src/gtkmvc/adapters/containers.py +++ b/src/gtkmvc/adapters/containers.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2007 by Roberto Cavada # @@ -18,14 +18,14 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . import types import gtk -from gtkmvc.adapters.basic import UserClassAdapter +from gtkmvc.adapters.basic import UserClassAdapter, Adapter from gtkmvc.adapters.default import * from gtkmvc.observer import Observer @@ -49,7 +49,6 @@ class StaticContainerAdapter (UserClassAdapter): dynamically. If the container grows up in length, no change will occur in the view-side. """ - def __init__(self, model, prop_name, prop_read=None, prop_write=None, value_error=None): @@ -59,7 +58,8 @@ class StaticContainerAdapter (UserClassAdapter): prop_read, prop_write, value_error) - prop = self._get_property() + prop = Adapter._get_property(self) + #prop = self._get_property() # bug fix reported by A. Dentella if not (hasattr(prop, "__getitem__") and hasattr(prop, "__setitem__")): raise TypeError("Property " + self._prop_name + diff --git a/src/gtkmvc/controller.py b/src/gtkmvc/controller.py index 6d75587..3c75b7d 100644 --- a/src/gtkmvc/controller.py +++ b/src/gtkmvc/controller.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2005 by Roberto Cavada # @@ -18,8 +18,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . from gtkmvc.observer import Observer diff --git a/src/gtkmvc/model.py b/src/gtkmvc/model.py index faedbfd..085723a 100644 --- a/src/gtkmvc/model.py +++ b/src/gtkmvc/model.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2005 by Roberto Cavada # @@ -18,8 +18,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . import support.metaclasses from support.wrappers import ObsWrapperBase diff --git a/src/gtkmvc/model_mt.py b/src/gtkmvc/model_mt.py index bd705c9..f4ff2b5 100644 --- a/src/gtkmvc/model_mt.py +++ b/src/gtkmvc/model_mt.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2006 by Roberto Cavada # @@ -18,8 +18,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . from gtkmvc.model import Model diff --git a/src/gtkmvc/observable.py b/src/gtkmvc/observable.py index 6699f5b..0ec78fd 100644 --- a/src/gtkmvc/observable.py +++ b/src/gtkmvc/observable.py @@ -1,5 +1,5 @@ # ------------------------------------------------------------------------- -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (C) 2006 by Roberto Cavada # @@ -19,7 +19,7 @@ # Boston, MA 02110, USA.ridge, MA 02139, USA. # # For more information on pygtkmvc see -# or email to the author . +# or email to the author . # ------------------------------------------------------------------------- diff --git a/src/gtkmvc/observer.py b/src/gtkmvc/observer.py index 35d3344..52c3ee2 100644 --- a/src/gtkmvc/observer.py +++ b/src/gtkmvc/observer.py @@ -1,5 +1,5 @@ # ------------------------------------------------------------------------- -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (C) 2006 by Roberto Cavada # @@ -19,8 +19,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . # ------------------------------------------------------------------------- diff --git a/src/gtkmvc/support/__init__.py b/src/gtkmvc/support/__init__.py index ff78e23..a796a37 100644 --- a/src/gtkmvc/support/__init__.py +++ b/src/gtkmvc/support/__init__.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2005 by Roberto Cavada # @@ -18,8 +18,9 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . -__all__ = ["metaclass_base", "metaclasses", "wrappers", "decorators"] +__all__ = ["metaclass_base", "metaclasses", "wrappers", "decorators", + "factories"] diff --git a/src/gtkmvc/support/decorators.py b/src/gtkmvc/support/decorators.py index 0f68f31..3f9d32a 100644 --- a/src/gtkmvc/support/decorators.py +++ b/src/gtkmvc/support/decorators.py @@ -1,5 +1,5 @@ # ------------------------------------------------------------------------- -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (C) 2006 by Roberto Cavada # @@ -19,8 +19,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . # ------------------------------------------------------------------------- diff --git a/src/gtkmvc/support/exceptions.py b/src/gtkmvc/support/exceptions.py index bc2a614..1ca0887 100644 --- a/src/gtkmvc/support/exceptions.py +++ b/src/gtkmvc/support/exceptions.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2005 by Roberto Cavada # @@ -18,7 +18,7 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . diff --git a/src/gtkmvc/support/factories.py b/src/gtkmvc/support/factories.py new file mode 100644 index 0000000..4b67d18 --- /dev/null +++ b/src/gtkmvc/support/factories.py @@ -0,0 +1,86 @@ +# ------------------------------------------------------------------------- +# Author: Roberto Cavada +# +# Copyright (C) 2008 by Roberto Cavada +# +# pygtkmvc is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# pygtkmvc is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110, USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . +# ------------------------------------------------------------------------- + +import new +from gtkmvc import Model +from noconflict import get_noconflict_metaclass + +class ModelFactory (object): + """This factory constructs classes for models. Use it to build + the classes to derive your own models""" + + __memoized = {} + + @staticmethod + def __fix_bases(base_classes, have_mt): + """This function check whether base_classes contains a Model + instance. If not, choose the best fitting class for + model. Furthermore, it makes the list in a cannonical + ordering form in a way that ic can be used as memoization + key""" + fixed = list(base_classes) + contains_model = False + for b in fixed: + if isinstance(fixed, Model): contains_model = True; break + pass + + # adds a model when user is lazy + if not contains_model: + if have_mt: + from gtkmvc.model_mt import ModelMT + fixed.insert(0, ModelMT) + else: fixed.insert(0, Model) + pass + + class ModelFactoryWrap (object): + __metaclass__ = get_noconflict_metaclass(tuple(fixed), (), ()) + def __init__(self, *args, **kwargs): pass + pass + + fixed.append(ModelFactoryWrap) + fixed.sort() + return tuple(fixed) + + @staticmethod + def make(base_classes=(), have_mt=False): + """Use this static method to build a model class that + possibly derives from other classes. If have_mt is True, + then returned class will take into account multi-threading + issues when dealing with observable properties.""" + + good_bc = ModelFactory.__fix_bases(base_classes, have_mt) + print "Base classes are:", good_bc + key = "".join(map(str, good_bc)) + if ModelFactory.__memoized.has_key(key): + return ModelFactory.__memoized[key] + + cls = new.classobj('', good_bc, {'__module__': '__main__', '__doc__': None}) + ModelFactory.__memoized[key] = cls + return cls + + #__ + #make = staticmethod(make) + + pass # end of class diff --git a/src/gtkmvc/support/metaclass_base.py b/src/gtkmvc/support/metaclass_base.py index 771929c..70c5963 100644 --- a/src/gtkmvc/support/metaclass_base.py +++ b/src/gtkmvc/support/metaclass_base.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2005 by Roberto Cavada # @@ -18,8 +18,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . import new @@ -59,7 +59,7 @@ class PropertyMeta (type): Programmers can override basic behaviour for getters or setters simply by defining their getters and setters (see at the names convention above). The customized function can lie everywhere in the user classes hierarchy. - Every overrided function will not be generated by the metaclass. + Every overridden function will not be generated by the metaclass. To supply your own methods is good for few methods, but can result in a very unconfortable way for many methods. In this case you can extend @@ -197,14 +197,14 @@ class PropertyMeta (type): # Override these: def get_getter_source(cls, getter_name, prop_name): - """This must be overrided if you need a different implementation. + """This must be overridden if you need a different implementation. Simply the generated implementation returns the variable name _prop_name""" return "def %s(self): return self._prop_%s" % (getter_name, prop_name) def get_setter_source(cls, setter_name, prop_name): - """This must be overrided if you need a different implementation. + """This must be overridden if you need a different implementation. Simply the generated implementation sets the variable _prop_name""" return "def %s(self, val): self._prop_%s = val" \ % (setter_name, prop_name) diff --git a/src/gtkmvc/support/metaclasses.py b/src/gtkmvc/support/metaclasses.py index 22091f6..34cd3d2 100644 --- a/src/gtkmvc/support/metaclasses.py +++ b/src/gtkmvc/support/metaclasses.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2005 by Roberto Cavada # @@ -18,8 +18,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . from metaclass_base import PropertyMeta import types diff --git a/src/gtkmvc/support/noconflict.py b/src/gtkmvc/support/noconflict.py new file mode 100644 index 0000000..3976bcd --- /dev/null +++ b/src/gtkmvc/support/noconflict.py @@ -0,0 +1,65 @@ +# Author: Michele Simionato +# Copyright (C) 2004 by Michele Simionato +# License: Python License (version not specified) +# Last Updated: 2nd of March 2007, 10:23 GMT +# +# Any serious user of metaclasses has been bitten at least once by +# the infamous metaclass/metatype conflict. This script contains a +# general recipe to solve the problem, as well as some theory and +# some examples. + + +import inspect, types, __builtin__ + +############## preliminary: two utility functions ##################### + +def skip_redundant(iterable, skipset=None): + "Redundant items are repeated items or items in the original skipset." + if skipset is None: skipset = set() + for item in iterable: + if item not in skipset: + skipset.add(item) + yield item + + +def remove_redundant(metaclasses): + skipset = set([types.ClassType]) + for meta in metaclasses: # determines the metaclasses to be skipped + skipset.update(inspect.getmro(meta)[1:]) + return tuple(skip_redundant(metaclasses, skipset)) + +################################################################## +## now the core of the module: two mutually recursive functions ## +################################################################## + +memoized_metaclasses_map = {} + +def get_noconflict_metaclass(bases, left_metas, right_metas): + """Not intended to be used outside of this module, unless you know + what you are doing.""" + # make tuple of needed metaclasses in specified priority order + metas = left_metas + tuple(map(type, bases)) + right_metas + needed_metas = remove_redundant(metas) + + # return existing confict-solving meta, if any + if needed_metas in memoized_metaclasses_map: + return memoized_metaclasses_map[needed_metas] + # nope: compute, memoize and return needed conflict-solving meta + elif not needed_metas: # wee, a trivial case, happy us + meta = type + elif len(needed_metas) == 1: # another trivial case + meta = needed_metas[0] + # check for recursion, can happen i.e. for Zope ExtensionClasses + elif needed_metas == bases: + raise TypeError("Incompatible root metatypes", needed_metas) + else: # gotta work ... + metaname = '_' + ''.join([m.__name__ for m in needed_metas]) + meta = classmaker()(metaname, needed_metas, {}) + memoized_metaclasses_map[needed_metas] = meta + return meta + +def classmaker(left_metas=(), right_metas=()): + def make_class(name, bases, adict): + metaclass = get_noconflict_metaclass(bases, left_metas, right_metas) + return metaclass(name, bases, adict) + return make_class diff --git a/src/gtkmvc/support/test.py b/src/gtkmvc/support/test.py new file mode 100644 index 0000000..f0139ba --- /dev/null +++ b/src/gtkmvc/support/test.py @@ -0,0 +1,4 @@ +class A (object): + a = 10 + pass + diff --git a/src/gtkmvc/support/utils.py b/src/gtkmvc/support/utils.py index c174de8..02725f2 100644 --- a/src/gtkmvc/support/utils.py +++ b/src/gtkmvc/support/utils.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (c) 2007 by Roberto Cavada # @@ -18,8 +18,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . diff --git a/src/gtkmvc/support/wrappers.py b/src/gtkmvc/support/wrappers.py index c567a62..c50a79b 100644 --- a/src/gtkmvc/support/wrappers.py +++ b/src/gtkmvc/support/wrappers.py @@ -1,5 +1,5 @@ # ------------------------------------------------------------------------- -# Author: Roberto Cavada +# Author: Roberto Cavada # # Copyright (C) 2006 by Roberto Cavada # @@ -19,8 +19,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . # ------------------------------------------------------------------------- diff --git a/src/gtkmvc/view.py b/src/gtkmvc/view.py index 220fbd0..8f485dc 100644 --- a/src/gtkmvc/view.py +++ b/src/gtkmvc/view.py @@ -1,4 +1,4 @@ -# Author: Roberto Cavada +# Author: Roberto Cavada # Modified by: Guillaume Libersat # # Copyright (c) 2005 by Roberto Cavada @@ -20,8 +20,8 @@ # Boston, MA 02110, USA. # # For more information on pygtkmvc see -# or email to the author Roberto Cavada . -# Please report bugs to . +# or email to the author Roberto Cavada . +# Please report bugs to . import gtk.glade