[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