# Copyright (c) 2014, Riverbank Computing Limited # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. 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. # # 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. from PyQt5.QtCore import pyqtSlot from PyQt5.QtWidgets import (QButtonGroup, QCheckBox, QGridLayout, QGroupBox, QStackedWidget, QVBoxLayout, QWidget) class PyQtPage(QStackedWidget): """ The GUI for the PyQt configuration page of a project. """ # The page's label. label = "PyQt Modules" class _PyQtModules: """ Encapsulate the PyQt modules for a particular version. """ def __init__(self, modules=(), opengl_modules=(), addon_modules=()): """ Initialise the object. """ self.modules = modules self.opengl_modules = opengl_modules self.addon_modules = addon_modules # The PyQt5 modules. _pyqt5_modules = _PyQtModules( modules=( 'QAxContainer', 'Qt', 'QtBluetooth', 'QtCore', 'QtDBus', 'QtDesigner', 'QtGui', 'QtHelp', 'QtMacExtras', 'QtMultimedia', 'QtMultimediaWidgets', 'QtNetwork', 'QtOpenGL', 'QtPositioning', 'QtPrintSupport', 'QtQml', 'QtQuick', 'QtSensors', 'QtSerialPort', 'QtSql', 'QtSvg', 'QtTest', 'QtWebKit', 'QtWebKitWidgets', 'QtWidgets', 'QtWinExtras', 'QtX11Extras', 'QtXmlPatterns', 'uic'), opengl_modules=('_QOpenGLFunctions_ES2', '_QOpenGLFunctions_2_0'), addon_modules=('Qsci', 'QtChart', 'QtDataVisualization')) # The PyQt4 modules. _pyqt4_modules = _PyQtModules( modules=( 'QAxContainer', 'Qt', 'QtCore', 'QtDBus', 'QtDeclarative', 'QtDesigner', 'QtGui', 'QtHelp', 'QtMultimedia', 'QtNetwork', 'QtOpenGL', 'QtScript', 'QtScriptTools', 'QtSql', 'QtSvg', 'QtTest', 'QtWebKit', 'QtXml', 'QtXmlPatterns', 'phonon', 'uic'), addon_modules=('Qsci', 'QtChart')) @property def project(self): """ The project property getter. """ return self._project @project.setter def project(self, value): """ The project property setter. """ if self._project != value: self._project = value self._update_page() def __init__(self): """ Initialise the page. """ super().__init__() self._project = None # Create the stacked pages for each PyQt version. self._pyqt5_page = _PyQtVersionPage(self._pyqt5_modules) self.addWidget(self._pyqt5_page) self._pyqt4_page = _PyQtVersionPage(self._pyqt4_modules) self.addWidget(self._pyqt4_page) @pyqtSlot(bool) def set_pyqt_version(self, is_pyqt5): """ Configure the page according to the PyQt version. """ page = self._pyqt5_page if is_pyqt5 else self._pyqt4_page page.update_project() self.setCurrentWidget(page) def _update_page(self): """ Update the page using the current project. """ project = self._project self._pyqt5_page.project = project self._pyqt4_page.project = project if project.application_is_pyqt5: self._pyqt5_page.configure() self._pyqt4_page.clear() self.setCurrentWidget(self._pyqt5_page) else: self._pyqt5_page.clear() self._pyqt4_page.configure() self.setCurrentWidget(self._pyqt4_page) class _PyQtVersionPage(QWidget): """ The GUI for a PyQt version specific configuration page. """ def __init__(self, modules): """ Initialise the page. """ super().__init__() self._modules = modules self.project = None # Create the page's GUI. layout = QVBoxLayout() self._modules_bg = self._create_button_group(layout, "Imported Modules", self._modules.modules) self._opengl_modules_bg = self._create_button_group(layout, "Internal OpenGL Modules", self._modules.opengl_modules) self._addon_modules_bg = self._create_button_group(layout, "Add-on Modules", self._modules.addon_modules) layout.addStretch() self.setLayout(layout) def update_project(self): """ Update the project to contain the currently selected modules. """ modules = self.project.pyqt_modules del modules[:] for b in self._get_buttons(): if b.isChecked(): modules.append(b.text()) def configure(self): """ Update the page according to modules specified in the project. """ modules = self.project.pyqt_modules self._block_signals(True) for b in self._get_buttons(): b.setChecked(b.text() in modules) self._block_signals(False) def clear(self): """ Deselect all modules. """ self._block_signals(True) for b in self._get_buttons(): b.setChecked(False) self._block_signals(False) def _create_button_group(self, layout, title, modules): """ Add a check box for each module to a layout and return a connected button group. """ if len(modules) == 0: return None b_group = QButtonGroup(exclusive=False) imports = QGroupBox(title) grid = QGridLayout() row = column = 0 for m in modules: b = QCheckBox(m) b_group.addButton(b) grid.addWidget(b, row, column) column += 1 if column == 5: row += 1 column = 0 imports.setLayout(grid) layout.addWidget(imports) b_group.buttonToggled.connect(self._module_toggled) return b_group def _get_buttons(self): """ A generator that returns all of the buttons in the page. """ if self._modules_bg is not None: for b in self._modules_bg.buttons(): yield b if self._opengl_modules_bg is not None: for b in self._opengl_modules_bg.buttons(): yield b if self._addon_modules_bg is not None: for b in self._addon_modules_bg.buttons(): yield b def _block_signals(self, block): """ Block (or unblock) all button group signals. """ if self._modules_bg is not None: self._modules_bg.blockSignals(block) if self._opengl_modules_bg is not None: self._opengl_modules_bg.blockSignals(block) if self._addon_modules_bg is not None: self._addon_modules_bg.blockSignals(block) def _module_toggled(self, button, checked): """ Invoked when a module button is toggled. """ if checked: self.project.pyqt_modules.append(button.text()) else: self.project.pyqt_modules.remove(button.text()) self.project.modified = True