|
|
- import os
-
- from . import PYSIDE, PYSIDE2, PYQT4, PYQT5
- from .QtWidgets import QComboBox
-
-
- if PYQT5:
-
- from PyQt5.uic import *
-
- elif PYQT4:
-
- from PyQt4.uic import *
-
- else:
-
- __all__ = ['loadUi']
-
- # 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@gmail.com>
- # Modifications by Charl Botha <cpbotha@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.
-
- if PYSIDE:
- from PySide.QtCore import QMetaObject
- from PySide.QtUiTools import QUiLoader
- elif PYSIDE2:
- from PySide2.QtCore import QMetaObject
- from PySide2.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
|