[POS-commit] r77 - in stoqlib/stoqlib: . interface interface/glade

Evandro Vale Miquelito evandro at async.com.br
Tue Mar 8 13:13:38 BRT 2005


Author: evandro
Date: 2005-03-08 13:13:37 -0300 (Tue, 08 Mar 2005)
New Revision: 77

Added:
   stoqlib/stoqlib/interface/__init__.py
   stoqlib/stoqlib/interface/cache.py
   stoqlib/stoqlib/interface/glade/BasicDialog.glade
   stoqlib/stoqlib/interface/reload.py
   stoqlib/stoqlib/interface/services.py
Modified:
   stoqlib/stoqlib/__init__.py
   stoqlib/stoqlib/interface/dialogs.py
Log:
Initial modules to suport application develpment


Modified: stoqlib/stoqlib/__init__.py
===================================================================
--- stoqlib/stoqlib/__init__.py	2005-03-07 21:41:54 UTC (rev 76)
+++ stoqlib/stoqlib/__init__.py	2005-03-08 16:13:37 UTC (rev 77)
@@ -1,2 +1 @@
-import reporting
 

Added: stoqlib/stoqlib/interface/__init__.py
===================================================================
--- stoqlib/stoqlib/interface/__init__.py	2005-03-07 21:41:54 UTC (rev 76)
+++ stoqlib/stoqlib/interface/__init__.py	2005-03-08 16:13:37 UTC (rev 77)
@@ -0,0 +1,10 @@
+import os
+from Kiwi2 import Views
+import stoqlib
+
+path = [os.path.join(stoqlib.__path__[0], "interface", "glade")]
+
+# If it doesn't already exists in the gladepath, add it
+if path not in Views.gladepath:
+    Views.set_gladepath(Views.gladepath + path)
+

