[Pymoul-svn] SF.net SVN: pymoul: [129] pymoul/trunk/src/moul
Status: Alpha
Brought to you by:
tiran
|
From: <ti...@us...> - 2007-02-03 18:42:22
|
Revision: 129
http://pymoul.svn.sourceforge.net/pymoul/?rev=129&view=rev
Author: tiran
Date: 2007-02-03 10:41:23 -0800 (Sat, 03 Feb 2007)
Log Message:
-----------
Added QNamespaceContainer()
Fixed unit tests
Modified Paths:
--------------
pymoul/trunk/src/moul/file/kiimage.py
pymoul/trunk/src/moul/file/localization.py
pymoul/trunk/src/moul/file/tests/test_directory.py
pymoul/trunk/src/moul/file/tests/test_plasmalog.py
pymoul/trunk/src/moul/qt/errorhandler.py
pymoul/trunk/src/moul/qt/localization.py
pymoul/trunk/src/moul/qt/mainwindow.py
Added Paths:
-----------
pymoul/trunk/src/moul/qt/utils.py
Modified: pymoul/trunk/src/moul/file/kiimage.py
===================================================================
--- pymoul/trunk/src/moul/file/kiimage.py 2007-02-03 02:12:36 UTC (rev 128)
+++ pymoul/trunk/src/moul/file/kiimage.py 2007-02-03 18:41:23 UTC (rev 129)
@@ -274,7 +274,7 @@
fixed.close()
tmp.close()
ki.close()
-
+
def __len__(self):
"""len() support - returns number of images to check
"""
Modified: pymoul/trunk/src/moul/file/localization.py
===================================================================
--- pymoul/trunk/src/moul/file/localization.py 2007-02-03 02:12:36 UTC (rev 128)
+++ pymoul/trunk/src/moul/file/localization.py 2007-02-03 18:41:23 UTC (rev 129)
@@ -316,7 +316,7 @@
def parseLocDir(self):
"""Parse all loc files at once
"""
- if self._loc is None:
+ if self._locs is None:
self.findLocs()
for loc in iter(self):
pass
@@ -324,7 +324,10 @@
def __len__(self):
"""len() support
"""
- return len(self._locs)
+ if self._locs is None:
+ return 0
+ else:
+ return len(self._locs)
def __iter__(self):
"""Iterator support for GUI progress bar
Modified: pymoul/trunk/src/moul/file/tests/test_directory.py
===================================================================
--- pymoul/trunk/src/moul/file/tests/test_directory.py 2007-02-03 02:12:36 UTC (rev 128)
+++ pymoul/trunk/src/moul/file/tests/test_directory.py 2007-02-03 18:41:23 UTC (rev 129)
@@ -53,7 +53,7 @@
def test_dumbfactorycreate(self):
for name in self.urudir._factories:
f = self.urudir.factory(name)
- self.failUnless(f, str((type(f), repr(f), name)))
+ self.failUnless(f is not None, str((type(f), repr(f), name)))
class UruPersonalDirTest(AbstractTest):
klass = UruPersonalDataDirectory
Modified: pymoul/trunk/src/moul/file/tests/test_plasmalog.py
===================================================================
--- pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-02-03 02:12:36 UTC (rev 128)
+++ pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-02-03 18:41:23 UTC (rev 129)
@@ -104,7 +104,9 @@
self.failUnless(os.path.isdir(self._kidest), self._kidest)
kif.findFiles()
- kif.checkAndCopyFiles()
+ # check and copy files
+ for f in iter(kif):
+ pass
content = os.listdir(self._kidest)
self.failUnlessEqual(len(content), 1, content)
self.failUnlessEqual(content, ["KIimage001.jpg"])
Modified: pymoul/trunk/src/moul/qt/errorhandler.py
===================================================================
--- pymoul/trunk/src/moul/qt/errorhandler.py 2007-02-03 02:12:36 UTC (rev 128)
+++ pymoul/trunk/src/moul/qt/errorhandler.py 2007-02-03 18:41:23 UTC (rev 129)
@@ -20,7 +20,7 @@
"""Error handling for moul qt
The module installs a custom exception hook that shows unhandled traceback in
-the ui. It also contains several functions to create message boxes.
+the ui.
"""
__author__ = "Christian Heimes"
__version__ = "$Id"
@@ -28,14 +28,14 @@
import os
import sys
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-from PyQt4.QtCore import Qt
+from PyQt4.QtGui import QApplication
from traceback import format_exception
from moul.log import getLogger
+from moul.qt.utils import criticalMB
+
LOG = getLogger('moul.qt.error')
@@ -48,9 +48,9 @@
if not getattr(sys, 'frozen', False):
return
try:
- title= QtGui.QApplication.translate("excepthook",
+ title= QApplication.translate("excepthook",
"An unhandled error has occured",
- None, QtGui.QApplication.UnicodeUTF8)
+ None, QQApplication.UnicodeUTF8)
msg = ("Please report the error:\n\n" +
'\n'.join([line.strip() for line in
format_exception(typ, value, traceback)])
@@ -74,46 +74,3 @@
"""
LOG.info("Qt exception hook removed")
sys.excepthook = sys.__excepthook__
-
-def _mkMessageBox(context, icon='Information'):
- """
- Create a message box
- """
- assert icon in ('Question', 'Information', 'Warning', 'Critical')
- if context:
- mb = QtGui.QMessageBox(context)
- else:
- mb = QtGui.QMessageBox()
- mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png"))
- mb.setIcon(getattr(QtGui.QMessageBox, icon))
- mb.setStandardButtons(QtGui.QMessageBox.Close)
- return mb
-
-
-def criticalMB(context, title, text):
- """
- Critical message box
- """
- mb = _mkMessageBox(context, icon='Critical')
- mb.setWindowTitle(title)
- mb.setText(text)
- return mb
-
-def warningMB(context, title, text):
- """
- warning message box
- """
- mb = _mkMessageBox(context, icon='Warning')
- mb.setWindowTitle(title)
- mb.setText(text)
- return mb
-
-def infoMB(context, title, text):
- """
- Info message box
- """
- mb = _mkMessageBox(context, icon='Information')
- mb.setStandardButtons(QtGui.QMessageBox.Ok)
- mb.setWindowTitle(title)
- mb.setText(text)
- return mb
Modified: pymoul/trunk/src/moul/qt/localization.py
===================================================================
--- pymoul/trunk/src/moul/qt/localization.py 2007-02-03 02:12:36 UTC (rev 128)
+++ pymoul/trunk/src/moul/qt/localization.py 2007-02-03 18:41:23 UTC (rev 129)
@@ -36,6 +36,7 @@
from moul.qt.simpleprogressbar import SimpleProgressbar
from moul.qt.threadlet import YieldingThreadlet
+from moul.qt.utils import QNamespaceContainer
LOG = getLogger('moul.loc')
@@ -44,17 +45,17 @@
dummy = type(lst)(["<choose>"])
return QtCore.QStringList(dummy+lst)
-class LocalizationMixin(object):
+class LocalizationContainer(QNamespaceContainer):
"""
Mixin for documentation tab
"""
- def _documents_init(self):
+ def initialize(self):
"""
@qtsignal loadLocalization(): load loc data
"""
- self._journals_loaded = False
+ self.loaded = False
self._documents_clear('language')
- self.connect(self, SIGNAL('loadLocalization()'),
+ self.connect(self.context, SIGNAL('loadLocalization()'),
self.on_localization_doload)
self.connect(self.cb_doc_language, SIGNAL("currentIndexChanged(int)"),
self.on_cb_doc_language_currentIndexChanged)
@@ -69,7 +70,7 @@
@qtslot loadLocalization(): Load localization
@qtsignal finished(): self._journal_threadlet
"""
- if self._journals_loaded:
+ if self.loaded:
return
loc = self.urugamedir.loc
@@ -85,17 +86,17 @@
self.trUtf8("No journals found."))
return
- self._journal_progressbar = SimpleProgressbar(self)
- self._journal_progressbar.setWindowTitle(self.trUtf8("Loading journals"))
- self._journal_progressbar.setProgressbar(0, len(loc), 0)
- self._journal_progressbar.show()
+ self.progressbar = SimpleProgressbar(self.context)
+ self.progressbar.setWindowTitle(self.trUtf8("Loading journals"))
+ self.progressbar.setProgressbar(0, len(loc), 0)
+ self.progressbar.show()
- self._journal_threadlet = YieldingThreadlet(self)
- self.connect(self._journal_threadlet, SIGNAL('finished()'),
+ self.threadlet = YieldingThreadlet(self.context)
+ self.connect(self.threadlet, SIGNAL('finished()'),
self.on_localization_loaded)
- self.connect(self._journal_threadlet, SIGNAL("yield(const QString&)"),
- self._journal_progressbar.increase)
- self._journal_threadlet.detach(loc)
+ self.connect(self.threadlet, SIGNAL("yield(const QString&)"),
+ self.progressbar.increase)
+ self.threadlet.detach(loc)
@signalLogDecorator(LOG)
def on_localization_loaded(self):
@@ -103,17 +104,17 @@
@qtslot finished(): self._journal_threadlet
"""
# remove thread
- self.disconnect(self._journal_threadlet, SIGNAL('finished()'),
+ self.disconnect(self.threadlet, SIGNAL('finished()'),
self.on_localization_loaded)
- self.disconnect(self._journal_threadlet, SIGNAL("yield(const QString&)"),
- self._journal_progressbar.increase)
- del self._journal_threadlet
+ self.disconnect(self.threadlet, SIGNAL("yield(const QString&)"),
+ self.progressbar.increase)
+ del self.threadlet
# close and remove info message box
- self._journal_progressbar.close()
- del self._journal_progressbar
+ self.progressbar.close()
+ del self.progressbar
- self._journals_loaded = True
+ self.loaded = True
self.lb_doc_status.setText(
self.trUtf8("Journals loaded."))
@@ -129,6 +130,9 @@
@signalLogDecorator(LOG)
def on_pb_doc_loadjournals_clicked(self):
"""
+ L{LocalizationContainer}
+
+ @slot clicked(): clicked pb_doc_loadjournals
"""
self.pb_doc_loadjournals.setEnabled(False)
self.emit(SIGNAL("loadLocalization()"))
@@ -139,7 +143,7 @@
if name == 'doc':
qobj = self.te_doc_view
else:
- qobj = getattr(self, 'cb_doc_%s' % name)
+ qobj = getattr(self.context, 'cb_doc_%s' % name)
qobj.clear()
qobj.setEnabled(False)
@@ -196,16 +200,3 @@
qstr = QtCore.QString(translation)
self.te_doc_view.setPlainText(qstr)
self.te_doc_view.setEnabled(True)
-
-#class LocalizationLoadEventFilter(QtCore.QObject):
- #"""Event filter to load localization
- #"""
- #def eventFilter(self, target, event):
- #"""
- #Event filter
- #"""
- #if event.type() in (QtCore.QEvent.MouseButtonPress,
- #QtCore.QEvent.FocusIn):
- #self.parent().emit(SIGNAL('loadLocalization()'))
-
- #return QtCore.QObject.eventFilter(self, target, event)
Modified: pymoul/trunk/src/moul/qt/mainwindow.py
===================================================================
--- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-03 02:12:36 UTC (rev 128)
+++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-03 18:41:23 UTC (rev 129)
@@ -43,7 +43,7 @@
from moul.server.ping import isSocketError
from moul.time.cavern import CavernTime
-from moul.qt.localization import LocalizationMixin
+from moul.qt.localization import LocalizationContainer
from moul.qt.simpleprogressbar import SimpleProgressbar
from moul.qt.threadlet import YieldingThreadlet
from moul.qt.ui.mainwindow import Ui_MainWindow
@@ -51,7 +51,7 @@
LOG = getLogger('moul.qt')
-class MainWindow(QtGui.QMainWindow, Ui_MainWindow, LocalizationMixin):
+class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
# Set up the user interface from Designer.
@@ -80,8 +80,11 @@
self._ping_init()
self._systray_init()
self._about_init()
- self._documents_init()
+ self.qcLocalization = LocalizationContainer(self)
+ # connect additional
+ QtCore.QMetaObject.connectSlotsByName(self)
+
# run checker
self._moulrunning = None
self._moulrunning_thread = MoulRunningThread()
Copied: pymoul/trunk/src/moul/qt/utils.py (from rev 126, pymoul/trunk/src/moul/qt/errorhandler.py)
===================================================================
--- pymoul/trunk/src/moul/qt/utils.py (rev 0)
+++ pymoul/trunk/src/moul/qt/utils.py 2007-02-03 18:41:23 UTC (rev 129)
@@ -0,0 +1,226 @@
+#!/usr/bin/env python2.5
+# pyMoul - Python interface to Myst Online URU Live
+# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de>
+
+# 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
+#
+
+"""Misc utilities
+
+It also contains several functions to create message boxes.
+"""
+__author__ = "Christian Heimes"
+__version__ = "$Id"
+__revision__ = "$Revision$"
+
+import re
+import warnings
+from PyQt4.QtCore import QObject
+from PyQt4.QtCore import SIGNAL
+from PyQt4 import QtGui
+from types import UnboundMethodType as UnboundMethod
+
+from moul.log import getLogger
+
+
+LOG = getLogger('moul.qt.utils')
+_marker=object()
+SLOT_RE = re.compile('^on_(.+)_([^_]+)$')
+
+class QNamespaceContainer(QObject):
+ """
+ Base class to assemble methods and logic in its own class.
+
+ Slot methods (on_method_event()) are automatically connected to widgets of
+ the parent. If the methods takes an argument you *must* apply a
+ @pyqtSignature() decorator!
+
+ connect(), disconnect(), emit() and attribute access are forwarded to the
+ parent class (like Zope2 implicit acquisition wrapper) but you *must* use
+ self.context instead self as argument.
+
+ >>> class MyStuff(QNamespaceContainer):
+ ... def initialize(self):
+ ... self.connect(self.context, SIGNAL("foo()"), bar)
+ ...
+ ... @pyqtSignature("int")
+ ... def on_button_clicked(self, boolean):
+
+ Now add the container to your class
+ >>> class MainWindow(QtCore.QObject):
+ ... def __init__(self, parent=None):
+ ... QtCore.QObject.__init__(self, parent=None)
+ ... self.qcMystuff = MyStuff(parent)
+
+ @warning: If you are creating new QObject based instances you should
+ bind them to self.context and *not* to self. This is especially true
+ for QWidget based objects.
+ """
+
+ def __init__(self, parent):
+ """
+ Constructor
+
+ Calls initialize() and auto connects slot methods with parent's
+ widgets.
+
+ @param parent: the Qt parent object
+ @type parent: a QObject based instance
+ """
+ QObject.__init__(self, parent)
+ self.initialize()
+ connectSlotsByName(container=parent, callobj=self)
+
+ @property
+ def context(self):
+ """
+ Shortcut for self.parent()
+ """
+ return self.parent()
+
+ def connect(self, *args):
+ """
+ Shortcut for self.parent().connect(*args)
+ """
+ if args[0] is self:
+ warnings.warn("You used self as first argument but should use "
+ "self.context!", SyntaxWarning, stacklevel=2)
+ self.parent().connect(*args)
+
+ def disconnect(self, *args):
+ """
+ Shortcut for self.parent().disconnect(*args)
+ """
+ if args[0] is self:
+ warnings.warn("You used self as first argument but should use "
+ "self.context!", SyntaxWarning, stacklevel=2)
+ self.parent().disconnect(*args)
+
+ def emit(self, *args):
+ """
+ Shortcut for self.parent().emit(*args)
+ """
+ self.parent().emit(*args)
+
+ def __getattr__(self, name, default=_marker):
+ """
+ Get attributes form parent.
+
+ Works similar to Zope 2's Implicit Acquisition wrapper.
+ """
+ try:
+ return getattr(self.parent(), name)
+ except AttributeError:
+ if default is not _marker:
+ return default
+ else:
+ raise AttributeError(name)
+
+ def initialize(self):
+ """
+ Initialize method
+
+ Must be implement in the subclass
+ """
+ raise NotImplementedError
+
+def connectSlotsByName(container, callobj):
+ """
+ A version of connectSlotsByName() that uses a potentially different object
+ to search for widget instances and to search for callbacks. This is more
+ flexible than the version that is provided with Qt because it allows you to
+ bind to callbacks on any object, not just on the widget container class
+ itself. You can also call this with a number of combinations of container
+ and callback objects.
+
+ See QtCore.QMetaObject.connectSlotsByName() for some background info.
+
+ Based on U{http://www.diotavelli.net/PyQtWiki/AutoConnectingSlots}
+
+ @param container: an instance whose attributes will be inspected to find
+ Qt widgets.
+ @type container: instance of a QObject subclass
+ @param callobj: an object which will be inspect for appropriately named methods
+ to be used as callbacks for widgets on 'container'.
+ @type callobj: instance of a QObject subclass
+
+ @note: You *must* use @pyqtSignature() if the method takes an argument!
+ """
+ #logging.debug('connectSlotsByName container=%s callobj=%s' %
+ # (container, callobj))
+ for name in dir(callobj):
+ method = getattr(callobj, name)
+ if not isinstance(method, UnboundMethod):
+ continue
+
+ mo = SLOT_RE.match(name)
+ if mo is None:
+ continue
+
+ nwidget, nsignal = mo.groups()
+ try:
+ widget = getattr(container, nwidget)
+ except AttributeError:
+ #logging.debug("Widget '%s' not found; method '%s' will not be "
+ # "bound." % (nwidget, name))
+ continue
+
+ # Support the QtCore.pyqtSignature decorator.
+ signature = '%s(%s)' % (nsignal, getattr(method, '_signature', ''))
+ #logging.debug('Connecting: %s to %s: %s' % (widget, signature, method))
+ QObject.connect(widget, SIGNAL(signature), method)
+
+def _mkMessageBox(context, icon='Information'):
+ """
+ Create a message box
+ """
+ assert icon in ('Question', 'Information', 'Warning', 'Critical')
+ if context:
+ mb = QtGui.QMessageBox(context)
+ else:
+ mb = QtGui.QMessageBox()
+ mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png"))
+ mb.setIcon(getattr(QtGui.QMessageBox, icon))
+ mb.setStandardButtons(QtGui.QMessageBox.Close)
+ return mb
+
+
+def criticalMB(context, title, text):
+ """
+ Critical message box
+ """
+ mb = _mkMessageBox(context, icon='Critical')
+ mb.setWindowTitle(title)
+ mb.setText(text)
+ return mb
+
+def warningMB(context, title, text):
+ """
+ warning message box
+ """
+ mb = _mkMessageBox(context, icon='Warning')
+ mb.setWindowTitle(title)
+ mb.setText(text)
+ return mb
+
+def infoMB(context, title, text):
+ """
+ Info message box
+ """
+ mb = _mkMessageBox(context, icon='Information')
+ mb.setStandardButtons(QtGui.QMessageBox.Ok)
+ mb.setWindowTitle(title)
+ mb.setText(text)
+ return mb
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|