diff --git a/mvc/glade/foo.glade b/mvc/glade/foo.glade new file mode 100644 index 0000000..89979e6 --- /dev/null +++ b/mvc/glade/foo.glade @@ -0,0 +1,130 @@ + + + + + + + True + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + label2 + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + + + 0 + True + True + + + + + + True + True + button1 + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + + + + + + True + <b>frame1</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + + + diff --git a/mvc/glade/main.glade b/mvc/glade/main.glade new file mode 100644 index 0000000..87e1358 --- /dev/null +++ b/mvc/glade/main.glade @@ -0,0 +1,588 @@ + + + + + + + mainW + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + + True + False + 0 + + + + True + GTK_PACK_DIRECTION_LTR + GTK_PACK_DIRECTION_LTR + + + + True + _File + True + + + + + + + True + gtk-new + True + + + + + + + True + gtk-open + True + + + + + + + True + gtk-save + True + + + + + + + True + gtk-save-as + True + + + + + + + True + + + + + + True + Recent files + True + + + + + + + True + + + + + + True + gtk-quit + True + + + + + + + + + + + True + _Edit + True + + + + + + + True + gtk-cut + True + + + + + + + True + gtk-copy + True + + + + + + + True + gtk-paste + True + + + + + + + True + gtk-delete + True + + + + + + + True + + + + + + True + gtk-preferences + True + + + + + + + + + + + True + _Catalog + True + + + + + + + True + Add CD/DVD + True + + + + + + + + True + Add Directory + True + + + + + + + + + + + True + _View + True + + + + + + + True + Toolbar + True + False + + + + + + + True + Status bar + True + False + + + + + + + + + + + True + _Help + True + + + + + + + True + gtk-about + True + + + + + + + + + + 0 + False + False + + + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + Create new catalog + gtk-new + True + True + False + + + + False + True + + + + + + True + Open catalog file + gtk-open + True + True + False + + + + False + True + + + + + + True + Save catalog + gtk-save + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Add CD/DVD to catalog + Add CD + True + gtk-cdrom + True + True + False + + + + False + True + + + + + + True + Find file + gtk-find + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Quit pyGTKtalog + gtk-quit + True + True + False + + + + False + True + + + + + 0 + False + False + + + + + + True + True + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + True + False + True + False + False + False + + + + + + + True + False + + + + + + True + True + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + True + False + False + False + + + + + + + True + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + GTK_JUSTIFY_LEFT + GTK_WRAP_NONE + False + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + True + True + + + + + False + True + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + False + + + 0 + True + True + + + + + + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.10000000149 + PANGO_ELLIPSIZE_NONE + + + 0 + False + False + + + + + 0 + False + True + + + + + + + diff --git a/mvc/gtkmvc/__init__.py b/mvc/gtkmvc/__init__.py new file mode 100644 index 0000000..3e4e252 --- /dev/null +++ b/mvc/gtkmvc/__init__.py @@ -0,0 +1,48 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . + + +__all__ = ["model", "view", "controller", "observable", "observer"] + +__version = (1,0,0) + +from model import Model, TreeStoreModel, ListStoreModel, TextBufferModel +from model_mt import ModelMT +from controller import Controller +from view import View +from observer import Observer +import observable + + +def get_version(): return __version + +def require(ver): + if isinstance(ver, str): ver = ver.split(".") + ver = tuple(map(int, ver)) + + if get_version() < ver: + raise AssertionError("gtkmvc required version '%s', found '%s'"\ + % (ver, get_version())) + pass + return + + diff --git a/mvc/gtkmvc/controller.py b/mvc/gtkmvc/controller.py new file mode 100644 index 0000000..68b481f --- /dev/null +++ b/mvc/gtkmvc/controller.py @@ -0,0 +1,46 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . + + +from gtkmvc.observer import Observer + +class Controller (Observer): + """We put all of our gtk signal handlers into a class. This lets us bind + all of them at once, because their names are in the class dict. + This class automatically register its instances as observers into the + corresponding model. + Also, when a view is created, the view calls method register_view, + which can be oveloaded in order to connect signals and perform other + specific operation""" + + def __init__(self, model): + Observer.__init__(self, model) + + self.view = None + return + + def register_view(self, view): + assert(self.view is None) + self.view = view + return + + pass # end of class Controller diff --git a/mvc/gtkmvc/model.py b/mvc/gtkmvc/model.py new file mode 100644 index 0000000..54434bd --- /dev/null +++ b/mvc/gtkmvc/model.py @@ -0,0 +1,316 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . + +import support.metaclasses +from support.wrappers import ObsWrapperBase +from observable import Signal + + +class Model (object): + """This class is the application model base class. + It handles a set of observable properties which you are interested + in showing by one ore more view - via one or more observers of course. + The mechanism is the following: + 1. You are interested in showing a set of model property, that you can + declare in the __properties__ member map. + 2. You define one or more observers that observe one or more properties + you registered. When someone changes a property value the model notifies + the changing to each listening controller. The property-observer[s] + association is given by the implicit rule in observers method names: if + you want the model notified the changing event of the property 'p' + you must define the method called 'property_p_change_notification' in + each listening observer class. + Notice that tipically 'controllers' implement the observer pattern. + The notification method gets the + emitting model, the old value for the property and the new one. + Properties functionalities are automatically provided by the + ObservablePropertyMeta meta-class.""" + + __metaclass__ = support.metaclasses.ObservablePropertyMeta + __properties__ = {} # override this + + def __init__(self): + object.__init__(self) + self.__observers = [] + # keys are properties names, values are methods inside the observer: + self.__value_notifications = {} + self.__instance_notif_before = {} + self.__instance_notif_after = {} + self.__signal_notif = {} + + for key in (self.__properties__.keys() + self.__derived_properties__.keys()): + self.register_property(key) + pass + + return + + def register_property(self, name): + """Registers an existing property to be monitored, and sets up + notifiers for notifications""" + if not self.__value_notifications.has_key(name): + self.__value_notifications[name] = [] + pass + + # registers observable wrappers + prop = getattr(self, "_prop_%s" % name) + + if isinstance(prop, ObsWrapperBase): + prop.__set_model__(self, name) + + if isinstance(prop, Signal): + if not self.__signal_notif.has_key(name): + self.__signal_notif[name] = [] + pass + pass + else: + if not self.__instance_notif_before.has_key(name): + self.__instance_notif_before[name] = [] + pass + if not self.__instance_notif_after.has_key(name): + self.__instance_notif_after[name] = [] + pass + pass + pass + + return + + + def register_observer(self, observer): + if observer in self.__observers: return # not already registered + + self.__observers.append(observer) + for key in (self.__properties__.keys() + self.__derived_properties__.keys()): + self.__add_observer_notification(observer, key) + pass + + return + + + def unregister_observer(self, observer): + if observer not in self.__observers: return + + for key in (self.__properties__.keys() + self.__derived_properties__.keys()): + self.__remove_observer_notification(observer, key) + pass + + self.__observers.remove(observer) + return + + + def _reset_property_notification(self, prop_name): + """Called when it has done an assignment that changes the type + of a property, so it must be unregistered and registered again""" + + self.register_property(prop_name) + + for observer in self.__observers: + self.__remove_observer_notification(observer, prop_name) + self.__add_observer_notification(observer, prop_name) + pass + return + + + def __add_observer_notification(self, observer, prop_name): + """Searches in the observer for any possible listener, and + stores the notification methods to be called later""" + + method_name = "property_%s_value_change" % prop_name + if hasattr(observer, method_name): + method = getattr(observer, method_name) + if method not in self.__value_notifications[prop_name]: + list.append(self.__value_notifications[prop_name], method) + pass + pass + + # is it a signal? + orig_prop = getattr(self, "_prop_%s" % prop_name) + if isinstance(orig_prop, Signal): + method_name = "property_%s_signal_emit" % prop_name + if hasattr(observer, method_name): + method = getattr(observer, method_name) + if method not in self.__signal_notif[prop_name]: + list.append(self.__signal_notif[prop_name], method) + pass + pass + pass + + # is it an instance change notification type? + elif isinstance(orig_prop, ObsWrapperBase): + method_name = "property_%s_before_change" % prop_name + if hasattr(observer, method_name): + method = getattr(observer, method_name) + if method not in self.__instance_notif_before[prop_name]: + list.append(self.__instance_notif_before[prop_name], method) + pass + pass + + method_name = "property_%s_after_change" % prop_name + if hasattr(observer, method_name): + method = getattr(observer, method_name) + if method not in self.__instance_notif_after[prop_name]: + list.append(self.__instance_notif_after[prop_name], method) + pass + pass + pass + + return + + + def __remove_observer_notification(self, observer, prop_name): + if self.__value_notifications.has_key(prop_name): + method_name = "property_%s_value_change" % prop_name + if hasattr(observer, method_name): + method = getattr(observer, method_name) + if method in self.__value_notifications[prop_name]: + self.__value_notifications[prop_name].remove(method) + pass + pass + pass + + + orig_prop = getattr(self, "_prop_%s" % prop_name) + # is it a signal? + if isinstance(orig_prop, Signal): + method_name = "property_%s_signal_emit" % prop_name + if hasattr(observer, method_name): + method = getattr(observer, method_name) + if method in self.__signal_notif[prop_name]: + self.__signal_notif[prop_name].remove(method) + pass + pass + pass + + # is it an instance change notification type? + elif isinstance(orig_prop, ObsWrapperBase): + if self.__instance_notif_before.has_key(prop_name): + method_name = "property_%s_before_change" % prop_name + if hasattr(observer, method_name): + method = getattr(observer, method_name) + if method in self.__instance_notif_before[prop_name]: + self.__instance_notif_before[prop_name].remove(method) + pass + pass + pass + + if self.__instance_notif_after.has_key(prop_name): + method_name = "property_%s_after_change" % prop_name + if hasattr(observer, method_name): + method = getattr(observer, method_name) + if method in self.__instance_notif_after[prop_name]: + self.__instance_notif_after[prop_name].remove(method) + pass + pass + pass + pass + + return + + + def __notify_observer__(self, observer, method, *args, **kwargs): + """This can be overridden by derived class in order to call + the method in a different manner (for example, in + multithreading, or a rpc, etc.) This implementation simply + calls the given method with the given arguments""" + return method(*args, **kwargs) + + + # ---------- Notifiers: + + def notify_property_value_change(self, prop_name, old, new): + assert(self.__value_notifications.has_key(prop_name)) + for method in self.__value_notifications[prop_name] : + self.__notify_observer__(method.im_self, method, + self, old, new) # notifies the change + pass + return + + def notify_method_before_change(self, prop_name, instance, meth_name, + args, kwargs): + assert(self.__instance_notif_before.has_key(prop_name)) + for method in self.__instance_notif_before[prop_name] : + self.__notify_observer__(method.im_self, method, self, instance, + meth_name, args, kwargs) # notifies the change + pass + return + + def notify_method_after_change(self, prop_name, instance, meth_name, + res, args, kwargs): + assert(self.__instance_notif_after.has_key(prop_name)) + for method in self.__instance_notif_after[prop_name] : + self.__notify_observer__(method.im_self, method, self, instance, + meth_name, res, args, kwargs) # notifies the change + pass + return + + def notify_signal_emit(self, prop_name, args, kwargs): + assert(self.__signal_notif.has_key(prop_name)) + for method in self.__signal_notif[prop_name] : + self.__notify_observer__(method.im_self, method, self, + args, kwargs) # notifies the signal emit + pass + return + + + pass # end of class Model +# ---------------------------------------------------------------------- + + + +import gtk +# ---------------------------------------------------------------------- +class TreeStoreModel (Model, gtk.TreeStore): + """Use this class as base class for your model derived by + gtk.TreeStore""" + __metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta + + def __init__(self, column_type, *args): + Model.__init__(self) + gtk.TreeStore.__init__(self, column_type, *args) + return + pass + + +# ---------------------------------------------------------------------- +class ListStoreModel (Model, gtk.ListStore): + """Use this class as base class for your model derived by + gtk.ListStore""" + __metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta + + def __init__(self, column_type, *args): + Model.__init__(self) + gtk.ListStore.__init__(self, column_type, *args) + return + pass + + +# ---------------------------------------------------------------------- +class TextBufferModel (Model, gtk.TextBuffer): + """Use this class as base class for your model derived by + gtk.TextBuffer""" + __metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta + + def __init__(self, table=None): + Model.__init__(self) + gtk.TextBuffer.__init__(self, table) + return + pass + diff --git a/mvc/gtkmvc/model_mt.py b/mvc/gtkmvc/model_mt.py new file mode 100644 index 0000000..07ac6ca --- /dev/null +++ b/mvc/gtkmvc/model_mt.py @@ -0,0 +1,119 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . + + +from gtkmvc.model import Model +import support.metaclasses + +try: import threading as _threading +except ImportError: import dummy_threading as _threading + +import gobject +if hasattr(gobject, "threads_init"): gobject.threads_init() +else: import gtk; gtk.threads_init() + + +class ModelMT (Model): + """A base class for models whose observable properties can be + changed by threads different than gtk main thread. Notification is + performed by exploiting the gtk idle loop only if needed, + otherwise the standard notification system (direct method call) is + used.""" + + def __init__(self): + Model.__init__(self) + self.__observer_threads = {} + return + + def register_observer(self, observer): + Model.register_observer(self, observer) + self.__observer_threads[observer] = _threading.currentThread() + return + + def unregister_observer(self, observer): + Model.unregister_observer(self, observer) + del self.__observer_threads[observer] + return + + # ---------- Notifiers: + + def __notify_observer__(self, observer, method, *args, **kwargs): + """This makes a call either through the gtk.idle list or a + direct method call depending whether the caller's thread is + different from the observer's thread""" + + assert self.__observer_threads.has_key(observer) + if _threading.currentThread() == self.__observer_threads[observer]: + # standard call + return Model.__notify_observer__(self, observer, method, + args, kwargs) + + # multi-threading call + gobject.idle_add(self.__idle_callback, observer, method, args, kwargs) + return + + def __idle_callback(self, observer, method, args, kwargs): + method(*args, **kwargs) + return False + + + pass # end of class + + +import gtk +# ---------------------------------------------------------------------- +class TreeStoreModelMT (ModelMT, gtk.TreeStore): + """Use this class as base class for your model derived by + gtk.TreeStore""" + __metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta + + def __init__(self, column_type, *args): + ModelMT.__init__(self) + gtk.TreeStore.__init__(self, column_type, *args) + return + pass + + +# ---------------------------------------------------------------------- +class ListStoreModelMT (ModelMT, gtk.ListStore): + """Use this class as base class for your model derived by + gtk.ListStore""" + __metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta + + def __init__(self, column_type, *args): + ModelMT.__init__(self) + gtk.ListStore.__init__(self, column_type, *args) + return + pass + + +# ---------------------------------------------------------------------- +class TextBufferModelMT (ModelMT, gtk.TextBuffer): + """Use this class as base class for your model derived by + gtk.TextBuffer""" + __metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta + + def __init__(self, table=None): + ModelMT.__init__(self) + gtk.TextBuffer.__init__(self, table) + return + pass diff --git a/mvc/gtkmvc/observable.py b/mvc/gtkmvc/observable.py new file mode 100644 index 0000000..f6ac190 --- /dev/null +++ b/mvc/gtkmvc/observable.py @@ -0,0 +1,68 @@ +# ------------------------------------------------------------------------- +# Author: Roberto Cavada +# +# Copyright (C) 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author . +# ------------------------------------------------------------------------- + + +from support import decorators +from support.wrappers import ObsWrapperBase + +# ---------------------------------------------------------------------- +class Observable (ObsWrapperBase): + def __init__(self): + ObsWrapperBase.__init__(self) + return + pass # end of class + + +@decorators.good_decorator +def observed(func): + """Use this decorator to make your class methods observable. + + Your observer will receive at most two notifications: + - property__before_change + - property__after_change + + """ + + def wrapper(*args, **kwargs): + self = args[0] + assert(isinstance(self, Observable)) + + self._notify_method_before(self, func.__name__, args, kwargs) + res = func(*args, **kwargs) + self._notify_method_after(self, func.__name__, res, args, kwargs) + return res + return wrapper + + +# ---------------------------------------------------------------------- +class Signal (Observable): + """Base class for signals properties""" + def __init__(self): + Observable.__init__(self) + return + + def emit(self, *args, **kwargs): + return self.__get_model__().notify_signal_emit( + self.__get_prop_name__(), args, kwargs) + pass # end of class + diff --git a/mvc/gtkmvc/observer.py b/mvc/gtkmvc/observer.py new file mode 100644 index 0000000..ac35f16 --- /dev/null +++ b/mvc/gtkmvc/observer.py @@ -0,0 +1,56 @@ +# ------------------------------------------------------------------------- +# Author: Roberto Cavada +# +# Copyright (C) 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . +# ------------------------------------------------------------------------- + + +class Observer (object): + """Use this class as base class of all observers""" + + def __init__(self, model=None): + self.model = None + self.register_model(model) + return + + def register_model(self, model): + self.unregister_model() + self.model = model + if self.model: self.model.register_observer(self) + return + + def unregister_model(self): + if self.model: + self.model.unregister_observer(self) + self.model = None + pass + return + + def __del__(self): + self.unregister_model() + return + + def get_model(self): return self.model + + pass # end of class + + + diff --git a/mvc/gtkmvc/support/__init__.py b/mvc/gtkmvc/support/__init__.py new file mode 100644 index 0000000..86ec566 --- /dev/null +++ b/mvc/gtkmvc/support/__init__.py @@ -0,0 +1,24 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . + + +__all__ = ["metaclass_base", "metaclasses", "wrappers", "decorators"] diff --git a/mvc/gtkmvc/support/decorators.py b/mvc/gtkmvc/support/decorators.py new file mode 100644 index 0000000..fef7184 --- /dev/null +++ b/mvc/gtkmvc/support/decorators.py @@ -0,0 +1,43 @@ +# ------------------------------------------------------------------------- +# Author: Roberto Cavada +# +# Copyright (C) 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . +# ------------------------------------------------------------------------- + + + +# This file contains decorators to be used (privately) by other parts +# of the framework + +def good_decorator(decorator): + """This decorator makes decorators behave well wrt to decorated + functions names, doc, etc.""" + def new_decorator(f): + g = decorator(f) + g.__name__ = f.__name__ + g.__doc__ = f.__doc__ + g.__dict__.update(f.__dict__) + return g + + new_decorator.__name__ = decorator.__name__ + new_decorator.__doc__ = decorator.__doc__ + new_decorator.__dict__.update(decorator.__dict__) + return new_decorator diff --git a/mvc/gtkmvc/support/metaclass_base.py b/mvc/gtkmvc/support/metaclass_base.py new file mode 100644 index 0000000..c9a2435 --- /dev/null +++ b/mvc/gtkmvc/support/metaclass_base.py @@ -0,0 +1,244 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . + + +import new +import re +import types + +import gtkmvc.support.wrappers as wrappers + + +# ---------------------------------------------------------------------- + +VERBOSE_LEVEL = 5 + +class PropertyMeta (type): + """This is a meta-class that provides auto-property support. + The idea is to allow programmers to define some properties which + will be automatically connected to auto-generated code which handles + access to those properties. + How can you use this meta-class? + First, '__metaclass__ = PropertyMeta' must be class member of the class + you want to make the automatic properties handling. + Second, '__properties__' must be a map containing the properties names + as keys, values will be initial values for properties. + That's all: after the instantiation, your class will contain all properties + you named inside '__properties__'. Each of them will be also associated + to a couple of automatically-generated functions which get and set the + property value inside a generated member variable. + About names: suppose the property is called 'x'. The generated variable + (which keeps the real value of the property x) is called _prop_x. + The getter is called get_prop_x(self), and the setter is called + 'set_prop_x(self, value)'. + + Customization: + The base implementation of getter is to return the value stored in the + variable associate to the property. The setter simply sets its value. + 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. + + 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 + the meta-class, and override methods get_[gs]etter_source with your + implementation (this can be probably made better). + An example is provided in meta-class PropertyMetaVerbose below. + """ + + def __init__(cls, name, bases, dict): + """class constructor""" + properties = {} + type.__init__(cls, name, bases, dict) + + props = getattr(cls, '__properties__', {}) + setattr(cls, '__derived_properties__', {}) + der_props = getattr(cls, '__derived_properties__') + + # Calculates derived properties: + for base in bases: + maps = ( getattr(base, '__properties__', {}), + getattr(base, '__derived_properties__', {}) ) + for map in maps: + for p in map.keys(): + if not props.has_key(p) and not der_props.has_key(p): + der_props[p] = map[p] + pass + pass + pass + pass + + # Generates code for all properties (but not for derived props): + props = getattr(cls, '__properties__', {}) + for prop in props.keys(): + type(cls).__create_prop_accessors__(cls, prop, props[prop]) + pass + + return + + + def __msg__(cls, msg, level): + """if level is less or equal to VERBOSE_LEVEL, ths message will + be printed""" + if level <= VERBOSE_LEVEL: print msg + return + + def __create_prop_accessors__(cls, prop_name, default_val): + """Private method that creates getter and setter, and the + corresponding property""" + getter_name = "get_prop_%s" % prop_name + setter_name = "set_prop_%s" % prop_name + + members_names = cls.__dict__.keys() + + # checks if accessors are already defined: + if getter_name not in members_names: + src = type(cls).get_getter_source(cls, getter_name, prop_name) + code = type(cls).get_func_code_from_func_src(cls, src) + type(cls).add_method_from_func_code(cls, getter_name, code) + else: + cls.__msg__("Warning: Custom member '%s' overloads generated accessor of property '%s'" \ + % (getter_name, prop_name), 2) + pass + + if setter_name not in members_names: + src = type(cls).get_setter_source(cls, setter_name, prop_name) + code = type(cls).get_func_code_from_func_src(cls, src) + type(cls).add_method_from_func_code(cls, setter_name, code) + else: + cls.__msg__("Warning: Custom member '%s' overloads generated accessor of property '%s'" \ + % (setter_name, prop_name), 2) + pass + + prop = property(getattr(cls, getter_name), getattr(cls, setter_name)) + + if prop_name in members_names: + cls.__msg__("Warning: automatic property builder is overriding property %s in class %s" \ + % (prop_name, cls.__name__), 2) + pass + setattr(cls, prop_name, prop) + + varname = "_prop_%s" % prop_name + if not varname in members_names: cls.__create_property(varname, default_val) + else: cls.__msg__("Warning: automatic property builder found a possible clashing for variable %s inside class %s" \ + % (varname, cls.__name__), 2) + return + + def __create_property(cls, name, default_val): + setattr(cls, name, cls.create_value(name, default_val)) + return + + def create_value(cls, prop_name, val, model=None): + """This is used to create a value to be assigned to a + property. Depending on the type of the value, different values + are created and returned. For example, for a list, a + ListWrapper is created to wrap it, and returned for the + assignment. model is different from model when the value is + changed (a model exists). Otherwise, during property creation + model is None""" + + if isinstance(val, tuple): + # this might be a class instance to be wrapped + if len(val) == 3 and \ + isinstance(val[1], val[0]) and \ + (isinstance(val[2], tuple) or isinstance(val[2], list)): + res = wrappers.ObsUserClassWrapper(val[1], val[2]) + if model: res.__set_model__(model, prop_name) + return res + pass + + elif isinstance(val, list): + res = wrappers.ObsListWrapper(val) + if model: res.__set_model__(model, prop_name) + return res + + elif isinstance(val, dict): + res = wrappers.ObsMapWrapper(val) + if model: res.__set_model__(model, prop_name) + return res + + return val + + # Services: + def add_method_from_func_code(cls, meth_name, code): + """Use this to add a code that is a new method for the class""" + + func = new.function(code, globals(), meth_name) + meth = new.instancemethod(func, cls, cls.__name__) + setattr(cls, meth_name, func) + return + + def get_func_code_from_func_src(cls, source): + """Public service that provided code object from function source""" + m = re.compile("def\s+(\w+)\s*\(.*\):").match(source) + if m is None: raise BadFuncSource(source) + + func_name = m.group(1) + exec source + code = eval("%s.func_code" % func_name) + return code + + + # Override these: + def get_getter_source(cls, getter_name, prop_name): + """This must be overrided 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. + Simply the generated implementation sets the variable _prop_name""" + return "def %s(self, val): self._prop_%s = val" \ + % (setter_name, prop_name) + + pass # end of class +# ---------------------------------------------------------------------- + + +# What follows underneath is a set of examples of usage + +## class PropertyMetaVerbose (PropertyMeta): +## """An example of customization""" +## def get_getter_source(cls, getter_name, prop_name): +## return "def %s(self): print 'Calling %s!'; return self._prop_%s" \ +## % (getter_name, getter_name, prop_name) + +## def get_setter_source(cls, setter_name, prop_name): +## return "def %s(self, val): print 'Calling %s!'; self._prop_%s = val;" \ +## % (setter_name, setter_name, prop_name) +## pass #end of class +# ---------------------------------------------------------------------- + +## class User: +## """An example of usage""" +## __metaclass__ = PropertyMetaVerbose +## __properties__ = {'x':10, 'y':20} + +## def __init__(self): +## print self.x # x is 10 +## self.x = self.y + 10 # x is now 30 +## return +## pass +# ---------------------------------------------------------------------- diff --git a/mvc/gtkmvc/support/metaclasses.py b/mvc/gtkmvc/support/metaclasses.py new file mode 100644 index 0000000..e594dac --- /dev/null +++ b/mvc/gtkmvc/support/metaclasses.py @@ -0,0 +1,54 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . + +from metaclass_base import PropertyMeta +import types + + +class ObservablePropertyMeta (PropertyMeta): + """Classes instantiated by this meta-class must provide a method named + notify_property_change(self, prop_name, old, new)""" + def __init__(cls, name, bases, dict): + PropertyMeta.__init__(cls, name, bases, dict) + return + + def get_setter_source(cls, setter_name, prop_name): + return """def %(setter)s(self, val): + old = self._prop_%(prop)s + self._prop_%(prop)s = type(self).create_value('%(prop)s', val, self) + if type(old) != type(self._prop_%(prop)s): self._reset_property_notification('%(prop)s') + self.notify_property_value_change('%(prop)s', old, val) + return +""" % {'setter':setter_name, 'prop':prop_name} + + pass #end of class + + + +try: + from gobject import GObjectMeta + class ObservablePropertyGObjectMeta (ObservablePropertyMeta, GObjectMeta): pass +except: + class ObservablePropertyGObjectMeta (ObservablePropertyMeta): pass + pass + + diff --git a/mvc/gtkmvc/support/wrappers.py b/mvc/gtkmvc/support/wrappers.py new file mode 100644 index 0000000..0f362ee --- /dev/null +++ b/mvc/gtkmvc/support/wrappers.py @@ -0,0 +1,152 @@ +# ------------------------------------------------------------------------- +# Author: Roberto Cavada +# +# Copyright (C) 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . +# ------------------------------------------------------------------------- + + +import new + + +# ---------------------------------------------------------------------- +class ObsWrapperBase (object): + def __init__(self): + self.__prop_name = None + self.__gtkmvc_model = None + return + + def __set_model__(self, model, prop_name): + self.__prop_name = prop_name + self.__gtkmvc_model = model + return + + def __get_prop_name__(self): return self.__prop_name + def __get_model__(self): return self.__gtkmvc_model + + def _notify_method_before(self, instance, name, args, kwargs): + self.__get_model__().notify_method_before_change(self.__prop_name, + instance, + name, args, kwargs) + return + + def _notify_method_after(self, instance, name, res_val, args, kwargs): + self.__get_model__().notify_method_after_change(self.__prop_name, + instance, + name, res_val, args, kwargs) + return + + pass + + +# ---------------------------------------------------------------------- +class ObsWrapper (ObsWrapperBase): + + def __init__(self, obj, method_names): + ObsWrapperBase.__init__(self) + + self._obj = obj + self.__doc__ = obj.__doc__ + + for name in method_names: + if hasattr(self._obj, name) and not hasattr(self, name): + src = self.__get_wrapper_code(name) + exec src + + code = eval("%s.func_code" % name) + func = new.function(code, globals()) + meth = new.instancemethod(func, self, type(self).__name__) + setattr(self, name, meth) + pass + pass + + return + + def __get_wrapper_code(self, name): + return """def %(name)s(self, *args, **kwargs): + self._notify_method_before(self._obj, "%(name)s", args, kwargs) + res = self._obj.%(name)s(*args, **kwargs) + self._notify_method_after(self._obj, "%(name)s", res, args, kwargs) + return res""" % {'name' : name} + + # For all fall backs + def __getattr__(self, name): return self._obj.__getattr__(name) + def __repr__(self): return self._obj.__repr__() + def __str__(self): return self._obj.__str__() + + pass #end of class + + +# ---------------------------------------------------------------------- +class ObsSeqWrapper (ObsWrapper): + def __init__(self, obj, method_names): + ObsWrapper.__init__(self, obj, method_names) + return + + def __setitem__(self, key, val): + + self._notify_method_before(self._obj, "__setitem__", (key,val), {}) + res = self._obj.__setitem__(key, val) + self._notify_method_after(self._obj, res, "__setitem__", (key,val), {}) + return res + + def __delitem__(self, key): + self._notify_method_before(self._obj, "__delitem__", (key,), {}) + res = self._obj.__delitem__(key) + self._notify_method_after(self._obj, res, "__delitem__", (key,), {}) + return res + + + def __getitem__(self, key): + return self._obj.__getitem__(key) + + pass #end of class + + +# ---------------------------------------------------------------------- +class ObsMapWrapper (ObsSeqWrapper): + def __init__(self, m): + methods = ("clear", "pop", "popitem", "update", + "setdefault") + ObsSeqWrapper.__init__(self, m, methods) + return + pass #end of class + + +# ---------------------------------------------------------------------- +class ObsListWrapper (ObsSeqWrapper): + def __init__(self, l): + methods = ("append", "extend", "insert", + "pop", "remove", "reverse", "sort") + ObsSeqWrapper.__init__(self, l, methods) + return + pass #end of class + + + +# ---------------------------------------------------------------------- +class ObsUserClassWrapper (ObsWrapper): + def __init__(self, user_class_instance, obs_method_names): + ObsWrapper.__init__(self, user_class_instance, obs_method_names) + return + pass #end of class + + + diff --git a/mvc/gtkmvc/view.py b/mvc/gtkmvc/view.py new file mode 100644 index 0000000..94147b1 --- /dev/null +++ b/mvc/gtkmvc/view.py @@ -0,0 +1,158 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author Roberto Cavada . +# Please report bugs to . + + +import gtk.glade +from controller import Controller +import types + +class View (object): + + def __init__(self, controller, glade_filename=None, + glade_top_widget_name=None, parent_view=None, register=True): + """If register is False you *must* call 'controller.register_view(self)' + from the derived class constructor (i.e. registration is delayed) + If filename is not given (or None) all following parameters must be + not given (or None). In that case widgets must be connected manually. + glade_top_widget_name can be either a string name or list of names.""" + self.manualWidgets = {} + self.xmlWidgets = [] + + if (( type(glade_top_widget_name) == types.StringType) + or (glade_top_widget_name is None) ): + wids = (glade_top_widget_name,) + else: wids = glade_top_widget_name # Already a list or tuple + + if (glade_filename is not None): + for i in range(0,len(wids)): + self.xmlWidgets.append(gtk.glade.XML(glade_filename, wids[i])) + pass + pass + + # top widget list or singleton: + if (glade_top_widget_name is not None): + if len(wids) > 1: + self.m_topWidget = [] + for i in range(0, len(wids)): + self.m_topWidget.append(self[wids[i]]) + pass + else: self.m_topWidget = self[wids[0]] + else: self.m_topWidget = None + + if (glade_filename is not None): self.autoconnect_signals(controller) + if (register): controller.register_view(self) + if (not parent_view is None): self.set_parent_view(parent_view) + return + + # Gives us the ability to do: view['widget_name'].action() + # Returns None if no widget name has been found. + def __getitem__(self, key): + wid = None + for xml in self.xmlWidgets: + wid = xml.get_widget(key) + if wid is not None: break + pass + + if (wid is None): + # try with manually-added widgets: + if (self.manualWidgets.has_key(key)): + wid = self.manualWidgets[key] + pass + pass + return wid + + # You can also add a single widget: + def __setitem__(self, key, wid): + self.manualWidgets[key] = wid + if (self.m_topWidget is None): self.m_topWidget = wid + return + + # performs Controller's signals auto-connection: + def autoconnect_signals(self, controller): + dict = {} + member_names = dir(controller) + for name in member_names: + method = getattr(controller, name) + if (not callable(method)): continue + assert(not dict.has_key(name)) # not already connected! + dict[name] = method + pass + + for xml in self.xmlWidgets: xml.signal_autoconnect(dict) + return + + def show(self): + ret = True + top = self.get_top_widget() + if type(top) in (types.ListType, types.TupleType): + for t in top: + if t is not None: ret = ret and t.show() + pass + elif (top is not None): ret = top.show_all() + else: ret = False + return ret + + + def hide(self): + top = self.get_top_widget() + if type(top) in (types.ListType, types.TupleType): + for t in top: + if t is not None: t.hide_all() + pass + elif top is not None: top.hide_all() + return + + # Returns the top-level widget, or a list of top widgets + def get_top_widget(self): + return self.m_topWidget + + + # Set parent view: + def set_parent_view(self, parent_view): + top = self.get_top_widget() + if type(top) in (types.ListType, types.TupleType): + for t in top: + if t is not None: + t.set_transient_for(parent_view.get_top_widget()) + pass + pass + elif (top is not None): + top.set_transient_for(parent_view.get_top_widget()) + pass + + return + + # Set the transient for the view: + def set_transient(self, transient_view): + top = self.get_top_widget() + if type(top) in (types.ListType, types.TupleType): + for t in top: + if t is not None: + transient_view.get_top_widget().set_transient_for(t) + pass + pass + elif (top is not None): + transient_view.get_top_widget().set_transient_for(top) + pass + return + + pass # end of class View diff --git a/mvc/img/notavail.gif b/mvc/img/notavail.gif new file mode 100644 index 0000000..e60111e Binary files /dev/null and b/mvc/img/notavail.gif differ diff --git a/mvc/main_window.py b/mvc/main_window.py new file mode 100644 index 0000000..41dbef9 --- /dev/null +++ b/mvc/main_window.py @@ -0,0 +1,24 @@ +# This Python file uses the following encoding: utf-8 +def setup_path(): + """Sets up the python include paths to include src""" + import os.path; import sys + + if sys.argv[0]: + top_dir = os.path.dirname(os.path.abspath(sys.argv[0])) + sys.path = [os.path.join(top_dir, "src")] + sys.path + pass + return + +if __name__ == "__main__": + setup_path() + + from models.m_main import MainModel + from controllers.c_main import MainController + from views.v_main import MainView + m = MainModel() + c = MainController(m) + v = MainView(c) + + import gtk + gtk.main() + pass diff --git a/mvc/pixmaps/mainicon.png b/mvc/pixmaps/mainicon.png new file mode 100644 index 0000000..55a22b1 Binary files /dev/null and b/mvc/pixmaps/mainicon.png differ diff --git a/mvc/pixmaps/mainicon.xcf b/mvc/pixmaps/mainicon.xcf new file mode 100644 index 0000000..06a6164 Binary files /dev/null and b/mvc/pixmaps/mainicon.xcf differ diff --git a/mvc/pixmaps/mainicon2.xcf b/mvc/pixmaps/mainicon2.xcf new file mode 100644 index 0000000..7e9949d Binary files /dev/null and b/mvc/pixmaps/mainicon2.xcf differ diff --git a/mvc/pyGTKtalog b/mvc/pyGTKtalog new file mode 100755 index 0000000..736f295 --- /dev/null +++ b/mvc/pyGTKtalog @@ -0,0 +1,6 @@ +#!/bin/sh +# Simple wraper to launch python application from desired place. +cd ~/Python/pyGTKtalog/mvc +#export PYTHONPATH="$PYTHONPATH:/usr/lib/gajim" +#exec python -OO pyGTKtalog.py $@ +exec python main_window.py $@ diff --git a/mvc/src/__init__.py b/mvc/src/__init__.py new file mode 100644 index 0000000..8349638 --- /dev/null +++ b/mvc/src/__init__.py @@ -0,0 +1,3 @@ + + +__all__ = ["models", "views", "controllers", "utils"] diff --git a/mvc/src/controllers/__init__.py b/mvc/src/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mvc/src/controllers/c_main.py b/mvc/src/controllers/c_main.py new file mode 100644 index 0000000..b4afd2f --- /dev/null +++ b/mvc/src/controllers/c_main.py @@ -0,0 +1,38 @@ +# This Python file uses the following encoding: utf-8 + +import utils._importer +import utils.globals +from gtkmvc import Controller +import gtk + +class MainController(Controller): + """Kontroler głównego okna aplikacji""" + def __init__(self, model): + Controller.__init__(self, model) + return + + def register_view(self, view): + Controller.register_view(self, view) + + # ustaw domyślne wartości dla poszczególnych widżetów + self.view['main'].set_title('pyGTKtalog'); + self.view['main'].set_icon_list(gtk.gdk.pixbuf_new_from_file("pixmaps/mainicon.png")) + + # pokaż główne okno + self.view['main'].show(); + return + + # Podłącz sygnały: + def on_main_destroy_event(self, window, event): + gtk.main_quit() + return True + + def on_tb_quit_clicked(self,toolbutton): + gtk.main_quit() + + def on_quit1_activate(self,button): + gtk.main_quit() + + # Obserwowalne właściwości + + pass # end of class diff --git a/mvc/src/models/__init__.py b/mvc/src/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mvc/src/models/m_main.py b/mvc/src/models/m_main.py new file mode 100644 index 0000000..45c9aeb --- /dev/null +++ b/mvc/src/models/m_main.py @@ -0,0 +1,18 @@ +# This Python file uses the following encoding: utf-8 + +import utils._importer +import utils.globals +from gtkmvc import Model + +class MainModel(Model): + """Our model contains a numeric counter and a numeric value that + holds the value that the counter must be assigned to when we the + model is reset""" + + __properties__ = {} + + def __init__(self): + Model.__init__(self) + return + + pass # end of class diff --git a/mvc/src/utils/__init__.py b/mvc/src/utils/__init__.py new file mode 100644 index 0000000..11d1287 --- /dev/null +++ b/mvc/src/utils/__init__.py @@ -0,0 +1,3 @@ + + +__all__ = ["globals", "_importer"] diff --git a/mvc/src/utils/_importer.py b/mvc/src/utils/_importer.py new file mode 100644 index 0000000..8a92aac --- /dev/null +++ b/mvc/src/utils/_importer.py @@ -0,0 +1,44 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author . +# Please report bugs to . + + + +# ====================================================================== +# This module is used only as a utility to import gtkmvc when not +# installed. + +import utils.globals + +if __name__ != "__main__": + try: import gtkmvc + except: + import os.path; import sys + + rel_path = os.path.join(utils.globals.TOP_DIR, "..") + top_dir = os.path.dirname(os.path.abspath(rel_path)) + sys.path = [top_dir] + sys.path + import gtkmvc + pass + + gtkmvc.require("1.0.0") +pass + diff --git a/mvc/src/utils/globals.py b/mvc/src/utils/globals.py new file mode 100644 index 0000000..38291ff --- /dev/null +++ b/mvc/src/utils/globals.py @@ -0,0 +1,33 @@ +# Author: Roberto Cavada +# +# Copyright (c) 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# For more information on pygtkmvc see +# or email to the author . +# Please report bugs to . + + +import os.path +import sys + +if sys.argv[0]: top_dir = os.path.dirname(os.path.abspath(sys.argv[0])) +else: top_dir = "." + + +# A set of global vars +TOP_DIR = top_dir +GLADE_DIR = os.path.join(TOP_DIR, "glade") diff --git a/mvc/src/views/__init__.py b/mvc/src/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mvc/src/views/v_main.py b/mvc/src/views/v_main.py new file mode 100644 index 0000000..45125fa --- /dev/null +++ b/mvc/src/views/v_main.py @@ -0,0 +1,17 @@ +# This Python file uses the following encoding: utf-8 + +import utils._importer +import utils.globals +from gtkmvc import View +import os.path + +class MainView(View): + """This handles only the graphical representation of the + application. The widgets set is loaded from glade file""" + + GLADE = os.path.join(utils.globals.GLADE_DIR, "main.glade") + def __init__(self, ctrl): + View.__init__(self, ctrl, self.GLADE) + return + + pass # end of class