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 __builtin__ as builtins
00035 except ImportError:
00036     # since the 'future' package provides a 'builtins' module in Python 2
00037     # this must not be checked second
00038     import builtins
00039 import os
00040 import sys
00041 
00042 
00043 QT_BINDING = None
00044 QT_BINDING_MODULES = {}
00045 QT_BINDING_VERSION = None
00046 
00047 
00048 def _select_qt_binding(binding_name=None, binding_order=None):
00049     global QT_BINDING, QT_BINDING_VERSION
00050 
00051     # order of default bindings can be changed here
00052     DEFAULT_BINDING_ORDER = ['pyqt', 'pyside']
00053     binding_order = binding_order or DEFAULT_BINDING_ORDER
00054 
00055     # determine binding preference
00056     if binding_name:
00057         if binding_name not in binding_order:
00058             raise ImportError("Qt binding '%s' is unknown" % binding_name)
00059         binding_order = [binding_name]
00060 
00061     required_modules = [
00062         'QtCore',
00063         'QtGui'
00064     ]
00065     optional_modules = [
00066         'QtDeclarative',
00067         'QtMultimedia',
00068         'QtNetwork',
00069         'QtOpenGL',
00070         'QtOpenVG',
00071         'QtScript',
00072         'QtScriptTools'
00073         'QtSql',
00074         'QtSvg',
00075         'QtWebKit',
00076         'QtXml',
00077         'QtXmlPatterns',
00078     ]
00079 
00080     # try to load preferred bindings
00081     error_msgs = []
00082     for binding_name in binding_order:
00083         try:
00084             binding_loader = getattr(sys.modules[__name__], '_load_%s' % binding_name, None)
00085             if binding_loader:
00086                 QT_BINDING_VERSION = binding_loader(required_modules, optional_modules)
00087                 QT_BINDING = binding_name
00088                 break
00089             else:
00090                 error_msgs.append("  Binding loader '_load_%s' not found." % binding_name)
00091         except ImportError as e:
00092             error_msgs.append("  ImportError for '%s': %s" % (binding_name, e))
00093 
00094     if not QT_BINDING:
00095         raise ImportError("Could not find Qt binding (looked for: %s):\n%s" % (', '.join(["'%s'" % b for b in binding_order]), '\n'.join(error_msgs)))
00096 
00097 
00098 def _register_binding_module(module_name, module):
00099     # register module using only its own name (TODO: legacy compatibility, remove when possible)
00100     sys.modules[module_name] = module
00101     # add module to the binding modules
00102     QT_BINDING_MODULES[module_name] = module
00103 
00104 
00105 def _named_import(name):
00106     parts = name.split('.')
00107     assert(len(parts) >= 2)
00108     module = builtins.__import__(name)
00109     for m in parts[1:]:
00110         module = module.__dict__[m]
00111     module_name = parts[-1]
00112     _register_binding_module(module_name, module)
00113 
00114 
00115 def _named_optional_import(name):
00116     try:
00117         _named_import(name)
00118     except ImportError:
00119         pass
00120 
00121 
00122 def _load_pyqt(required_modules, optional_modules):
00123     # set environment variable QT_API for matplotlib
00124     os.environ['QT_API'] = 'pyqt'
00125 
00126     # select PyQt4 API, see http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html
00127     import sip
00128     try:
00129         sip.setapi('QDate', 2)
00130         sip.setapi('QDateTime', 2)
00131         sip.setapi('QString', 2)
00132         sip.setapi('QTextStream', 2)
00133         sip.setapi('QTime', 2)
00134         sip.setapi('QUrl', 2)
00135         sip.setapi('QVariant', 2)
00136     except ValueError as e:
00137         raise RuntimeError('Could not set API version (%s): did you import PyQt4 directly?' % e)
00138 
00139     # register required and optional PyQt4 modules
00140     for module_name in required_modules:
00141         _named_import('PyQt4.%s' % module_name)
00142     for module_name in optional_modules:
00143         _named_optional_import('PyQt4.%s' % module_name)
00144 
00145     # set some names for compatibility with PySide
00146     sys.modules['QtCore'].Signal = sys.modules['QtCore'].pyqtSignal
00147     sys.modules['QtCore'].Slot = sys.modules['QtCore'].pyqtSlot
00148     sys.modules['QtCore'].Property = sys.modules['QtCore'].pyqtProperty
00149 
00150     # try to register PyQt4.Qwt5 module
00151     try:
00152         import PyQt4.Qwt5
00153         _register_binding_module('Qwt', PyQt4.Qwt5)
00154     except ImportError:
00155         pass
00156 
00157     global _loadUi
00158 
00159     def _loadUi(uifile, baseinstance=None, custom_widgets_=None):
00160         from PyQt4 import uic
00161         return uic.loadUi(uifile, baseinstance=baseinstance)
00162 
00163     # override specific function to improve compatibility between different bindings
00164     from QtGui import QFileDialog
00165     QFileDialog.getOpenFileName = QFileDialog.getOpenFileNameAndFilter
00166     QFileDialog.getSaveFileName = QFileDialog.getSaveFileNameAndFilter
00167 
00168     import PyQt4.QtCore
00169     return PyQt4.QtCore.PYQT_VERSION_STR
00170 
00171 
00172 def _load_pyside(required_modules, optional_modules):
00173     # set environment variable QT_API for matplotlib
00174     os.environ['QT_API'] = 'pyside'
00175 
00176     # register required and optional PySide modules
00177     for module_name in required_modules:
00178         _named_import('PySide.%s' % module_name)
00179     for module_name in optional_modules:
00180         _named_optional_import('PySide.%s' % module_name)
00181 
00182     # set some names for compatibility with PyQt4
00183     sys.modules['QtCore'].pyqtSignal = sys.modules['QtCore'].Signal
00184     sys.modules['QtCore'].pyqtSlot = sys.modules['QtCore'].Slot
00185     sys.modules['QtCore'].pyqtProperty = sys.modules['QtCore'].Property
00186 
00187     # try to register PySideQwt module
00188     try:
00189         import PySideQwt
00190         _register_binding_module('Qwt', PySideQwt)
00191     except ImportError:
00192         pass
00193 
00194     global _loadUi
00195 
00196     def _loadUi(uifile, baseinstance=None, custom_widgets=None):
00197         from PySide.QtUiTools import QUiLoader
00198         from PySide.QtCore import QMetaObject
00199 
00200         class CustomUiLoader(QUiLoader):
00201             class_aliases = {
00202                 'Line': 'QFrame',
00203             }
00204 
00205             def __init__(self, baseinstance=None, custom_widgets=None):
00206                 super(CustomUiLoader, self).__init__(baseinstance)
00207                 self._base_instance = baseinstance
00208                 self._custom_widgets = custom_widgets or {}
00209 
00210             def createWidget(self, class_name, parent=None, name=''):
00211                 # don't create the top-level widget, if a base instance is set
00212                 if self._base_instance and not parent:
00213                     return self._base_instance
00214 
00215                 if class_name in self._custom_widgets:
00216                     widget = self._custom_widgets[class_name](parent)
00217                 else:
00218                     widget = QUiLoader.createWidget(self, class_name, parent, name)
00219 
00220                 if str(type(widget)).find(self.class_aliases.get(class_name, class_name)) < 0:
00221                     sys.modules['QtCore'].qDebug(str('PySide.loadUi(): could not find widget class "%s", defaulting to "%s"' % (class_name, type(widget))))
00222 
00223                 if self._base_instance:
00224                     setattr(self._base_instance, name, widget)
00225 
00226                 return widget
00227 
00228         loader = CustomUiLoader(baseinstance, custom_widgets)
00229 
00230         # instead of passing the custom widgets, they should be registered using QUiLoader.registerCustomWidget(),
00231         # but this does not work in PySide 1.0.6: it simply segfaults...
00232         #loader = CustomUiLoader(baseinstance)
00233         #custom_widgets = custom_widgets or {}
00234         #for custom_widget in custom_widgets.values():
00235         #    loader.registerCustomWidget(custom_widget)
00236 
00237         ui = loader.load(uifile)
00238         QMetaObject.connectSlotsByName(ui)
00239         return ui
00240 
00241     import PySide
00242     return PySide.__version__
00243 
00244 
00245 def loadUi(uifile, baseinstance=None, custom_widgets=None):
00246     """
00247     @type uifile: str
00248     @param uifile: Absolute path of .ui file
00249     @type baseinstance: QWidget
00250     @param baseinstance: the optional instance of the Qt base class.
00251                          If specified then the user interface is created in
00252                          it. Otherwise a new instance of the base class is
00253                          automatically created.
00254     @type custom_widgets: dict of {str:QWidget}
00255     @param custom_widgets: Class name and type of the custom classes used
00256                            in uifile if any. This can be None if no custom
00257                            class is in use. (Note: this is only necessary
00258                            for PySide, see
00259                            http://answers.ros.org/question/56382/what-does-python_qt_bindingloaduis-3rd-arg-do-in-pyqt-binding/
00260                            for more information)
00261     """
00262     return _loadUi(uifile, baseinstance, custom_widgets)
00263 
00264 
00265 _select_qt_binding(
00266     getattr(sys, 'SELECT_QT_BINDING', None),
00267     getattr(sys, 'SELECT_QT_BINDING_ORDER', None),
00268 )


python_qt_binding
Author(s): Dave Hershberger, Dorian Scholz, Dirk Thomas
autogenerated on Thu Aug 27 2015 14:35:26