[pyzo] 43/68: Use (part of) qtpy.
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Wed Sep 28 09:47:12 UTC 2016
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to branch debian/master
in repository pyzo.
commit ec010479c7996cb16157d7857780c259018e381f
Author: Almar Klein <almar.klein at gmail.com>
Date: Mon Sep 19 13:47:40 2016 +0200
Use (part of) qtpy.
---
pyzo/util/qt/QtCore.py | 47 ++++
pyzo/util/qt/QtGui.py | 103 +++++++++
pyzo/util/qt/QtWidgets.py | 122 ++++++++++
pyzo/util/qt/__init__.py | 463 +++++++++----------------------------
pyzo/util/qt/_patch/__init__.py | 0
pyzo/util/qt/_patch/qcombobox.py | 101 ++++++++
pyzo/util/qt/_patch/qheaderview.py | 82 +++++++
pyzo/util/qt/_version.py | 2 +
pyzo/util/qt/uic.py | 223 ++++++++++++++++++
9 files changed, 786 insertions(+), 357 deletions(-)
diff --git a/pyzo/util/qt/QtCore.py b/pyzo/util/qt/QtCore.py
new file mode 100644
index 0000000..bde48a7
--- /dev/null
+++ b/pyzo/util/qt/QtCore.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © 2014-2015 Colin Duquesnoy
+# Copyright © 2009- The Spyder Development Team
+#
+# Licensed under the terms of the MIT License
+# (see LICENSE.txt for details)
+
+"""
+Provides QtCore classes and functions.
+"""
+
+from . import PYQT5, PYQT4, PYSIDE, PythonQtError
+
+
+if PYQT5:
+ from PyQt5.QtCore import *
+ from PyQt5.QtCore import pyqtSignal as Signal
+ from PyQt5.QtCore import pyqtSlot as Slot
+ from PyQt5.QtCore import pyqtProperty as Property
+ from PyQt5.QtCore import QT_VERSION_STR as __version__
+
+ # Those are imported from `import *`
+ del pyqtSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR
+elif PYQT4:
+ from PyQt4.QtCore import *
+ # Those are things we inherited from Spyder that fix crazy crashes under
+ # some specific situations. (See #34)
+ from PyQt4.QtCore import QCoreApplication
+ from PyQt4.QtCore import Qt
+ from PyQt4.QtCore import pyqtSignal as Signal
+ from PyQt4.QtCore import pyqtSlot as Slot
+ from PyQt4.QtCore import pyqtProperty as Property
+ from PyQt4.QtGui import (QItemSelection, QItemSelectionModel,
+ QItemSelectionRange, QSortFilterProxyModel)
+ from PyQt4.QtCore import QT_VERSION_STR as __version__
+
+ # Those are imported from `import *`
+ del pyqtSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR
+elif PYSIDE:
+ from PySide.QtCore import *
+ from PySide.QtGui import (QItemSelection, QItemSelectionModel,
+ QItemSelectionRange, QSortFilterProxyModel)
+ import PySide.QtCore
+ __version__ = PySide.QtCore.__version__
+else:
+ raise PythonQtError('No Qt bindings could be found')
diff --git a/pyzo/util/qt/QtGui.py b/pyzo/util/qt/QtGui.py
new file mode 100644
index 0000000..99477c0
--- /dev/null
+++ b/pyzo/util/qt/QtGui.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © 2014-2015 Colin Duquesnoy
+# Copyright © 2009- The Spyder Development Team
+#
+# Licensed under the terms of the MIT License
+# (see LICENSE.txt for details)
+
+"""
+Provides QtGui classes and functions.
+.. warning:: Only PyQt4/PySide QtGui classes compatible with PyQt5.QtGui are
+ exposed here. Therefore, you need to treat/use this package as if it were
+ the ``PyQt5.QtGui`` module.
+"""
+
+from . import PYQT5, PYQT4, PYSIDE, PythonQtError
+
+
+if PYQT5:
+ from PyQt5.QtGui import *
+elif PYQT4:
+ from PyQt4.Qt import QKeySequence, QTextCursor
+ from PyQt4.QtGui import (QAbstractTextDocumentLayout, QActionEvent, QBitmap,
+ QBrush, QClipboard, QCloseEvent, QColor,
+ QConicalGradient, QContextMenuEvent, QCursor,
+ QDesktopServices, QDoubleValidator, QDrag,
+ QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent,
+ QDropEvent, QFileOpenEvent, QFocusEvent, QFont,
+ QFontDatabase, QFontInfo, QFontMetrics,
+ QFontMetricsF, QGlyphRun, QGradient, QHelpEvent,
+ QHideEvent, QHoverEvent, QIcon, QIconDragEvent,
+ QIconEngine, QImage, QImageIOHandler, QImageReader,
+ QImageWriter, QInputEvent, QInputMethodEvent,
+ QKeyEvent, QLinearGradient,
+ QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2,
+ QMatrix3x3, QMatrix3x4, QMatrix4x2, QMatrix4x3,
+ QMatrix4x4, QMouseEvent, QMoveEvent, QMovie,
+ QPaintDevice, QPaintEngine, QPaintEngineState,
+ QPaintEvent, QPainter, QPainterPath,
+ QPainterPathStroker, QPalette, QPen, QPicture,
+ QPictureIO, QPixmap, QPixmapCache, QPolygon,
+ QPolygonF, QQuaternion, QRadialGradient, QRawFont,
+ QRegExpValidator, QRegion, QResizeEvent,
+ QSessionManager, QShortcutEvent, QShowEvent,
+ QStandardItem, QStandardItemModel, QStaticText,
+ QStatusTipEvent, QSyntaxHighlighter, QTabletEvent,
+ QTextBlock, QTextBlockFormat, QTextBlockGroup,
+ QTextBlockUserData, QTextCharFormat,
+ QTextDocument, QTextDocumentFragment,
+ QTextDocumentWriter, QTextFormat, QTextFragment,
+ QTextFrame, QTextFrameFormat, QTextImageFormat,
+ QTextInlineObject, QTextItem, QTextLayout,
+ QTextLength, QTextLine, QTextList, QTextListFormat,
+ QTextObject, QTextObjectInterface, QTextOption,
+ QTextTable, QTextTableCell, QTextTableCellFormat,
+ QTextTableFormat, QTouchEvent, QTransform,
+ QValidator, QVector2D, QVector3D, QVector4D,
+ QWhatsThisClickedEvent, QWheelEvent,
+ QWindowStateChangeEvent, qAlpha, qBlue,
+ qFuzzyCompare, qGray, qGreen, qIsGray, qRed, qRgb,
+ qRgba, QIntValidator)
+elif PYSIDE:
+ from PySide.QtGui import (QAbstractTextDocumentLayout, QActionEvent, QBitmap,
+ QBrush, QClipboard, QCloseEvent, QColor,
+ QConicalGradient, QContextMenuEvent, QCursor,
+ QDesktopServices, QDoubleValidator, QDrag,
+ QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent,
+ QDropEvent, QFileOpenEvent, QFocusEvent, QFont,
+ QFontDatabase, QFontInfo, QFontMetrics,
+ QFontMetricsF, QGradient, QHelpEvent,
+ QHideEvent, QHoverEvent, QIcon, QIconDragEvent,
+ QIconEngine, QImage, QImageIOHandler, QImageReader,
+ QImageWriter, QInputEvent, QInputMethodEvent,
+ QKeyEvent, QKeySequence, QLinearGradient,
+ QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2,
+ QMatrix3x3, QMatrix3x4, QMatrix4x2, QMatrix4x3,
+ QMatrix4x4, QMouseEvent, QMoveEvent, QMovie,
+ QPaintDevice, QPaintEngine, QPaintEngineState,
+ QPaintEvent, QPainter, QPainterPath,
+ QPainterPathStroker, QPalette, QPen, QPicture,
+ QPictureIO, QPixmap, QPixmapCache, QPolygon,
+ QPolygonF, QQuaternion, QRadialGradient,
+ QRegExpValidator, QRegion, QResizeEvent,
+ QSessionManager, QShortcutEvent, QShowEvent,
+ QStandardItem, QStandardItemModel,
+ QStatusTipEvent, QSyntaxHighlighter, QTabletEvent,
+ QTextBlock, QTextBlockFormat, QTextBlockGroup,
+ QTextBlockUserData, QTextCharFormat, QTextCursor,
+ QTextDocument, QTextDocumentFragment,
+ QTextFormat, QTextFragment,
+ QTextFrame, QTextFrameFormat, QTextImageFormat,
+ QTextInlineObject, QTextItem, QTextLayout,
+ QTextLength, QTextLine, QTextList, QTextListFormat,
+ QTextObject, QTextObjectInterface, QTextOption,
+ QTextTable, QTextTableCell, QTextTableCellFormat,
+ QTextTableFormat, QTouchEvent, QTransform,
+ QValidator, QVector2D, QVector3D, QVector4D,
+ QWhatsThisClickedEvent, QWheelEvent,
+ QWindowStateChangeEvent, qAlpha, qBlue,
+ qGray, qGreen, qIsGray, qRed, qRgb, qRgba,
+ QIntValidator)
+else:
+ raise PythonQtError('No Qt bindings could be found')
diff --git a/pyzo/util/qt/QtWidgets.py b/pyzo/util/qt/QtWidgets.py
new file mode 100644
index 0000000..9613464
--- /dev/null
+++ b/pyzo/util/qt/QtWidgets.py
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © 2014-2015 Colin Duquesnoy
+# Copyright © 2009- The Spyder Developmet Team
+#
+# Licensed under the terms of the MIT License
+# (see LICENSE.txt for details)
+
+"""
+Provides widget classes and functions.
+.. warning:: Only PyQt4/PySide QtGui classes compatible with PyQt5.QtWidgets
+ are exposed here. Therefore, you need to treat/use this package as if it
+ were the ``PyQt5.QtWidgets`` module.
+"""
+
+from . import PYQT5, PYQT4, PYSIDE, PythonQtError
+from ._patch.qcombobox import patch_qcombobox
+from ._patch.qheaderview import introduce_renamed_methods_qheaderview
+
+
+if PYQT5:
+ from PyQt5.QtWidgets import *
+elif PYQT4:
+ from PyQt4.QtGui import *
+ QStyleOptionViewItem = QStyleOptionViewItemV4
+ del QStyleOptionViewItemV4
+
+ # These objects belong to QtGui
+ del (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard,
+ QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor,
+ QDesktopServices, QDoubleValidator, QDrag, QDragEnterEvent,
+ QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent,
+ QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics,
+ QFontMetricsF, QGlyphRun, QGradient, QHelpEvent, QHideEvent,
+ QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage,
+ QImageIOHandler, QImageReader, QImageWriter, QInputEvent,
+ QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient,
+ QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3,
+ QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, QMouseEvent,
+ QMoveEvent, QMovie, QPaintDevice, QPaintEngine, QPaintEngineState,
+ QPaintEvent, QPainter, QPainterPath, QPainterPathStroker, QPalette,
+ QPen, QPicture, QPictureIO, QPixmap, QPixmapCache, QPolygon,
+ QPolygonF, QQuaternion, QRadialGradient, QRawFont, QRegExpValidator,
+ QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent,
+ QStandardItem, QStandardItemModel, QStaticText, QStatusTipEvent,
+ QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat,
+ QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor,
+ QTextDocument, QTextDocumentFragment, QTextDocumentWriter,
+ QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat,
+ QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout,
+ QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject,
+ QTextObjectInterface, QTextOption, QTextTable, QTextTableCell,
+ QTextTableCellFormat, QTextTableFormat, QTouchEvent, QTransform,
+ QValidator, QVector2D, QVector3D, QVector4D, QWhatsThisClickedEvent,
+ QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, qFuzzyCompare,
+ qGray, qGreen, qIsGray, qRed, qRgb, qRgba, QIntValidator)
+
+ # These objects belong to QtPrintSupport
+ del (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine,
+ QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo)
+
+ # These objects belong to QtCore
+ del (QItemSelection, QItemSelectionModel, QItemSelectionRange,
+ QSortFilterProxyModel)
+
+ # Patch QComboBox to allow Python objects to be passed to userData
+ patch_qcombobox(QComboBox)
+
+ # QHeaderView: renamed methods
+ introduce_renamed_methods_qheaderview(QHeaderView)
+
+elif PYSIDE:
+ from PySide.QtGui import *
+ QStyleOptionViewItem = QStyleOptionViewItemV4
+ del QStyleOptionViewItemV4
+
+ # These objects belong to QtGui
+ del (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard,
+ QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor,
+ QDesktopServices, QDoubleValidator, QDrag, QDragEnterEvent,
+ QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent,
+ QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics,
+ QFontMetricsF, QGradient, QHelpEvent, QHideEvent,
+ QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage,
+ QImageIOHandler, QImageReader, QImageWriter, QInputEvent,
+ QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient,
+ QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3,
+ QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, QMouseEvent,
+ QMoveEvent, QMovie, QPaintDevice, QPaintEngine, QPaintEngineState,
+ QPaintEvent, QPainter, QPainterPath, QPainterPathStroker, QPalette,
+ QPen, QPicture, QPictureIO, QPixmap, QPixmapCache, QPolygon,
+ QPolygonF, QQuaternion, QRadialGradient, QRegExpValidator,
+ QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent,
+ QStandardItem, QStandardItemModel, QStatusTipEvent,
+ QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat,
+ QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor,
+ QTextDocument, QTextDocumentFragment,
+ QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat,
+ QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout,
+ QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject,
+ QTextObjectInterface, QTextOption, QTextTable, QTextTableCell,
+ QTextTableCellFormat, QTextTableFormat, QTouchEvent, QTransform,
+ QValidator, QVector2D, QVector3D, QVector4D, QWhatsThisClickedEvent,
+ QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, qGray, qGreen,
+ qIsGray, qRed, qRgb, qRgba, QIntValidator)
+
+ # These objects belong to QtPrintSupport
+ del (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine,
+ QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo)
+
+ # These objects belong to QtCore
+ del (QItemSelection, QItemSelectionModel, QItemSelectionRange,
+ QSortFilterProxyModel)
+
+ # Patch QComboBox to allow Python objects to be passed to userData
+ patch_qcombobox(QComboBox)
+
+ # QHeaderView: renamed methods
+ introduce_renamed_methods_qheaderview(QHeaderView)
+
+else:
+ raise PythonQtError('No Qt bindings could be found')
diff --git a/pyzo/util/qt/__init__.py b/pyzo/util/qt/__init__.py
index 26f7eb5..273df1d 100644
--- a/pyzo/util/qt/__init__.py
+++ b/pyzo/util/qt/__init__.py
@@ -1,385 +1,134 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2016, Almar Klein
#
-# This file is distributed under the terms of the (new) BSD License.
-
-""" Module that serves as a proxy for loading Qt libraries.
-
-This module has several goals:
- * Import QtCore, QtGui, etc. from PySide or PyQt4 (whichever is available).
- * Fix some incompatibilities between the two.
- * For applications that bring their own Qt libs, avoid clashes.
- * Allow using the PySide or PyQt4 libraries of the system
- (the ones in /usr/lib/...), so that frozen applications can look good.
-
-To use do ``from pyzo.util.qt import QtCore, QtGui``. Note that this proxy
-package is designed to be portable; it should be possible to use it in
-your own application or library.
-
-To use in frozen applications, create a qt.conf next to the executable,
-that has text as specified in DEFAULT_QT_CONF_TEXT. By modifying the
-text, preferences can be changed.
-
-
-Notes
------
-
-To prevent colliding of Qt libs when an app brings its own libs, in
-particular on KDE, the plugins of Qt should be disabled. This needs
-to be done in two places:
- * via qt.conf "Plugins = ''"
- * set the QT_PLUGIN_PATH variable to empty string
-
-The latter is equivalent to QtGui.QApplication.setLibraryPaths([]),
-but has the advantage that it can be set beforehand.
-
-A downside of the plugins being disabled is that the native style
-(GTK+, Oxygen) cannot be used and other features (Unity integrated
-toolbar) are not available. This module allows a work-around by
-loading the native libs.
+# Copyright © 2009- The Spyder Development Team
+# Copyright © 2014-2015 Colin Duquesnoy
+#
+# Licensed under the terms of the MIT License
+# (see LICENSE.txt for details)
"""
+**QtPy** is a shim over the various Python Qt bindings. It is used to write
+Qt binding indenpendent libraries or applications.
-import sys
-import os
-import imp
-import importlib
+The shim will automatically select the first available API (PyQt5, PyQt4 and
+finally PySide).
-VERBOSE = False
+You can force the use of one specific bindings (e.g. if your application is
+using one specific bindings and you need to use library that use QtPy) by
+setting up the ``QT_API`` environment variable.
+PyQt5
+=====
+For PyQt5, you don't have to set anything as it will be used automatically::
-def qt_name():
- """ Return the name of the Qt lib in use: 'PySide', 'PyQt4' or None.
- """
- try:
- importer_instance._import_qt()
- except ImportError:
- pass
- else:
- return importer_instance._qtPackage.__name__
+ >>> from qtpy import QtGui, QtWidgets, QtCore
+ >>> print(QtWidgets.QWidget)
+PyQt4
+=====
-def loadWidget(filename, parent=None):
- """ Load a widget from a .ui file. Returns a QWidget object.
- """
-
- # Note that PyQt4 has PyQt4.uic.loadUi(filename, basewidget)
- # allowing the newly created widget to inherit from a given widget
- # instance. This is not supported in PySide and therefore not
- # suported by this function.
-
- # Check
- if not os.path.isfile(filename):
- raise ValueError('Filename in loadWidget() is not a valid file.')
-
- if qt_name().lower() == 'pyside':
- # Import (from PySide import QtCore, QtUiTools)
- QtCore = importer_instance.load_module('QtCore')
- QtUiTools = importer_instance.load_module('QtUiTools')
- # Create loader and load widget
- loader = QtUiTools.QUiLoader()
- uifile = QtCore.QFile(filename)
- uifile.open(QtCore.QFile.ReadOnly)
- w = loader.load(uifile, parent)
- uifile.close()
- return w
- else:
- # Import (from PyQt4 import QtCore, uic)
- QtCore = importer_instance.load_module('QtCore')
- uic = importer_instance.load_module('uic')
- # Load widget
- w = uic.loadUi(filename)
- # We set the parent explicitly
- if parent is not None:
- w.setParent(parent)
- return w
+Set the ``QT_API`` environment variable to 'pyqt' before importing any python
+package::
+ >>> import os
+ >>> os.environ['QT_API'] = 'pyqt'
+ >>> from qtpy import QtGui, QtWidgets, QtCore
+ >>> print(QtWidgets.QWidget)
+PySide
+======
-class QtProxyImporter:
- """ Importer to import Qt modules, either from PySide or from PyQt,
- and either from this Python's version, or the system ones (if
- available and matching).
- """
-
- def __init__(self):
- self._qtPackage = None
- self._enabled = True
- self._import_path = None # None for 'normal' (non-system) import
-
-
- def find_module(self, fullname, path=None):
- """ This is called by Python's import mechanism. We return ourself
- only if this really looks like a Qt import, and when its imported
- as a submodule from this stub package.
- """
-
- # Only proceed if we are enabled
- if not self._enabled:
- return None
-
- # Get different parts of the module name
- nameparts = fullname.split('.')
-
- # sip is required by PyQt4
- if fullname == 'sip':
- self._import_qt()
- return self
-
- # If the import is relative to this package, we will try to
- # import relative to the selected qtPackage
- if '.'.join(nameparts[:-1]) == __name__:
- self._import_qt()
- return self
-
-
- def load_module(self, fullname):
- """ This method is called by Python's import mechanism after
- this instance has been returned from find_module. Here we
- actually import the module and do some furher processing.
- """
-
- # Get different parts of the module name
- nameparts = fullname.split('.')
- modulename = nameparts[-1]
-
- # We can only proceed if qtPackage was loaded
- if self._qtPackage is None:
- raise ImportError()
-
- # Get qt dir or dummy
- if self._import_path:
- qtdir = os.path.dirname(self._qtPackage.__file__)
- else:
- qtdir = '/nonexisting/dir/with/subdirs/dummy'
-
- # Get real name and path to load it from
- if fullname == self._qtPackage.__name__:
- return self._qtPackage
- elif fullname == 'sip':
- realmodulename = 'sip'
- searchdir = os.path.dirname(qtdir)
- elif modulename.startswith('Qt') or modulename == 'uic':
- realmodulename = '%s.%s' % (self._qtPackage.__name__, modulename)
- searchdir = qtdir
- else:
- raise ImportError()
-
- # Import. We also need to modify sys.path in case this is a system package
- if os.path.isdir(qtdir):
- if VERBOSE: print('load_module explicitly: %s' % fullname)
- sys.path.insert(0, os.path.dirname(qtdir))
- try:
- for entry in os.listdir(searchdir):
- if entry.startswith(modulename+'.'):
- m = imp.load_dynamic( realmodulename,
- os.path.join(searchdir, entry))
- break
- else:
- raise ImportError('Could not import %s' % realmodulename)
- finally:
- sys.path.pop(0)
- else:
- # Module can be inside a zip-file when frozen
- # Import normally, and disable ourselves so we do not recurse
- if VERBOSE: print('load_module normally: %s' % realmodulename)
- self._enabled = False
- try:
- p = __import__(realmodulename)
- finally:
- self._enabled = True
- # Get the actual modele
- if '.' in realmodulename:
- m = getattr(p, modulename)
- else:
- m = p
-
- # Also register in sys.modules under the name as it was imported
- sys.modules[realmodulename] = m
- sys.modules[fullname] = m
-
- # Fix some compatibility issues
- self._fix_compat(m)
-
- # Done
- return m
-
-
- def _determine_preference(self):
- """ Determine preference by reading from qt.conf.
- """
-
- # Get dirs to look for qt.conf
- dirs = [os.path.dirname(sys.executable)]
- script_dir = ''
- if sys.path:
- script_dir = sys.path[0]
- if getattr(sys, 'frozen', None):
- script_dir = os.path.dirname(script_dir)
- dirs.append(script_dir)
-
- # Read qt.conf
- for dir in dirs:
- qt_conf = os.path.join(dir, 'qt.conf')
- if os.path.isfile(qt_conf):
- text = open(qt_conf, 'rb').read().decode('utf-8', 'ignore')
- break
- else:
- text = ''
-
- # Parse qt.conf
- prefer_system = False
- prefer_toolkit = ''
- #
- for line in text.splitlines():
- line = line.split('#',1)[0].strip()
- if '=' not in line:
- continue
- key, val = [i.strip() for i in line.split('=', 1)]
- if key == 'PreferSystem' and val.lower() in ('yes', 'true', '1'):
- prefer_system = True
- if key == 'PreferToolkit':
- prefer_toolkit = val
-
- return prefer_system, prefer_toolkit
-
-
- def _import_qt(self, toolkit=None):
- """ This is where we import either PySide or PyQt4.
- This is done only once.
- """
-
- # Make qtPackage global and only proceed if its not set yet
- if self._qtPackage is not None:
- return
-
- # Establish preference
- prefer_system, prefer_toolkit = self._determine_preference()
-
- # Check toolkit, use pyside by default
- prefer_toolkit = toolkit or prefer_toolkit or 'pyside'
- if prefer_toolkit.lower() not in ('pyside', 'pyqt4'):
- prefer_toolkit = 'pyside'
- print('Invalid Qt toolit preference given: "%s"' % prefer_toolkit)
-
- # Really import
- self._qtPackage = self._import_qt_for_real(prefer_system, prefer_toolkit)
-
- # Disable plugins if necessary
- if self._qtPackage and sys.platform.startswith('linux'):
- if not self._qtPackage.__file__.startswith('/usr'):
- os.environ['QT_PLUGIN_PATH'] = ''
-
-
- def _import_qt_for_real(self, prefer_system, prefer_toolkit):
- """ The actual importing.
- """
-
- # Perhaps it is already loaded
- if 'PySide' in sys.modules:
- return sys.modules['PySide']
- elif 'PyQt4' in sys.modules:
- return sys.modules['PyQt4']
-
- # Init potential imports
- pyside_imports = [('PySide', None)]
- pyqt4_imports = [('PyQt4', None)]
- pyside_system_imports = []
- pyqt4_system_imports = []
-
- # Get possible paths, but only on Linux
- if sys.platform.startswith('linux'):
- # Determine where PySide or PyQt4 can be
- ver = sys.version[:3]
- possible_paths = ['/usr/local/lib/python%s/dist-packages' % ver,
- os.path.expanduser('~/.local/lib/python%s/site-packages' % ver)]
- if os.path.isdir('/usr/lib/python%s' % ver):
- possible_paths.append('/usr/lib/python%s/dist-packages' % ver[0])
- # Trty if it is there
- for path in possible_paths:
- if os.path.isdir(os.path.join(path, 'PySide')):
- pyside_system_imports.append(('PySide', path))
- if os.path.isdir(os.path.join(path, 'PyQt4')):
- pyqt4_system_imports.append(('PyQt4', path))
-
- # Combine imports in right order
- if prefer_system:
- if 'pyside' == prefer_toolkit.lower():
- imports = pyside_system_imports + pyqt4_system_imports + \
- pyside_imports + pyqt4_imports
- else:
- imports = pyqt4_system_imports + pyside_system_imports + \
- pyqt4_imports + pyside_imports
- else:
- if 'pyside' == prefer_toolkit.lower():
- imports = pyside_imports + pyqt4_imports #+ \
- #pyside_system_imports + pyqt4_system_imports
- else:
- imports = pyqt4_imports + pyside_imports #+ \
- #pyqt4_system_imports + pyside_system_imports
-
- # Try importing
- package = None
- for package_name, path in imports:
- if path:
- sys.path.insert(0, path)
- if VERBOSE: print('Attempting to import %s (system=%i)' % (package_name, bool(path)))
- self._import_path = path
- try:
- return __import__(package_name, level=0)
- except ImportError as err:
- if VERBOSE: print('Import failed')
- finally:
- if path:
- sys.path.pop(0)
- else:
- raise ImportError('Could not import PySide nor PyQt4.')
-
-
- def _fix_compat(self, m):
- """ Fix incompatibilities between PySide and PyQt4.
- """
- if self._qtPackage.__name__ == 'PySide':
- pass
- else:
- if m.__name__.endswith('QtCore'):
- m.Signal = m.pyqtSignal
-
- # todo: more compat, like uic loading
-
+Set the QT_API environment variable to 'pyside' before importing other
+packages::
-importer_instance = QtProxyImporter()
-sys.meta_path.insert(0, importer_instance)
+ >>> import os
+ >>> os.environ['QT_API'] = 'pyside'
+ >>> from qtpy import QtGui, QtWidgets, QtCore
+ >>> print(QtWidgets.QWidget)
+"""
+import os
+# Version of QtPy
+from ._version import __version__
-DEFAULT_QT_CONF_TEXT = """## This file contains configuration options for Qt.
-## It disables plugins so that an application that brings its own
-## Qt libraries do not clashs with the native Qt. It also has options
-## that the pyzo qt proxy uses to allow you to use your system
-## PySide/PyQt4 libraries.
+#: Qt API environment variable name
+QT_API = 'QT_API'
+#: names of the expected PyQt5 api
+PYQT5_API = ['pyqt5']
+#: names of the expected PyQt4 api
+PYQT4_API = [
+ 'pyqt', # name used in IPython.qt
+ 'pyqt4' # pyqode.qt original name
+]
+#: names of the expected PySide api
+PYSIDE_API = ['pyside']
-[Py]
+os.environ.setdefault(QT_API, 'pyqt5')
+API = os.environ[QT_API].lower()
+assert API in (PYQT5_API + PYQT4_API + PYSIDE_API)
-## Preferred toolkit: PySide or PyQt4
-PreferToolkit = PySide
+is_old_pyqt = is_pyqt46 = False
+PYQT5 = True
+PYQT4 = PYSIDE = False
-## Uncomment if pyzo should try to use the system libraries
-## Note that you version of Python must be ABI compatible with the
-## version on your system for this to work
-#PreferSystem = yes
+class PythonQtError(Exception):
+ """Error raise if no bindings could be selected"""
+ pass
-[Paths]
-## This disables plugins, avoiding Qt library clashes
-Plugins = ''
+if API in PYQT5_API:
+ try:
+ from PyQt5.Qt import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore
+ from PyQt5.Qt import QT_VERSION_STR as QT_VERSION # analysis:ignore
+ PYSIDE_VERSION = None
+ except ImportError:
+ API = os.environ['QT_API'] = 'pyqt'
-## On Ubuntu Unity, if PreferSystem is enabled, uncomment this to
-## enable the fancy menu bar.
-#Plugins = /usr/lib/x86_64-linux-gnu/qt4/plugins
+if API in PYQT4_API:
+ try:
+ import sip
+ try:
+ sip.setapi('QString', 2)
+ sip.setapi('QVariant', 2)
+ sip.setapi('QDate', 2)
+ sip.setapi('QDateTime', 2)
+ sip.setapi('QTextStream', 2)
+ sip.setapi('QTime', 2)
+ sip.setapi('QUrl', 2)
+ except AttributeError:
+ # PyQt < v4.6
+ pass
+ from PyQt4.Qt import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore
+ from PyQt4.Qt import QT_VERSION_STR as QT_VERSION # analysis:ignore
+ PYSIDE_VERSION = None
+ PYQT5 = False
+ PYQT4 = True
+ except ImportError:
+ API = os.environ['QT_API'] = 'pyside'
+ else:
+ is_old_pyqt = PYQT_VERSION.startswith(('4.4', '4.5', '4.6', '4.7'))
+ is_pyqt46 = PYQT_VERSION.startswith('4.6')
-"""
+if API in PYSIDE_API:
+ try:
+ from PySide import __version__ as PYSIDE_VERSION # analysis:ignore
+ from PySide.QtCore import __version__ as QT_VERSION # analysis:ignore
+ PYQT_VERSION = None
+ PYQT5 = False
+ PYSIDE = True
+ except ImportError:
+ raise PythonQtError('No Qt bindings could be found')
+
+API_NAME = {'pyqt5': 'PyQt5', 'pyqt': 'PyQt4', 'pyqt4': 'PyQt4',
+ 'pyside': 'PySide'}[API]
+if PYQT4:
+ import sip
+ try:
+ API_NAME += (" (API v{0})".format(sip.getapi('QString')))
+ except AttributeError:
+ pass
diff --git a/pyzo/util/qt/_patch/__init__.py b/pyzo/util/qt/_patch/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyzo/util/qt/_patch/qcombobox.py b/pyzo/util/qt/_patch/qcombobox.py
new file mode 100644
index 0000000..d3e98be
--- /dev/null
+++ b/pyzo/util/qt/_patch/qcombobox.py
@@ -0,0 +1,101 @@
+# The code below, as well as the associated test were adapted from
+# qt-helpers, which was released under a 3-Clause BSD license:
+#
+# Copyright (c) 2015, Chris Beaumont and Thomas Robitaille
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of the Glue project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+def patch_qcombobox(QComboBox):
+ """
+ In PySide, using Python objects as userData in QComboBox causes
+ Segmentation faults under certain conditions. Even in cases where it
+ doesn't, findData does not work correctly. Likewise, findData also does not
+ work correctly with Python objects when using PyQt4. On the other hand,
+ PyQt5 deals with this case correctly. We therefore patch QComboBox when
+ using PyQt4 and PySide to avoid issues.
+ """
+
+ from ..QtGui import QIcon
+ from ..QtCore import Qt, QObject
+
+ class userDataWrapper():
+ """
+ This class is used to wrap any userData object. If we don't do this,
+ then certain types of objects can cause segmentation faults or issues
+ depending on whether/how __getitem__ is defined.
+ """
+ def __init__(self, data):
+ self.data = data
+
+ _addItem = QComboBox.addItem
+
+ def addItem(self, *args, **kwargs):
+ if len(args) == 3 or (not isinstance(args[0], QIcon)
+ and len(args) == 2):
+ args, kwargs['userData'] = args[:-1], args[-1]
+ if 'userData' in kwargs:
+ kwargs['userData'] = userDataWrapper(kwargs['userData'])
+ _addItem(self, *args, **kwargs)
+
+ _insertItem = QComboBox.insertItem
+
+ def insertItem(self, *args, **kwargs):
+ if len(args) == 4 or (not isinstance(args[1], QIcon)
+ and len(args) == 3):
+ args, kwargs['userData'] = args[:-1], args[-1]
+ if 'userData' in kwargs:
+ kwargs['userData'] = userDataWrapper(kwargs['userData'])
+ _insertItem(self, *args, **kwargs)
+
+ _setItemData = QComboBox.setItemData
+
+ def setItemData(self, index, value, role=Qt.UserRole):
+ value = userDataWrapper(value)
+ _setItemData(self, index, value, role=role)
+
+ _itemData = QComboBox.itemData
+
+ def itemData(self, index, role=Qt.UserRole):
+ userData = _itemData(self, index, role=role)
+ if isinstance(userData, userDataWrapper):
+ userData = userData.data
+ return userData
+
+ def findData(self, value):
+ for i in range(self.count()):
+ if self.itemData(i) == value:
+ return i
+ return -1
+
+ QComboBox.addItem = addItem
+ QComboBox.insertItem = insertItem
+ QComboBox.setItemData = setItemData
+ QComboBox.itemData = itemData
+ QComboBox.findData = findData
\ No newline at end of file
diff --git a/pyzo/util/qt/_patch/qheaderview.py b/pyzo/util/qt/_patch/qheaderview.py
new file mode 100644
index 0000000..8bef839
--- /dev/null
+++ b/pyzo/util/qt/_patch/qheaderview.py
@@ -0,0 +1,82 @@
+def introduce_renamed_methods_qheaderview(QHeaderView):
+
+ _isClickable = QHeaderView.isClickable
+ def sectionsClickable(self):
+ """
+ QHeaderView.sectionsClickable() -> bool
+ """
+ return _isClickable(self)
+ QHeaderView.sectionsClickable = sectionsClickable
+ def isClickable(self):
+ raise Exception('isClickable is only available in Qt4. Use '
+ 'sectionsClickable instead.')
+ QHeaderView.isClickable = isClickable
+
+
+ _isMovable = QHeaderView.isMovable
+ def sectionsMovable(self):
+ """
+ QHeaderView.sectionsMovable() -> bool
+ """
+ return _isMovable(self)
+ QHeaderView.sectionsMovable = sectionsMovable
+ def isMovable(self):
+ raise Exception('isMovable is only available in Qt4. Use '
+ 'sectionsMovable instead.')
+ QHeaderView.isMovable = isMovable
+
+
+ _resizeMode = QHeaderView.resizeMode
+ def sectionResizeMode(self, logicalIndex):
+ """
+ QHeaderView.sectionResizeMode(int) -> QHeaderView.ResizeMode
+ """
+ return _resizeMode(self, logicalIndex)
+ QHeaderView.sectionResizeMode = sectionResizeMode
+ def resizeMode(self, logicalIndex):
+ raise Exception('resizeMode is only available in Qt4. Use '
+ 'sectionResizeMode instead.')
+ QHeaderView.resizeMode = resizeMode
+
+ _setClickable = QHeaderView.setClickable
+ def setSectionsClickable(self, clickable):
+ """
+ QHeaderView.setSectionsClickable(bool)
+ """
+ return _setClickable(self, clickable)
+ QHeaderView.setSectionsClickable = setSectionsClickable
+ def setClickable(self, clickable):
+ raise Exception('setClickable is only available in Qt4. Use '
+ 'setSectionsClickable instead.')
+ QHeaderView.setClickable = setClickable
+
+
+ _setMovable = QHeaderView.setMovable
+ def setSectionsMovable(self, movable):
+ """
+ QHeaderView.setSectionsMovable(bool)
+ """
+ return _setMovable(self, movable)
+ QHeaderView.setSectionsMovable = setSectionsMovable
+ def setMovable(self, movable):
+ raise Exception('setMovable is only available in Qt4. Use '
+ 'setSectionsMovable instead.')
+ QHeaderView.setMovable = setMovable
+
+
+ _setResizeMode = QHeaderView.setResizeMode
+ def setSectionResizeMode(self, *args):
+ """
+ QHeaderView.setSectionResizeMode(QHeaderView.ResizeMode)
+ QHeaderView.setSectionResizeMode(int, QHeaderView.ResizeMode)
+ """
+ _setResizeMode(self, *args)
+ QHeaderView.setSectionResizeMode = setSectionResizeMode
+ def setResizeMode(self, *args):
+ raise Exception('setResizeMode is only available in Qt4. Use '
+ 'setSectionResizeMode instead.')
+ QHeaderView.setResizeMode = setResizeMode
+
+
+
+
diff --git a/pyzo/util/qt/_version.py b/pyzo/util/qt/_version.py
new file mode 100644
index 0000000..a89112b
--- /dev/null
+++ b/pyzo/util/qt/_version.py
@@ -0,0 +1,2 @@
+version_info = (1, 2, 0, 'dev0')
+__version__ = '.'.join(map(str, version_info))
diff --git a/pyzo/util/qt/uic.py b/pyzo/util/qt/uic.py
new file mode 100644
index 0000000..abca491
--- /dev/null
+++ b/pyzo/util/qt/uic.py
@@ -0,0 +1,223 @@
+import os
+
+from . import PYSIDE, PYQT4, PYQT5
+from .QtWidgets import QComboBox
+
+__all__ = ['loadUi']
+
+if PYQT5:
+
+ from PyQt5.uic import loadUi
+
+elif PYQT4:
+
+ from PyQt4.uic import loadUi
+
+elif PYSIDE:
+
+ # In PySide, loadUi does not exist, so we define it using QUiLoader, and
+ # then make sure we expose that function. This is adapted from qt-helpers
+ # which was released under a 3-clause BSD license:
+ # qt-helpers - a common front-end to various Qt modules
+ #
+ # Copyright (c) 2015, Chris Beaumont and Thomas Robitaille
+ #
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above copyright
+ # notice, this list of conditions and the following disclaimer in the
+ # documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of the Glue project nor the names of its contributors
+ # may be used to endorse or promote products derived from this software
+ # without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ #
+ # Which itself was based on the solution at
+ #
+ # https://gist.github.com/cpbotha/1b42a20c8f3eb9bb7cb8
+ #
+ # which was released under the MIT license:
+ #
+ # Copyright (c) 2011 Sebastian Wiesner <lunaryorn at gmail.com>
+ # Modifications by Charl Botha <cpbotha at vxlabs.com>
+ #
+ # Permission is hereby granted, free of charge, to any person obtaining a
+ # copy of this software and associated documentation files (the "Software"),
+ # to deal in the Software without restriction, including without limitation
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ # and/or sell copies of the Software, and to permit persons to whom the
+ # Software is furnished to do so, subject to the following conditions:
+ #
+ # The above copyright notice and this permission notice shall be included in
+ # all copies or substantial portions of the Software.
+ #
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ # DEALINGS IN THE SOFTWARE.
+
+ from PySide.QtCore import QMetaObject
+ from PySide.QtUiTools import QUiLoader
+
+ class UiLoader(QUiLoader):
+ """
+ Subclass of :class:`~PySide.QtUiTools.QUiLoader` to create the user
+ interface in a base instance.
+
+ Unlike :class:`~PySide.QtUiTools.QUiLoader` itself this class does not
+ create a new instance of the top-level widget, but creates the user
+ interface in an existing instance of the top-level class if needed.
+
+ This mimics the behaviour of :func:`PyQt4.uic.loadUi`.
+ """
+
+ def __init__(self, baseinstance, customWidgets=None):
+ """
+ Create a loader for the given ``baseinstance``.
+
+ The user interface is created in ``baseinstance``, which must be an
+ instance of the top-level class in the user interface to load, or a
+ subclass thereof.
+
+ ``customWidgets`` is a dictionary mapping from class name to class
+ object for custom widgets. Usually, this should be done by calling
+ registerCustomWidget on the QUiLoader, but with PySide 1.1.2 on
+ Ubuntu 12.04 x86_64 this causes a segfault.
+
+ ``parent`` is the parent object of this loader.
+ """
+
+ QUiLoader.__init__(self, baseinstance)
+
+ self.baseinstance = baseinstance
+
+ if customWidgets is None:
+ self.customWidgets = {}
+ else:
+ self.customWidgets = customWidgets
+
+ def createWidget(self, class_name, parent=None, name=''):
+ """
+ Function that is called for each widget defined in ui file,
+ overridden here to populate baseinstance instead.
+ """
+
+ if parent is None and self.baseinstance:
+ # supposed to create the top-level widget, return the base
+ # instance instead
+ return self.baseinstance
+
+ else:
+
+ # For some reason, Line is not in the list of available
+ # widgets, but works fine, so we have to special case it here.
+ if class_name in self.availableWidgets() or class_name == 'Line':
+ # create a new widget for child widgets
+ widget = QUiLoader.createWidget(self, class_name, parent, name)
+
+ else:
+ # If not in the list of availableWidgets, must be a custom
+ # widget. This will raise KeyError if the user has not
+ # supplied the relevant class_name in the dictionary or if
+ # customWidgets is empty.
+ try:
+ widget = self.customWidgets[class_name](parent)
+ except KeyError:
+ raise Exception('No custom widget ' + class_name + ' '
+ 'found in customWidgets')
+
+ if self.baseinstance:
+ # set an attribute for the new child widget on the base
+ # instance, just like PyQt4.uic.loadUi does.
+ setattr(self.baseinstance, name, widget)
+
+ return widget
+
+ def _get_custom_widgets(ui_file):
+ """
+ This function is used to parse a ui file and look for the <customwidgets>
+ section, then automatically load all the custom widget classes.
+ """
+
+ import sys
+ import importlib
+ from xml.etree.ElementTree import ElementTree
+
+ # Parse the UI file
+ etree = ElementTree()
+ ui = etree.parse(ui_file)
+
+ # Get the customwidgets section
+ custom_widgets = ui.find('customwidgets')
+
+ if custom_widgets is None:
+ return {}
+
+ custom_widget_classes = {}
+
+ for custom_widget in custom_widgets.getchildren():
+
+ cw_class = custom_widget.find('class').text
+ cw_header = custom_widget.find('header').text
+
+ module = importlib.import_module(cw_header)
+
+ custom_widget_classes[cw_class] = getattr(module, cw_class)
+
+ return custom_widget_classes
+
+ def loadUi(uifile, baseinstance=None, workingDirectory=None):
+ """
+ Dynamically load a user interface from the given ``uifile``.
+
+ ``uifile`` is a string containing a file name of the UI file to load.
+
+ If ``baseinstance`` is ``None``, the a new instance of the top-level
+ widget will be created. Otherwise, the user interface is created within
+ the given ``baseinstance``. In this case ``baseinstance`` must be an
+ instance of the top-level widget class in the UI file to load, or a
+ subclass thereof. In other words, if you've created a ``QMainWindow``
+ interface in the designer, ``baseinstance`` must be a ``QMainWindow``
+ or a subclass thereof, too. You cannot load a ``QMainWindow`` UI file
+ with a plain :class:`~PySide.QtGui.QWidget` as ``baseinstance``.
+
+ :method:`~PySide.QtCore.QMetaObject.connectSlotsByName()` is called on
+ the created user interface, so you can implemented your slots according
+ to its conventions in your widget class.
+
+ Return ``baseinstance``, if ``baseinstance`` is not ``None``. Otherwise
+ return the newly created instance of the user interface.
+ """
+
+ # We parse the UI file and import any required custom widgets
+ customWidgets = _get_custom_widgets(uifile)
+
+ loader = UiLoader(baseinstance, customWidgets)
+
+ if workingDirectory is not None:
+ loader.setWorkingDirectory(workingDirectory)
+
+ widget = loader.load(uifile)
+ QMetaObject.connectSlotsByName(widget)
+ return widget
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/pyzo.git
More information about the debian-science-commits
mailing list