Added: stoqlib/stoqlib/interface/cache.py
===================================================================
--- stoqlib/stoqlib/interface/cache.py	2005-03-07 21:41:54 UTC (rev 76)
+++ stoqlib/stoqlib/interface/cache.py	2005-03-08 16:13:37 UTC (rev 77)
@@ -0,0 +1,60 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2004 Async Open Source <http://www.async.com.br>
+## All rights reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program 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 General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+"""
+interface/cache.py:
+
+   A short description about what this file implements ...
+"""
+
+class DialogCache:
+    def __init__(self):
+        self.dialogs = {}
+    
+    def get_dialog(self, dialog_class, *args, **kwargs):
+        """ This method returns a dialog instance. If the dialog is not
+        in cache, it instantiates the dialog and insert it in cache.
+        Else, refreshes cached instance and use it. 
+
+        When passing in model, you must *make sure* that it is in the
+        right connection, or else you will end up trying to manipulate
+        an object in a stale connection (RuntimeError in
+        ZODB.Connection.load())
+        """ 
+        if self.has_dialog(dialog_class):
+            d = self.dialogs[dialog_class]
+            if hasattr(d, 'refresh'):
+                print 'XXX: REFRESHING'
+                d.refresh(*args, **kwargs)
+                return d
+            del self.dialogs[dialog_class]
+        d = self.dialogs[dialog_class] = dialog_class(*args, **kwargs) 
+        return d
+
+    def has_dialog(self, dialog_class):
+        """ Checks if the dialog is already in cache. """
+        return self.dialogs.has_key(dialog_class)
+
+""" Global cache instance """ 
+
+cache = DialogCache()
+

Modified: stoqlib/stoqlib/interface/dialogs.py
===================================================================
--- stoqlib/stoqlib/interface/dialogs.py	2005-03-07 21:41:54 UTC (rev 76)
+++ stoqlib/stoqlib/interface/dialogs.py	2005-03-08 16:13:37 UTC (rev 77)
@@ -0,0 +1,179 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2004 Async Open Source <http://www.async.com.br>
+## All rights reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program 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 General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+"""
+interface/dialogs.py:
+
+   Basic dialogs definition
+"""
+
+from Kiwi2.Delegates import GladeDelegate
+from Kiwi2.initgtk import gtk
+
+class RunnableView:
+    """A mixin class for any View or Delegate that offers run/close"""
+    retval = None
+    def close(self, *args):
+        """Handles action to be performed when window is closed.
+Defaults to _shutdown()"""
+        return self._shutdown()
+
+    def run(self):
+        """Handles action to be performed when window is opened.
+Defaults to _open(), which blocks in a mainloop. Returns the value of
+the retval attribute"""
+        self._open()
+        return self.retval
+
+    def _shutdown(self):
+        self.hide_and_quit()
+        return True
+
+    def _open(self):
+#         # For some odd reason, when spawning a modal dialog using a
+#         # double-click, you can get a weird focus bug. Check here if
+#         # we're modal, and if so, set it using an idle handler. Yuck.
+#         if self.toplevel['modal']:
+#             self.toplevel.set_modal(0)
+#             gtk.idle_add(self._restore_modality)
+        self.show()
+
+    def _restore_modality(self, *args):
+        time.sleep(0.2)
+        gtk.idle_add(self.toplevel.set_modal, 1)
+        
+
+#
+# Abstract classes: inherit only, do not use.
+#
+
+class _AbstractDialog(GladeDelegate, RunnableView):
+    """Abstract Dialog class that defines a simple run API."""
+    gladefile = None
+    widgets = []
+
+    def __init__(self, delete_handler=None):
+        if not delete_handler:
+            delete_handler=self.close
+        
+        GladeDelegate.__init__(self, gladefile=self.gladefile, 
+                               delete_handler=delete_handler,
+                               widgets=self.widgets)
+
+#
+# Special note for _BasicDialog and _BasicPluggableDialog: if you inherit
+# from this class, you *must* call _Basic*Dialog._initialize() right after
+# calling _Basic*Dialog.__init__() or the dialog will not be set up
+# correctly. Initialization has been broken into two steps to allow it to
+# be called conveniently from a consumer refresh() method. See
+# NotifyDialog/PluggableNotifyDialog for an example of how __init__ should
+# behave.
+#
+
+class _BasicDialog(_AbstractDialog):
+    """Abstract class that offers a Dialog with two buttons. It should
+be subclassed and customized."""
+#TODO: waiting for kiwi2 support: see bug 1843
+    gladefile = "BasicDialog"
+
+    widgets = ['top_separator', 
+               'header', 
+               'main', 
+               'label', 
+               'ok_button',
+               'cancel_button', 
+               'down_separator', 
+               'down_buttonbox']
+
+    # Yes, title=" ". Use a single space to work around *cough* BROKEN
+    # window managers that want to set the title as Unnamed or ? when an
+    # empty string is set to it.
+    def __init__(self):
+        _AbstractDialog.__init__(self, delete_handler=self.cancel)
+
+        #TODO: We must implement keyactions on kiwi2. See bug 1844
+        # self.keyactions = { GDK.Escape : self.on_escape_pressed }
+#         self.keyactions = {
+#             # GDK.Escape is redefined on subclasses, when necessary
+#             GDK.Escape : self.confirm,
+#         }
+        
+
+    def _initialize(self, text=None, title=" ", header=None, size=None): 
+        self.set_title(title)
+        if size:
+            self.get_toplevel().set_usize(*size)
+        if text:
+            self.label.set_text(text)
+        if header:
+            self.header.set_text(header)
+        else:
+            self.header.hide()
+            self.top_separator.hide()
+
+    def on_ok_button__clicked(self, *args):
+        return self.confirm()
+
+    def confirm(self, *args):
+        self.retval = True
+        return self.close()
+    
+    def on_cancel_button__clicked(self, *args):
+        return self.cancel()
+
+    def cancel(self, *args):
+        self.retval = False
+        return self.close()
+    
+    def enable_ok(self):
+        self.ok_button.set_sensitive(True)
+
+    def disable_ok(self):
+        self.ok_button.set_sensitive(False)
+
+    def set_ok_label(self, text):
+        self.ok_button.children()[0].set_text(text)
+
+    def set_cancel_label(self, text):
+        self.cancel_button.children()[0].set_text(text)
+
+    def justify_label(self, just):
+        self.label.set_justify(just)
+
+
+#
+# Main classes start here. There are two basic types: Notify and
+# Confirm dialogs, the only difference between them being that Notify
+# offers only an OK button and Confirm offering both OK and Cancel. The
+# second set offers a pluggable slave area.
+#
+
+class NotifyDialog(_BasicDialog):
+    """Dialog that notifies an event. It prints text in a label and
+offers a single OK button."""
+    def __init__(self, text, title=" ", header=None, size=None):
+        _BasicDialog.__init__(self)
+        _BasicDialog._initialize(self, text, title, header, size)
+        self.cancel_button.hide()
+#         self.keyactions.update({ GDK.Return : self.confirm,
+#                                  GDK.KP_Enter : self.confirm })
+

Added: stoqlib/stoqlib/interface/glade/BasicDialog.glade
===================================================================
--- stoqlib/stoqlib/interface/glade/BasicDialog.glade	2005-03-07 21:41:54 UTC (rev 76)
+++ stoqlib/stoqlib/interface/glade/BasicDialog.glade	2005-03-08 16:13:37 UTC (rev 77)
@@ -0,0 +1,106 @@
+<?xml version="1.0" ?>
+<glade-interface>
+    <widget class="GtkWindow" id="BasicDialog">
+        <property name="role"></property>
+        <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+        <property name="window_position">center-always</property>
+        <property name="title" context="True" translatable="True"></property>
+        <child>
+            <widget class="GtkVBox" id="vbox1">
+                <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                <property name="visible">True</property>
+                <child>
+                    <widget class="GtkLabel" id="header">
+                        <property name="pattern" context="True" translatable="True"></property>
+                        <property name="label" context="True" translatable="True">header</property>
+                        <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                        <property name="visible">True</property>
+                    </widget>
+                    <packing>
+                        <property name="expand">False</property>
+                    </packing>
+                </child>
+                <child>
+                    <widget class="GtkHSeparator" id="top_separator">
+                        <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                        <property name="visible">True</property>
+                    </widget>
+                    <packing>
+                        <property name="position">1</property>
+                        <property name="expand">False</property>
+                    </packing>
+                </child>
+                <child>
+                    <widget class="GtkEventBox" id="main">
+                        <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                        <property name="visible">True</property>
+                        <child>
+                            <widget class="GtkLabel" id="label">
+                                <property name="pattern" context="True" translatable="True"></property>
+                                <property name="label" context="True" translatable="True">label</property>
+                                <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                                <property name="visible">True</property>
+                            </widget>
+                        </child>
+                    </widget>
+                    <packing>
+                        <property name="position">2</property>
+                    </packing>
+                </child>
+                <child>
+                    <widget class="GtkEventBox" id="notice">
+                        <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                        <property name="visible">True</property>
+                        <child>
+                            <placeholder/>
+                        </child>
+                    </widget>
+                    <packing>
+                        <property name="position">3</property>
+                    </packing>
+                </child>
+                <child>
+                    <widget class="GtkHSeparator" id="down_separator">
+                        <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                        <property name="visible">True</property>
+                    </widget>
+                    <packing>
+                        <property name="position">4</property>
+                        <property name="expand">False</property>
+                    </packing>
+                </child>
+                <child>
+                    <widget class="GtkHButtonBox" id="down_buttonbox">
+                        <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                        <property name="visible">True</property>
+                        <child>
+                            <widget class="GtkButton" id="cancel_button">
+                                <property name="receives_default">True</property>
+                                <property name="label" context="True" translatable="True">Cancel</property>
+                                <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                                <property name="can_focus">True</property>
+                                <property name="visible">True</property>
+                            </widget>
+                            <packing/>
+                        </child>
+                        <child>
+                            <widget class="GtkButton" id="ok_button">
+                                <property name="receives_default">True</property>
+                                <property name="label" context="True" translatable="True">OK</property>
+                                <property name="events">all-events-mask | button-motion-mask | button-press-mask | button-release-mask | button1-motion-mask | button2-motion-mask | button3-motion-mask | enter-notify-mask | exposure-mask | focus-change-mask | key-press-mask | key-release-mask | leave-notify-mask | pointer-motion-hint-mask | pointer-motion-mask | property-change-mask | proximity-in-mask | proximity-out-mask | scroll-mask | structure-mask | substructure-mask | visibility-notify-mask</property>
+                                <property name="can_focus">True</property>
+                                <property name="visible">True</property>
+                            </widget>
+                            <packing>
+                                <property name="position">1</property>
+                            </packing>
+                        </child>
+                    </widget>
+                    <packing>
+                        <property name="position">5</property>
+                    </packing>
+                </child>
+            </widget>
+        </child>
+    </widget>
+</glade-interface>

Added: stoqlib/stoqlib/interface/reload.py
===================================================================
--- stoqlib/stoqlib/interface/reload.py	2005-03-07 21:41:54 UTC (rev 76)
+++ stoqlib/stoqlib/interface/reload.py	2005-03-08 16:13:37 UTC (rev 77)
@@ -0,0 +1,230 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2004 Async Open Source <http://www.async.com.br>
+## All rights reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program 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 General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+"""
+interface/reload.py:
+
+   Reload routines
+"""
+
+
+
+import os, sys, types, time, linecache
+
+#
+# Reloader functions
+#
+
+def reload_world():
+    "reloads all modules, using rebuild for updating module instances"
+    global lastRebuild
+    print "Reloading changed modules...\n",
+    sys.stdout.flush()
+    for name, mod in sys.modules.items():
+        if mod is None: continue
+        if not hasattr(mod, "__file__"): continue # builtins
+        if not module_mtime(mod) > lastRebuild: continue
+        print "- %s [%s]" % (name, mod.__file__)
+        rebuild(mod)
+    lastRebuild = time.time()
+    print "done"
+
+def module_mtime(module):
+    "returns the last modified date for a given module's source file"
+    if module.__file__.endswith("pyc"):
+        # use [:-1] to stat the actual .py file, not the precompiled version
+        return os.stat(module.__file__[:-1])[8]
+    return os.stat(module.__file__)[8]
+
+#
+# This section from twisted.python.reflect
+#
+
+def namedModule(name):
+    """Return a module given its name."""
+    topLevel = __import__(name)
+    packages = name.split(".")[1:]
+    m = topLevel
+    for p in packages:
+        m = getattr(m, p)
+    return m
+
+#
+# This section from twisted.python.rebuild
+#
+
+lastRebuild = time.time()
+
+_modDictIDMap = {}
+
+def latestFunction(oldFunc):
+    """Get the latest version of a function.
+    """
+    # This may be CPython specific, since I believe jython instantiates a new
+    # module upon reload.
+    dictID = id(oldFunc.func_globals)
+    module = _modDictIDMap.get(dictID)
+    if module is None:
+        return oldFunc
+    return getattr(module, oldFunc.__name__)
+
+
+if sys.version_info >= (2, 2, 0):
+    # We have 'object'
+    def latestClass(oldClass):
+        """Get the latest version of a class.
+        """
+        module = namedModule(oldClass.__module__)
+        newClass = getattr(module, oldClass.__name__)
+        newBases = []
+        for base in newClass.__bases__:
+            newBases.append(latestClass(base))
+        
+        try:
+            # This makes old-style stuff work
+            newClass.__bases__ = tuple(newBases)
+            return newClass
+        except TypeError:
+            ctor = getattr(newClass, '__metaclass__', type)
+            return ctor(newClass.__name__, tuple(newBases), dict(newClass.__dict__))
+else:
+    object = 0
+
+    def latestClass(oldClass):
+        """Get the latest version of a class.
+        """
+        module = __import__(oldClass.__module__, {}, {}, 'nothing')
+        newClass = getattr(module, oldClass.__name__)
+        newBases = []
+        for base in newClass.__bases__:
+            newBases.append(latestClass(base))
+        newClass.__bases__ = tuple(newBases)
+        return newClass
+
+
+def updateInstance(inst):
+    """Updates an instance to be current
+    """
+    inst.__class__ = latestClass(inst.__class__)
+
+def __getattr__(inst, name):
+    """A getattr method to cause a class to be refreshed.
+    """
+    if name == '__del__':
+        raise AttributeError("Without this, Python segfaults.")
+    updateInstance(inst)
+    result = getattr(inst, name)
+    return result
+
+def rebuild(module):
+    """Reload a module and do as much as possible to replace its references.
+    """
+
+    d = module.__dict__
+    _modDictIDMap[id(d)] = module
+    newclasses = {}
+    classes = {}
+    functions = {}
+    values = {}
+    for k, v in d.items():
+        if type(v) == types.ClassType:
+            # Failure condition -- instances of classes with buggy
+            # __hash__/__cmp__ methods referenced at the module level...
+            if v.__module__ == module.__name__:
+                classes[v] = 1
+        elif type(v) == types.FunctionType:
+            if v.func_globals is module.__dict__:
+                functions[v] = 1
+        elif object and isinstance(v, type):
+            if v.__module__ == module.__name__:
+                newclasses[v] = 1
+
+    values.update(classes)
+    values.update(functions)
+    fromOldModule = values.has_key
+    newclasses = newclasses.keys()
+    classes = classes.keys()
+    functions = functions.keys()
+
+    # Boom.
+    reload(module)
+    # Make sure that my traceback printing will at least be recent...
+    linecache.clearcache()
+
+    for clazz in classes:
+        if getattr(module, clazz.__name__) is clazz:
+            pass
+        else:
+            clazz.__bases__ = ()
+            clazz.__dict__.clear()
+            clazz.__getattr__ = __getattr__
+            clazz.__module__ = module.__name__
+    if newclasses:
+        import gc
+        if (2, 2, 0) <= sys.version_info[:3] < (2, 2, 2):
+            hasBrokenRebuild = 1
+            gc_objects = gc.get_objects()
+        else:
+            hasBrokenRebuild = 0
+    for nclass in newclasses:
+        ga = getattr(module, nclass.__name__)
+        if ga is nclass:
+            pass
+        else:
+            if hasBrokenRebuild:
+                for r in gc_objects:
+                    if not getattr(r, '__class__', None) is nclass:
+                        continue
+                    r.__class__ = ga
+            else:
+                for r in gc.get_referrers(nclass):
+                    if getattr(r, '__class__', None) is nclass:
+                        r.__class__ = ga
+    modcount = 0
+    for mk, mod in sys.modules.items():
+        modcount = modcount + 1
+        if mod == module or mod is None:
+            continue
+
+        if not hasattr(mod, '__file__'):
+            # It's a builtin module; nothing to replace here.
+            continue
+
+        for k, v in mod.__dict__.items():
+            try:
+                hash(v)
+            except TypeError:
+                continue
+            if fromOldModule(v):
+                if type(v) == types.ClassType:
+                    nv = latestClass(v)
+                else:
+                    nv = latestFunction(v)
+                setattr(mod, k, nv)
+            else:
+                # Replace bases of non-module classes just to be sure.
+                if type(v) == types.ClassType:
+                    for base in v.__bases__:
+                        if fromOldModule(base):
+                            latestClass(v)
+    return module
+

Added: stoqlib/stoqlib/interface/services.py
===================================================================
--- stoqlib/stoqlib/interface/services.py	2005-03-07 21:41:54 UTC (rev 76)
+++ stoqlib/stoqlib/interface/services.py	2005-03-08 16:13:37 UTC (rev 77)
@@ -0,0 +1,204 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2004 Async Open Source <http://www.async.com.br>
+## All rights reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program 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 General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+"""
+interface/services.py:
+
+    Base classes and functions to run applications
+"""
+import traceback
+
+from IndexedCatalog.Shelf import Shelf
+from ZODB.POSException import ConflictError
+
+from Kiwi2.Delegates import GladeDelegate
+from Kiwi2.Views import GladeSlaveView, SlaveView, AbstractView
+
+from gtk import timeout_add
+from types import ListType, TupleType
+
+from cache import cache 
+from dialogs import NotifyDialog
+
+""" Service classes """ 
+
+#
+# Exceptions
+#
+
+class ModelDataError(Exception): pass
+
+#
+# Expects an main window class, which takes one argument: the app (for
+# shutdown purposes)
+#
+
+class BaseApp:
+    """ Base class for application control. """
+    def __init__(self, main_window_class, sync_time=10000):
+        # The self should be passed to main_window to let it access
+        # shutdown and do_sync methods.
+        self.main_window = main_window_class(self)
+        timeout_add(sync_time, self.do_sync)
+
+    def run(self):
+        self.main_window.show()
+
+    def shutdown(self, *args):
+        self.main_window.hide_and_quit()
+
+    def do_sync(self, *args):
+        if hasattr(self.main_window, 'sync'):
+            self.main_window.sync()
+        return TRUE
+
+#
+# Expects an app, with app.shutdown available as a handler
+#
+
+class BaseAppWindow(GladeDelegate):
+    """ Class to be inherited by applications main window.  """
+    def __init__(self, app, *args, **kwargs):
+        GladeDelegate.__init__(self, delete_handler=app.shutdown)
+
+    def set_sensitive(self, widgets, value):
+        """Sets one or more widgets to state sensitive. XXX: Kiwi?"""
+        for widget in widgets:
+            widget.set_sensitive(value)
+
+    def get_dialog(self, dialog_class, *args, **kwargs):
+        """ Encapsuled method for getting dialogs. """
+        return get_dialog(self, dialog_class, *args, **kwargs)
+
+    def run_dialog(self, dialog_class, *args, **kwargs):
+        """ Encapsuled method for running dialogs. """
+        return get_dialog(self, dialog_class, *args, **kwargs).run()
+
+    def lookup_model(self, conn, model):
+        """ Encapsuled method for looking up models. """
+        return lookup_model(conn, model)
+
+    def ensure_insert_model(self, conn, model):
+        """ Encapsuled method for inserting models in catalogs. """
+        return ensure_insert_model(conn, model)
+
+    def finish_transaction(self, conn, model=1, keep=0):
+        """ Encapsuled method for committing/aborting changes in models.
+        This method is special (and different from the standalone
+        finish_transaction) because, unless keep=1 is provided, the
+        connection provided is also closed."""
+        # Default model is 1 which means that we'll commit if nothing
+        # was passed in.
+        if not isinstance(conn, Shelf):
+            raise TypeError, "conn must be Shelf, got %r" % conn
+        ret = finish_transaction(conn, model)
+        if not keep:
+            conn.close()
+        return ret
+
+""" Service functions """ 
+
+def get_dialog(parent, dialog_class, *args, **kwargs):
+    """ Returns a dialog, inserting it on a cache, if it was not already
+    open.
+    - parent: the window which is opening the dialog;
+    - cache: the application window cache;
+    - dialog_class: the dialog class;
+    - *args, **kwargs: the arguments which should be used on dialog_class
+      instantiation;
+    """
+    d = cache.get_dialog(dialog_class, *args, **kwargs)
+    if not isinstance(parent, AbstractView):
+        parent = None
+    # If parent is a slaveview, use GTK+ calls to get the toplevel
+    # window. This is a bit of a hack :-/
+    if isinstance(parent, GladeSlaveView) or isinstance(parent, SlaveView):
+        parent = parent.toplevel.get_toplevel()
+    if parent:
+        d.set_transient_for(parent)
+    return d
+        
+def run_dialog(parent, dialog_class, *args, **kwargs):
+    return get_dialog(parent, dialog_class, *args, **kwargs).run()
+
+def finish_transaction(conn, model=1):
+    """ Function to commit/abort created/modified models. """ 
+    if model:
+        try:
+            conn.commit()
+            return model
+        except ConflictError, e:
+            _conflict_dialog(e)
+            conn.sync()
+            return None
+    else:
+        conn.abort()
+        conn.sync()
+        return None
+
+def lookup_model(conn, model):
+    """ Function to lookup the model according to the connection which
+    should be used by a dialog.
+    - model: can be a model, or a list of models. """
+    if type(model) in (ListType, TupleType):
+        model = [conn.lookup(item) for item in model]
+    else:
+        model = conn.lookup(model)
+    return model
+
+def ensure_insert_model(conn, model):
+    if not model:
+        raise AttributeError, "Model was None!"
+    cat = conn.get_catalog(model.__class__)
+    if not cat.has_object(model):
+        try:
+            cat.insert(model)
+        except ConflictError, e:
+            # In this case it's definitely an RCE
+            _conflict_dialog(e)        
+            conn.sync()
+            return None
+    # Calling a hook for doing something needed after the model insertion in
+    # the catalog
+    model.after_insert_model(conn)
+    return model
+
+def _conflict_dialog(e):
+    # Import inline para evitar dependências
+    import sys
+    from stoqlib.interface.dialogs import NotifyDialog
+    traceback.print_stack()
+    sys.stderr.write("XXX ConflictError: %s" % str(e))
+    msg = ("A conflict was generated at the end of the transaction. \n "
+           "Please cancel and do the transaction again.\n\n"
+           "(This problem was registered and will be evaluated.)")
+    NotifyDialog(msg).run()
+
+def notify_if_raises(win, check_func, exceptions=ModelDataError, 
+                     text="An error ocurred: %s", title=" ", header=None):
+    try:
+        check_func()
+    except exceptions, e:
+        run_dialog(win, NotifyDialog, text % e, title, header)
+        return TRUE 
+    return FALSE
+        



More information about the POS-commit mailing list