binding_helper.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Copyright (c) 2011, Dirk Thomas, Dorian Scholz, TU Darmstadt
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions
00008 # are met:
00009 #
00010 #   * Redistributions of source code must retain the above copyright
00011 #     notice, this list of conditions and the following disclaimer.
00012 #   * Redistributions in binary form must reproduce the above
00013 #     copyright notice, this list of conditions and the following
00014 #     disclaimer in the documentation and/or other materials provided
00015 #     with the distribution.
00016 #   * Neither the name of the TU Darmstadt nor the names of its
00017 #     contributors may be used to endorse or promote products derived
00018 #     from this software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 # POSSIBILITY OF SUCH DAMAGE.
00032 
00033 try:
00034     import builtins
00035 except ImportError:
00036     import __builtin__ as builtins
00037 import os
00038 import sys
00039 
00040 
00041 QT_BINDING = None
00042 QT_BINDING_MODULES = {}
00043 QT_BINDING_VERSION = None
00044 
00045 
00046 def _select_qt_binding(binding_name=None, binding_order=None):
00047     global QT_BINDING, QT_BINDING_VERSION
00048 
00049     # order of default bindings can be changed here
00050     DEFAULT_BINDING_ORDER = ['pyqt', 'pyside']
00051     binding_order = binding_order or DEFAULT_BINDING_ORDER
00052 
00053     # determine binding preference
00054     if binding_name:
00055         if binding_name not in binding_order:
00056             raise ImportError("Qt binding '%s' is unknown" % binding_name)
00057         binding_order = [binding_name]
00058 
00059     required_modules = [
00060         'QtCore',
00061         'QtGui'
00062     ]
00063     optional_modules = [
00064         'QtDeclarative',
00065         'QtMultimedia',
00066         'QtNetwork',
00067         'QtOpenGL',
00068         'QtOpenVG',
00069         'QtScript',
00070         'QtScriptTools'
00071         'QtSql',
00072         'QtSvg',
00073         'QtWebKit',
00074         'QtXml',
00075         'QtXmlPatterns',
00076     ]
00077 
00078     # try to load preferred bindings
00079     error_msgs = []
00080     for binding_name in binding_order:
00081         try:
00082             binding_loader = getattr(sys.modules[__name__], '_load_%s' % binding_name, None)
00083             if binding_loader:
00084                 QT_BINDING_VERSION = binding_loader(required_modules, optional_modules)
00085                 QT_BINDING = binding_name
00086                 break
00087             else:
00088                 error_msgs.append("  Binding loader '_load_%s' not found." % binding_name)
00089         except ImportError as e:
00090             error_msgs.append("  ImportError for '%s': %s" % (binding_name, e))
00091 
00092     if not QT_BINDING:
00093         raise ImportError("Could not find Qt binding (looked for: %s):\n%s" % (', '.join(["'%s'" % b for b in binding_order]), '\n'.join(error_msgs)))
00094 
00095 
00096 def _register_binding_module(module_name, module):
00097     # register module using only its own name (TODO: legacy compatibility, remove when possible)
00098     sys.modules[module_name] = module
00099     # add module to the binding modules
00100     QT_BINDING_MODULES[module_name] = module
00101 
00102 
00103 def _named_import(name):
00104     parts = name.split('.')
00105     assert(len(parts) >= 2)
00106     module = builtins.__import__(name)
00107     for m in parts[1:]:
00108         module = module.__dict__[m]
00109     module_name = parts[-1]
00110     _register_binding_module(module_name, module)
00111 
00112 
00113 def _named_optional_import(name):
00114     try:
00115         _named_import(name)
00116     except ImportError:
00117         pass
00118 
00119 
00120 def _load_pyqt(required_modules, optional_modules):
00121     # set environment variable QT_API for matplotlib
00122     os.environ['QT_API'] = 'pyqt'
00123 
00124     # select PyQt4 API, see http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html
00125     import sip
00126     try:
00127         sip.setapi('QDate', 2)
00128         sip.setapi('QDateTime', 2)
00129         sip.setapi('QString', 2)
00130         sip.setapi('QTextStream', 2)
00131         sip.setapi('QTime', 2)
00132         sip.setapi('QUrl', 2)
00133         sip.setapi('QVariant', 2)
00134     except ValueError as e:
00135         raise RuntimeError('Could not set API version (%s): did you import PyQt4 directly?' % e)
00136 
00137     # register required and optional PyQt4 modules
00138     for module_name in required_modules:
00139         _named_import('PyQt4.%s' % module_name)
00140     for module_name in optional_modules:
00141         _named_optional_import('PyQt4.%s' % module_name)
00142 
00143     # set some names for compatibility with PySide
00144     sys.modules['QtCore'].Signal = sys.modules['QtCore'].pyqtSignal
00145     sys.modules['QtCore'].Slot = sys.modules['QtCore'].pyqtSlot
00146     sys.modules['QtCore'].Property = sys.modules['QtCore'].pyqtProperty
00147 
00148     # try to register PyQt4.Qwt5 module
00149     try:
00150         import PyQt4.Qwt5
00151         _register_binding_module('Qwt', PyQt4.Qwt5)
00152     except ImportError:
00153         pass
00154 
00155     global _loadUi
00156 
00157     def _loadUi(uifile, baseinstance=None, custom_widgets_=None):
00158         from PyQt4 import uic
00159         return uic.loadUi(uifile, baseinstance=baseinstance)
00160 
00161     # override specific function to improve compatibility between different bindings
00162     from QtGui import QFileDialog
00163     QFileDialog.getOpenFileName = QFileDialog.getOpenFileNameAndFilter
00164     QFileDialog.getSaveFileName = QFileDialog.getSaveFileNameAndFilter
00165 
00166     import PyQt4.QtCore
00167     return PyQt4.QtCore.PYQT_VERSION_STR
00168 
00169 
00170 def _load_pyside(required_modules, optional_modules):
00171     # set environment variable QT_API for matplotlib
00172     os.environ['QT_API'] = 'pyside'
00173 
00174     # register required and optional PySide modules
00175     for module_name in required_modules:
00176         _named_import('PySide.%s' % module_name)
00177     for module_name in optional_modules:
00178         _named_optional_import('PySide.%s' % module_name)
00179 
00180     # set some names for compatibility with PyQt4
00181     sys.modules['QtCore'].pyqtSignal = sys.modules['QtCore'].Signal
00182     sys.modules['QtCore'].pyqtSlot = sys.modules['QtCore'].Slot
00183     sys.modules['QtCore'].pyqtProperty = sys.modules['QtCore'].Property
00184 
00185     # try to register PySideQwt module
00186     try:
00187         import PySideQwt
00188         _register_binding_module('Qwt', PySideQwt)
00189     except ImportError:
00190         pass
00191 
00192     global _loadUi
00193 
00194     def _loadUi(uifile, baseinstance=None, custom_widgets=None):
00195         from PySide.QtUiTools import QUiLoader
00196         from PySide.QtCore import QMetaObject
00197 
00198         class CustomUiLoader(QUiLoader):
00199             class_aliases = {
00200                 'Line': 'QFrame',
00201             }
00202 
00203             def __init__(self, baseinstance=None, custom_widgets=None):
00204                 super(CustomUiLoader, self).__init__(baseinstance)
00205                 self._base_instance = baseinstance
00206                 self._custom_widgets = custom_widgets or {}
00207 
00208             def createWidget(self, class_name, parent=None, name=''):
00209                 # don't create the top-level widget, if a base instance is set
00210                 if self._base_instance and not parent:
00211                     return self._base_instance
00212 
00213                 if class_name in self._custom_widgets:
00214                     widget = self._custom_widgets[class_name](parent)
00215                 else:
00216                     widget = QUiLoader.createWidget(self, class_name, parent, name)
00217 
00218                 if str(type(widget)).find(self.class_aliases.get(class_name, class_name)) < 0:
00219                     sys.modules['QtCore'].qDebug(str('PySide.loadUi(): could not find widget class "%s", defaulting to "%s"' % (class_name, type(widget))))
00220 
00221                 if self._base_instance:
00222                     setattr(self._base_instance, name, widget)
00223 
00224                 return widget
00225 
00226         loader = CustomUiLoader(baseinstance, custom_widgets)
00227 
00228         # instead of passing the custom widgets, they should be registered using QUiLoader.registerCustomWidget(),
00229         # but this does not work in PySide 1.0.6: it simply segfaults...
00230         #loader = CustomUiLoader(baseinstance)
00231         #custom_widgets = custom_widgets or {}
00232         #for custom_widget in custom_widgets.values():
00233         #    loader.registerCustomWidget(custom_widget)
00234 
00235         ui = loader.load(uifile)
00236         QMetaObject.connectSlotsByName(ui)
00237         return ui
00238 
00239     import PySide
00240     return PySide.__version__
00241 
00242 
00243 def loadUi(uifile, baseinstance=None, custom_widgets=None):
00244     """
00245     @type uifile: str
00246     @param uifile: Absolute path of .ui file
00247     @type baseinstance: QWidget
00248     @param baseinstance: the optional instance of the Qt base class.
00249                          If specified then the user interface is created in
00250                          it. Otherwise a new instance of the base class is
00251                          automatically created.
00252     @type custom_widgets: dict of {str:QWidget}
00253     @param custom_widgets: Class name and type of the custom classes used
00254                            in uifile if any. This can be None if no custom
00255                            class is in use. (Note: this is only necessary
00256                            for PySide, see
00257                            http://answers.ros.org/question/56382/what-does-python_qt_bindingloaduis-3rd-arg-do-in-pyqt-binding/
00258                            for more information)
00259     """
00260     return _loadUi(uifile, baseinstance, custom_widgets)
00261 
00262 
00263 _select_qt_binding(
00264     getattr(sys, 'SELECT_QT_BINDING', None),
00265     getattr(sys, 'SELECT_QT_BINDING_ORDER', None),
00266 )


python_qt_binding
Author(s): Dave Hershberger, Dorian Scholz, Dirk Thomas
autogenerated on Mon Oct 6 2014 03:57:26