aboutsummaryrefslogtreecommitdiffstats
path: root/examples/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'examples/corelib/tools')
-rwxr-xr-xexamples/corelib/tools/codecs/codecs.py251
-rwxr-xr-xexamples/corelib/tools/regexp.py195
-rwxr-xr-xexamples/corelib/tools/settingseditor/settingseditor.py722
3 files changed, 1168 insertions, 0 deletions
diff --git a/examples/corelib/tools/codecs/codecs.py b/examples/corelib/tools/codecs/codecs.py
new file mode 100755
index 000000000..15f7d9563
--- /dev/null
+++ b/examples/corelib/tools/codecs/codecs.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+
+#############################################################################
+##
+## Copyright (C) 2013 Riverbank Computing Limited.
+## Copyright (C) 2016 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the PySide examples of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:BSD$
+## You may use this file under the terms of the BSD license as follows:
+##
+## "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 Qt Company Ltd 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
+## OWNER 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."
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+"""PySide2 port of the widgets/tools/codecs example from Qt v5.x"""
+
+from PySide2 import QtCore, QtGui, QtWidgets
+
+
+def codec_name(codec):
+ try:
+ # Python v3.
+ name = str(codec.name(), encoding='ascii')
+ except TypeError:
+ # Python v2.
+ name = str(codec.name())
+
+ return name
+
+
+class MainWindow(QtWidgets.QMainWindow):
+ def __init__(self):
+ super(MainWindow, self).__init__()
+
+ self.textEdit = QtWidgets.QTextEdit()
+ self.textEdit.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)
+ self.setCentralWidget(self.textEdit)
+
+ self.codecs = []
+ self.findCodecs()
+
+ self.previewForm = PreviewForm(self)
+ self.previewForm.setCodecList(self.codecs)
+
+ self.saveAsActs = []
+ self.createActions()
+ self.createMenus()
+
+ self.setWindowTitle("Codecs")
+ self.resize(500, 400)
+
+ def open(self):
+ fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self)
+ if fileName:
+ inFile = QtCore.QFile(fileName)
+ if not inFile.open(QtCore.QFile.ReadOnly):
+ QtWidgets.QMessageBox.warning(self, "Codecs",
+ "Cannot read file %s:\n%s" % (fileName, inFile.errorString()))
+ return
+
+ data = inFile.readAll()
+
+ self.previewForm.setEncodedData(data)
+ if self.previewForm.exec_():
+ self.textEdit.setPlainText(self.previewForm.decodedString())
+
+ def save(self):
+ fileName = QtWidgets.QFileDialog.getSaveFileName(self)
+ if fileName:
+ outFile = QtCore.QFile(fileName)
+ if not outFile.open(QtCore.QFile.WriteOnly|QtCore.QFile.Text):
+ QtWidgets.QMessageBox.warning(self, "Codecs",
+ "Cannot write file %s:\n%s" % (fileName, outFile.errorString()))
+ return
+
+ action = self.sender()
+ codecName = action.data()
+
+ out = QtCore.QTextStream(outFile)
+ out.setCodec(codecName)
+ out << self.textEdit.toPlainText()
+
+ def about(self):
+ QtWidgets.QMessageBox.about(self, "About Codecs",
+ "The <b>Codecs</b> example demonstrates how to read and "
+ "write files using various encodings.")
+
+ def aboutToShowSaveAsMenu(self):
+ currentText = self.textEdit.toPlainText()
+
+ for action in self.saveAsActs:
+ codecName = str(action.data())
+ codec = QtCore.QTextCodec.codecForName(codecName)
+ action.setVisible(codec and codec.canEncode(currentText))
+
+ def findCodecs(self):
+ codecMap = []
+ iso8859RegExp = QtCore.QRegExp('ISO[- ]8859-([0-9]+).*')
+
+ for mib in QtCore.QTextCodec.availableMibs():
+ codec = QtCore.QTextCodec.codecForMib(mib)
+ sortKey = codec_name(codec).upper()
+ rank = 0
+
+ if sortKey.startswith('UTF-8'):
+ rank = 1
+ elif sortKey.startswith('UTF-16'):
+ rank = 2
+ elif iso8859RegExp.exactMatch(sortKey):
+ if len(iso8859RegExp.cap(1)) == 1:
+ rank = 3
+ else:
+ rank = 4
+ else:
+ rank = 5
+
+ codecMap.append((str(rank) + sortKey, codec))
+
+ codecMap.sort()
+ self.codecs = [item[-1] for item in codecMap]
+
+ def createActions(self):
+ self.openAct = QtWidgets.QAction("&Open...", self, shortcut="Ctrl+O",
+ triggered=self.open)
+
+ for codec in self.codecs:
+ name = codec_name(codec)
+
+ action = QtWidgets.QAction(name + '...', self, triggered=self.save)
+ action.setData(name)
+ self.saveAsActs.append(action)
+
+ self.exitAct = QtWidgets.QAction("E&xit", self, shortcut="Ctrl+Q",
+ triggered=self.close)
+
+ self.aboutAct = QtWidgets.QAction("&About", self, triggered=self.about)
+
+ self.aboutQtAct = QtWidgets.QAction("About &Qt", self,
+ triggered=QtWidgets.qApp.aboutQt)
+
+ def createMenus(self):
+ self.saveAsMenu = QtWidgets.QMenu("&Save As", self)
+ for action in self.saveAsActs:
+ self.saveAsMenu.addAction(action)
+
+ self.saveAsMenu.aboutToShow.connect(self.aboutToShowSaveAsMenu)
+
+ self.fileMenu = QtWidgets.QMenu("&File", self)
+ self.fileMenu.addAction(self.openAct)
+ self.fileMenu.addMenu(self.saveAsMenu)
+ self.fileMenu.addSeparator()
+ self.fileMenu.addAction(self.exitAct)
+
+ self.helpMenu = QtWidgets.QMenu("&Help", self)
+ self.helpMenu.addAction(self.aboutAct)
+ self.helpMenu.addAction(self.aboutQtAct)
+
+ self.menuBar().addMenu(self.fileMenu)
+ self.menuBar().addSeparator()
+ self.menuBar().addMenu(self.helpMenu)
+
+
+class PreviewForm(QtWidgets.QDialog):
+ def __init__(self, parent):
+ super(PreviewForm, self).__init__(parent)
+
+ self.encodingComboBox = QtWidgets.QComboBox()
+ encodingLabel = QtWidgets.QLabel("&Encoding:")
+ encodingLabel.setBuddy(self.encodingComboBox)
+
+ self.textEdit = QtWidgets.QTextEdit()
+ self.textEdit.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)
+ self.textEdit.setReadOnly(True)
+
+ buttonBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
+
+ self.encodingComboBox.activated.connect(self.updateTextEdit)
+ buttonBox.accepted.connect(self.accept)
+ buttonBox.rejected.connect(self.reject)
+
+ mainLayout = QtWidgets.QGridLayout()
+ mainLayout.addWidget(encodingLabel, 0, 0)
+ mainLayout.addWidget(self.encodingComboBox, 0, 1)
+ mainLayout.addWidget(self.textEdit, 1, 0, 1, 2)
+ mainLayout.addWidget(buttonBox, 2, 0, 1, 2)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle("Choose Encoding")
+ self.resize(400, 300)
+
+ def setCodecList(self, codecs):
+ self.encodingComboBox.clear()
+ for codec in codecs:
+ self.encodingComboBox.addItem(codec_name(codec), codec.mibEnum())
+
+ def setEncodedData(self, data):
+ self.encodedData = data
+ self.updateTextEdit()
+
+ def decodedString(self):
+ return self.decodedStr
+
+ def updateTextEdit(self):
+ mib = self.encodingComboBox.itemData(self.encodingComboBox.currentIndex())
+ codec = QtCore.QTextCodec.codecForMib(mib)
+
+ data = QtCore.QTextStream(self.encodedData)
+ data.setAutoDetectUnicode(False)
+ data.setCodec(codec)
+
+ self.decodedStr = data.readAll()
+ self.textEdit.setPlainText(self.decodedStr)
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtWidgets.QApplication(sys.argv)
+ mainWin = MainWindow()
+ mainWin.show()
+ sys.exit(app.exec_())
diff --git a/examples/corelib/tools/regexp.py b/examples/corelib/tools/regexp.py
new file mode 100755
index 000000000..7e28a5365
--- /dev/null
+++ b/examples/corelib/tools/regexp.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python
+
+#############################################################################
+##
+## Copyright (C) 2013 Riverbank Computing Limited.
+## Copyright (C) 2016 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the PySide examples of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:BSD$
+## You may use this file under the terms of the BSD license as follows:
+##
+## "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 Qt Company Ltd 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
+## OWNER 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."
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+"""PySide2 port of the widgets/tools/regexp example from Qt v5.x"""
+
+from PySide2 import QtCore, QtGui, QtWidgets
+
+
+class RegExpDialog(QtWidgets.QDialog):
+ MaxCaptures = 6
+
+ def __init__(self, parent=None):
+ super(RegExpDialog, self).__init__(parent)
+
+ self.patternComboBox = QtWidgets.QComboBox()
+ self.patternComboBox.setEditable(True)
+ self.patternComboBox.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
+ QtWidgets.QSizePolicy.Preferred)
+
+ patternLabel = QtWidgets.QLabel("&Pattern:")
+ patternLabel.setBuddy(self.patternComboBox)
+
+ self.escapedPatternLineEdit = QtWidgets.QLineEdit()
+ self.escapedPatternLineEdit.setReadOnly(True)
+ palette = self.escapedPatternLineEdit.palette()
+ palette.setBrush(QtGui.QPalette.Base,
+ palette.brush(QtGui.QPalette.Disabled, QtGui.QPalette.Base))
+ self.escapedPatternLineEdit.setPalette(palette)
+
+ escapedPatternLabel = QtWidgets.QLabel("&Escaped Pattern:")
+ escapedPatternLabel.setBuddy(self.escapedPatternLineEdit)
+
+ self.syntaxComboBox = QtWidgets.QComboBox()
+ self.syntaxComboBox.addItem("Regular expression v1",
+ QtCore.QRegExp.RegExp)
+ self.syntaxComboBox.addItem("Regular expression v2",
+ QtCore.QRegExp.RegExp2)
+ self.syntaxComboBox.addItem("Wildcard", QtCore.QRegExp.Wildcard)
+ self.syntaxComboBox.addItem("Fixed string",
+ QtCore.QRegExp.FixedString)
+
+ syntaxLabel = QtWidgets.QLabel("&Pattern Syntax:")
+ syntaxLabel.setBuddy(self.syntaxComboBox)
+
+ self.textComboBox = QtWidgets.QComboBox()
+ self.textComboBox.setEditable(True)
+ self.textComboBox.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
+ QtWidgets.QSizePolicy.Preferred)
+
+ textLabel = QtWidgets.QLabel("&Text:")
+ textLabel.setBuddy(self.textComboBox)
+
+ self.caseSensitiveCheckBox = QtWidgets.QCheckBox("Case &Sensitive")
+ self.caseSensitiveCheckBox.setChecked(True)
+ self.minimalCheckBox = QtWidgets.QCheckBox("&Minimal")
+
+ indexLabel = QtWidgets.QLabel("Index of Match:")
+ self.indexEdit = QtWidgets.QLineEdit()
+ self.indexEdit.setReadOnly(True)
+
+ matchedLengthLabel = QtWidgets.QLabel("Matched Length:")
+ self.matchedLengthEdit = QtWidgets.QLineEdit()
+ self.matchedLengthEdit.setReadOnly(True)
+
+ self.captureLabels = []
+ self.captureEdits = []
+ for i in range(self.MaxCaptures):
+ self.captureLabels.append(QtWidgets.QLabel("Capture %d:" % i))
+ self.captureEdits.append(QtWidgets.QLineEdit())
+ self.captureEdits[i].setReadOnly(True)
+ self.captureLabels[0].setText("Match:")
+
+ checkBoxLayout = QtWidgets.QHBoxLayout()
+ checkBoxLayout.addWidget(self.caseSensitiveCheckBox)
+ checkBoxLayout.addWidget(self.minimalCheckBox)
+ checkBoxLayout.addStretch(1)
+
+ mainLayout = QtWidgets.QGridLayout()
+ mainLayout.addWidget(patternLabel, 0, 0)
+ mainLayout.addWidget(self.patternComboBox, 0, 1)
+ mainLayout.addWidget(escapedPatternLabel, 1, 0)
+ mainLayout.addWidget(self.escapedPatternLineEdit, 1, 1)
+ mainLayout.addWidget(syntaxLabel, 2, 0)
+ mainLayout.addWidget(self.syntaxComboBox, 2, 1)
+ mainLayout.addLayout(checkBoxLayout, 3, 0, 1, 2)
+ mainLayout.addWidget(textLabel, 4, 0)
+ mainLayout.addWidget(self.textComboBox, 4, 1)
+ mainLayout.addWidget(indexLabel, 5, 0)
+ mainLayout.addWidget(self.indexEdit, 5, 1)
+ mainLayout.addWidget(matchedLengthLabel, 6, 0)
+ mainLayout.addWidget(self.matchedLengthEdit, 6, 1)
+
+ for i in range(self.MaxCaptures):
+ mainLayout.addWidget(self.captureLabels[i], 7 + i, 0)
+ mainLayout.addWidget(self.captureEdits[i], 7 + i, 1)
+ self.setLayout(mainLayout)
+
+ self.patternComboBox.editTextChanged.connect(self.refresh)
+ self.textComboBox.editTextChanged.connect(self.refresh)
+ self.caseSensitiveCheckBox.toggled.connect(self.refresh)
+ self.minimalCheckBox.toggled.connect(self.refresh)
+ self.syntaxComboBox.currentIndexChanged.connect(self.refresh)
+
+ self.patternComboBox.addItem("[A-Za-z_]+([A-Za-z_0-9]*)")
+ self.textComboBox.addItem("(10 + delta4)* 32")
+
+ self.setWindowTitle("RegExp")
+ self.setFixedHeight(self.sizeHint().height())
+ self.refresh()
+
+ def refresh(self):
+ self.setUpdatesEnabled(False)
+
+ pattern = self.patternComboBox.currentText()
+ text = self.textComboBox.currentText()
+
+ escaped = str(pattern)
+ escaped.replace('\\', '\\\\')
+ escaped.replace('"', '\\"')
+ self.escapedPatternLineEdit.setText('"' + escaped + '"')
+
+ rx = QtCore.QRegExp(pattern)
+ cs = QtCore.Qt.CaseInsensitive
+ if self.caseSensitiveCheckBox.isChecked():
+ cs = QtCore.Qt.CaseSensitive
+ rx.setCaseSensitivity(cs)
+ rx.setMinimal(self.minimalCheckBox.isChecked())
+ syntax = self.syntaxComboBox.itemData(self.syntaxComboBox.currentIndex())
+ rx.setPatternSyntax(QtCore.QRegExp.PatternSyntax(syntax))
+
+ palette = self.patternComboBox.palette()
+ if rx.isValid():
+ palette.setColor(QtGui.QPalette.Text,
+ self.textComboBox.palette().color(QtGui.QPalette.Text))
+ else:
+ palette.setColor(QtGui.QPalette.Text, QtCore.Qt.red)
+ self.patternComboBox.setPalette(palette)
+
+ self.indexEdit.setText(str(rx.indexIn(text)))
+ self.matchedLengthEdit.setText(str(rx.matchedLength()))
+
+ for i in range(self.MaxCaptures):
+ self.captureLabels[i].setEnabled(i <= rx.captureCount())
+ self.captureEdits[i].setEnabled(i <= rx.captureCount())
+ self.captureEdits[i].setText(rx.cap(i))
+
+ self.setUpdatesEnabled(True)
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtWidgets.QApplication(sys.argv)
+ dialog = RegExpDialog()
+ sys.exit(dialog.exec_())
diff --git a/examples/corelib/tools/settingseditor/settingseditor.py b/examples/corelib/tools/settingseditor/settingseditor.py
new file mode 100755
index 000000000..905049746
--- /dev/null
+++ b/examples/corelib/tools/settingseditor/settingseditor.py
@@ -0,0 +1,722 @@
+#!/usr/bin/env python
+
+#############################################################################
+##
+## Copyright (C) 2013 Riverbank Computing Limited.
+## Copyright (C) 2016 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the PySide examples of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:BSD$
+## You may use this file under the terms of the BSD license as follows:
+##
+## "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 Qt Company Ltd 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
+## OWNER 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."
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+"""PySide2 port of the widgets/tools/settingseditor example from Qt v5.x"""
+
+import sys
+
+from PySide2 import QtCore, QtGui, QtWidgets
+
+
+class MainWindow(QtWidgets.QMainWindow):
+ def __init__(self, parent=None):
+ super(MainWindow, self).__init__(parent)
+
+ self.settingsTree = SettingsTree()
+ self.setCentralWidget(self.settingsTree)
+
+ self.locationDialog = None
+
+ self.createActions()
+ self.createMenus()
+
+ self.autoRefreshAct.setChecked(True)
+ self.fallbacksAct.setChecked(True)
+
+ self.setWindowTitle("Settings Editor")
+ self.resize(500, 600)
+
+ def openSettings(self):
+ if self.locationDialog is None:
+ self.locationDialog = LocationDialog(self)
+
+ if self.locationDialog.exec_():
+ settings = QtCore.QSettings(self.locationDialog.format(),
+ self.locationDialog.scope(),
+ self.locationDialog.organization(),
+ self.locationDialog.application())
+ self.setSettingsObject(settings)
+ self.fallbacksAct.setEnabled(True)
+
+ def openIniFile(self):
+ fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open INI File",
+ '', "INI Files (*.ini *.conf)")
+
+ if fileName:
+ settings = QtCore.QSettings(fileName, QtCore.QSettings.IniFormat)
+ self.setSettingsObject(settings)
+ self.fallbacksAct.setEnabled(False)
+
+ def openPropertyList(self):
+ fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self,
+ "Open Property List", '', "Property List Files (*.plist)")
+
+ if fileName:
+ settings = QtCore.QSettings(fileName, QtCore.QSettings.NativeFormat)
+ self.setSettingsObject(settings)
+ self.fallbacksAct.setEnabled(False)
+
+ def openRegistryPath(self):
+ path, ok = QtWidgets.QInputDialog.getText(self, "Open Registry Path",
+ "Enter the path in the Windows registry:",
+ QtWidgets.QLineEdit.Normal, 'HKEY_CURRENT_USER\\')
+
+ if ok and path != '':
+ settings = QtCore.QSettings(path, QtCore.QSettings.NativeFormat)
+ self.setSettingsObject(settings)
+ self.fallbacksAct.setEnabled(False)
+
+ def about(self):
+ QtWidgets.QMessageBox.about(self, "About Settings Editor",
+ "The <b>Settings Editor</b> example shows how to access "
+ "application settings using Qt.")
+
+ def createActions(self):
+ self.openSettingsAct = QtWidgets.QAction("&Open Application Settings...",
+ self, shortcut="Ctrl+O", triggered=self.openSettings)
+
+ self.openIniFileAct = QtWidgets.QAction("Open I&NI File...", self,
+ shortcut="Ctrl+N", triggered=self.openIniFile)
+
+ self.openPropertyListAct = QtWidgets.QAction("Open macOS &Property List...",
+ self, shortcut="Ctrl+P", triggered=self.openPropertyList)
+ if sys.platform != 'darwin':
+ self.openPropertyListAct.setEnabled(False)
+
+ self.openRegistryPathAct = QtWidgets.QAction(
+ "Open Windows &Registry Path...", self, shortcut="Ctrl+G",
+ triggered=self.openRegistryPath)
+ if sys.platform != 'win32':
+ self.openRegistryPathAct.setEnabled(False)
+
+ self.refreshAct = QtWidgets.QAction("&Refresh", self, shortcut="Ctrl+R",
+ enabled=False, triggered=self.settingsTree.refresh)
+
+ self.exitAct = QtWidgets.QAction("E&xit", self, shortcut="Ctrl+Q",
+ triggered=self.close)
+
+ self.autoRefreshAct = QtWidgets.QAction("&Auto-Refresh", self,
+ shortcut="Ctrl+A", checkable=True, enabled=False)
+ self.autoRefreshAct.triggered[bool].connect(self.settingsTree.setAutoRefresh)
+ self.autoRefreshAct.triggered[bool].connect(self.refreshAct.setDisabled)
+
+ self.fallbacksAct = QtWidgets.QAction("&Fallbacks", self,
+ shortcut="Ctrl+F", checkable=True, enabled=False)
+ self.fallbacksAct.triggered[bool].connect(self.settingsTree.setFallbacksEnabled)
+
+ self.aboutAct = QtWidgets.QAction("&About", self, triggered=self.about)
+
+ self.aboutQtAct = QtWidgets.QAction("About &Qt", self,
+ triggered=QtWidgets.qApp.aboutQt)
+
+ def createMenus(self):
+ self.fileMenu = self.menuBar().addMenu("&File")
+ self.fileMenu.addAction(self.openSettingsAct)
+ self.fileMenu.addAction(self.openIniFileAct)
+ self.fileMenu.addAction(self.openPropertyListAct)
+ self.fileMenu.addAction(self.openRegistryPathAct)
+ self.fileMenu.addSeparator()
+ self.fileMenu.addAction(self.refreshAct)
+ self.fileMenu.addSeparator()
+ self.fileMenu.addAction(self.exitAct)
+
+ self.optionsMenu = self.menuBar().addMenu("&Options")
+ self.optionsMenu.addAction(self.autoRefreshAct)
+ self.optionsMenu.addAction(self.fallbacksAct)
+
+ self.menuBar().addSeparator()
+
+ self.helpMenu = self.menuBar().addMenu("&Help")
+ self.helpMenu.addAction(self.aboutAct)
+ self.helpMenu.addAction(self.aboutQtAct)
+
+ def setSettingsObject(self, settings):
+ settings.setFallbacksEnabled(self.fallbacksAct.isChecked())
+ self.settingsTree.setSettingsObject(settings)
+
+ self.refreshAct.setEnabled(True)
+ self.autoRefreshAct.setEnabled(True)
+
+ niceName = settings.fileName()
+ niceName.replace('\\', '/')
+ niceName = niceName.split('/')[-1]
+
+ if not settings.isWritable():
+ niceName += " (read only)"
+
+ self.setWindowTitle("%s - Settings Editor" % niceName)
+
+
+class LocationDialog(QtWidgets.QDialog):
+ def __init__(self, parent=None):
+ super(LocationDialog, self).__init__(parent)
+
+ self.formatComboBox = QtWidgets.QComboBox()
+ self.formatComboBox.addItem("Native")
+ self.formatComboBox.addItem("INI")
+
+ self.scopeComboBox = QtWidgets.QComboBox()
+ self.scopeComboBox.addItem("User")
+ self.scopeComboBox.addItem("System")
+
+ self.organizationComboBox = QtWidgets.QComboBox()
+ self.organizationComboBox.addItem("Trolltech")
+ self.organizationComboBox.setEditable(True)
+
+ self.applicationComboBox = QtWidgets.QComboBox()
+ self.applicationComboBox.addItem("Any")
+ self.applicationComboBox.addItem("Application Example")
+ self.applicationComboBox.addItem("Assistant")
+ self.applicationComboBox.addItem("Designer")
+ self.applicationComboBox.addItem("Linguist")
+ self.applicationComboBox.setEditable(True)
+ self.applicationComboBox.setCurrentIndex(3)
+
+ formatLabel = QtWidgets.QLabel("&Format:")
+ formatLabel.setBuddy(self.formatComboBox)
+
+ scopeLabel = QtWidgets.QLabel("&Scope:")
+ scopeLabel.setBuddy(self.scopeComboBox)
+
+ organizationLabel = QtWidgets.QLabel("&Organization:")
+ organizationLabel.setBuddy(self.organizationComboBox)
+
+ applicationLabel = QtWidgets.QLabel("&Application:")
+ applicationLabel.setBuddy(self.applicationComboBox)
+
+ self.locationsGroupBox = QtWidgets.QGroupBox("Setting Locations")
+
+ self.locationsTable = QtWidgets.QTableWidget()
+ self.locationsTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
+ self.locationsTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
+ self.locationsTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
+ self.locationsTable.setColumnCount(2)
+ self.locationsTable.setHorizontalHeaderLabels(("Location", "Access"))
+ self.locationsTable.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
+ self.locationsTable.horizontalHeader().resizeSection(1, 180)
+
+ self.buttonBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
+
+ self.formatComboBox.activated.connect(self.updateLocationsTable)
+ self.scopeComboBox.activated.connect(self.updateLocationsTable)
+ self.organizationComboBox.lineEdit().editingFinished.connect(self.updateLocationsTable)
+ self.applicationComboBox.lineEdit().editingFinished.connect(self.updateLocationsTable)
+ self.buttonBox.accepted.connect(self.accept)
+ self.buttonBox.rejected.connect(self.reject)
+
+ locationsLayout = QtWidgets.QVBoxLayout()
+ locationsLayout.addWidget(self.locationsTable)
+ self.locationsGroupBox.setLayout(locationsLayout)
+
+ mainLayout = QtWidgets.QGridLayout()
+ mainLayout.addWidget(formatLabel, 0, 0)
+ mainLayout.addWidget(self.formatComboBox, 0, 1)
+ mainLayout.addWidget(scopeLabel, 1, 0)
+ mainLayout.addWidget(self.scopeComboBox, 1, 1)
+ mainLayout.addWidget(organizationLabel, 2, 0)
+ mainLayout.addWidget(self.organizationComboBox, 2, 1)
+ mainLayout.addWidget(applicationLabel, 3, 0)
+ mainLayout.addWidget(self.applicationComboBox, 3, 1)
+ mainLayout.addWidget(self.locationsGroupBox, 4, 0, 1, 2)
+ mainLayout.addWidget(self.buttonBox, 5, 0, 1, 2)
+ self.setLayout(mainLayout)
+
+ self.updateLocationsTable()
+
+ self.setWindowTitle("Open Application Settings")
+ self.resize(650, 400)
+
+ def format(self):
+ if self.formatComboBox.currentIndex() == 0:
+ return QtCore.QSettings.NativeFormat
+ else:
+ return QtCore.QSettings.IniFormat
+
+ def scope(self):
+ if self.scopeComboBox.currentIndex() == 0:
+ return QtCore.QSettings.UserScope
+ else:
+ return QtCore.QSettings.SystemScope
+
+ def organization(self):
+ return self.organizationComboBox.currentText()
+
+ def application(self):
+ if self.applicationComboBox.currentText() == "Any":
+ return ''
+
+ return self.applicationComboBox.currentText()
+
+ def updateLocationsTable(self):
+ self.locationsTable.setUpdatesEnabled(False)
+ self.locationsTable.setRowCount(0)
+
+ for i in range(2):
+ if i == 0:
+ if self.scope() == QtCore.QSettings.SystemScope:
+ continue
+
+ actualScope = QtCore.QSettings.UserScope
+ else:
+ actualScope = QtCore.QSettings.SystemScope
+
+ for j in range(2):
+ if j == 0:
+ if not self.application():
+ continue
+
+ actualApplication = self.application()
+ else:
+ actualApplication = ''
+
+ settings = QtCore.QSettings(self.format(), actualScope,
+ self.organization(), actualApplication)
+
+ row = self.locationsTable.rowCount()
+ self.locationsTable.setRowCount(row + 1)
+
+ item0 = QtWidgets.QTableWidgetItem()
+ item0.setText(settings.fileName())
+
+ item1 = QtWidgets.QTableWidgetItem()
+ disable = not (settings.childKeys() or settings.childGroups())
+
+ if row == 0:
+ if settings.isWritable():
+ item1.setText("Read-write")
+ disable = False
+ else:
+ item1.setText("Read-only")
+ self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).setDisabled(disable)
+ else:
+ item1.setText("Read-only fallback")
+
+ if disable:
+ item0.setFlags(item0.flags() & ~QtCore.Qt.ItemIsEnabled)
+ item1.setFlags(item1.flags() & ~QtCore.Qt.ItemIsEnabled)
+
+ self.locationsTable.setItem(row, 0, item0)
+ self.locationsTable.setItem(row, 1, item1)
+
+ self.locationsTable.setUpdatesEnabled(True)
+
+
+class SettingsTree(QtWidgets.QTreeWidget):
+ def __init__(self, parent=None):
+ super(SettingsTree, self).__init__(parent)
+
+ self.setItemDelegate(VariantDelegate(self))
+
+ self.setHeaderLabels(("Setting", "Type", "Value"))
+ self.header().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
+ self.header().setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
+
+ self.settings = None
+ self.refreshTimer = QtCore.QTimer()
+ self.refreshTimer.setInterval(2000)
+ self.autoRefresh = False
+
+ self.groupIcon = QtGui.QIcon()
+ self.groupIcon.addPixmap(self.style().standardPixmap(QtWidgets.QStyle.SP_DirClosedIcon),
+ QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ self.groupIcon.addPixmap(self.style().standardPixmap(QtWidgets.QStyle.SP_DirOpenIcon),
+ QtGui.QIcon.Normal, QtGui.QIcon.On)
+ self.keyIcon = QtGui.QIcon()
+ self.keyIcon.addPixmap(self.style().standardPixmap(QtWidgets.QStyle.SP_FileIcon))
+
+ self.refreshTimer.timeout.connect(self.maybeRefresh)
+
+ def setSettingsObject(self, settings):
+ self.settings = settings
+ self.clear()
+
+ if self.settings is not None:
+ self.settings.setParent(self)
+ self.refresh()
+ if self.autoRefresh:
+ self.refreshTimer.start()
+ else:
+ self.refreshTimer.stop()
+
+ def sizeHint(self):
+ return QtCore.QSize(800, 600)
+
+ def setAutoRefresh(self, autoRefresh):
+ self.autoRefresh = autoRefresh
+
+ if self.settings is not None:
+ if self.autoRefresh:
+ self.maybeRefresh()
+ self.refreshTimer.start()
+ else:
+ self.refreshTimer.stop()
+
+ def setFallbacksEnabled(self, enabled):
+ if self.settings is not None:
+ self.settings.setFallbacksEnabled(enabled)
+ self.refresh()
+
+ def maybeRefresh(self):
+ if self.state() != QtWidgets.QAbstractItemView.EditingState:
+ self.refresh()
+
+ def refresh(self):
+ if self.settings is None:
+ return
+
+ # The signal might not be connected.
+ try:
+ self.itemChanged.disconnect(self.updateSetting)
+ except:
+ pass
+
+ self.settings.sync()
+ self.updateChildItems(None)
+
+ self.itemChanged.connect(self.updateSetting)
+
+ def event(self, event):
+ if event.type() == QtCore.QEvent.WindowActivate:
+ if self.isActiveWindow() and self.autoRefresh:
+ self.maybeRefresh()
+
+ return super(SettingsTree, self).event(event)
+
+ def updateSetting(self, item):
+ key = item.text(0)
+ ancestor = item.parent()
+
+ while ancestor:
+ key = ancestor.text(0) + '/' + key
+ ancestor = ancestor.parent()
+
+ d = item.data(2, QtCore.Qt.UserRole)
+ self.settings.setValue(key, item.data(2, QtCore.Qt.UserRole))
+
+ if self.autoRefresh:
+ self.refresh()
+
+ def updateChildItems(self, parent):
+ dividerIndex = 0
+
+ for group in self.settings.childGroups():
+ childIndex = self.findChild(parent, group, dividerIndex)
+ if childIndex != -1:
+ child = self.childAt(parent, childIndex)
+ child.setText(1, '')
+ child.setText(2, '')
+ child.setData(2, QtCore.Qt.UserRole, None)
+ self.moveItemForward(parent, childIndex, dividerIndex)
+ else:
+ child = self.createItem(group, parent, dividerIndex)
+
+ child.setIcon(0, self.groupIcon)
+ dividerIndex += 1
+
+ self.settings.beginGroup(group)
+ self.updateChildItems(child)
+ self.settings.endGroup()
+
+ for key in self.settings.childKeys():
+ childIndex = self.findChild(parent, key, 0)
+ if childIndex == -1 or childIndex >= dividerIndex:
+ if childIndex != -1:
+ child = self.childAt(parent, childIndex)
+ for i in range(child.childCount()):
+ self.deleteItem(child, i)
+ self.moveItemForward(parent, childIndex, dividerIndex)
+ else:
+ child = self.createItem(key, parent, dividerIndex)
+ child.setIcon(0, self.keyIcon)
+ dividerIndex += 1
+ else:
+ child = self.childAt(parent, childIndex)
+
+ value = self.settings.value(key)
+ if value is None:
+ child.setText(1, 'Invalid')
+ else:
+ child.setText(1, value.__class__.__name__)
+ child.setText(2, VariantDelegate.displayText(value))
+ child.setData(2, QtCore.Qt.UserRole, value)
+
+ while dividerIndex < self.childCount(parent):
+ self.deleteItem(parent, dividerIndex)
+
+ def createItem(self, text, parent, index):
+ after = None
+
+ if index != 0:
+ after = self.childAt(parent, index - 1)
+
+ if parent is not None:
+ item = QtWidgets.QTreeWidgetItem(parent, after)
+ else:
+ item = QtWidgets.QTreeWidgetItem(self, after)
+
+ item.setText(0, text)
+ item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
+ return item
+
+ def deleteItem(self, parent, index):
+ if parent is not None:
+ item = parent.takeChild(index)
+ else:
+ item = self.takeTopLevelItem(index)
+ del item
+
+ def childAt(self, parent, index):
+ if parent is not None:
+ return parent.child(index)
+ else:
+ return self.topLevelItem(index)
+
+ def childCount(self, parent):
+ if parent is not None:
+ return parent.childCount()
+ else:
+ return self.topLevelItemCount()
+
+ def findChild(self, parent, text, startIndex):
+ for i in range(self.childCount(parent)):
+ if self.childAt(parent, i).text(0) == text:
+ return i
+ return -1
+
+ def moveItemForward(self, parent, oldIndex, newIndex):
+ for int in range(oldIndex - newIndex):
+ self.deleteItem(parent, newIndex)
+
+
+class VariantDelegate(QtWidgets.QItemDelegate):
+ def __init__(self, parent=None):
+ super(VariantDelegate, self).__init__(parent)
+
+ self.boolExp = QtCore.QRegExp()
+ self.boolExp.setPattern('true|false')
+ self.boolExp.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
+
+ self.byteArrayExp = QtCore.QRegExp()
+ self.byteArrayExp.setPattern('[\\x00-\\xff]*')
+
+ self.charExp = QtCore.QRegExp()
+ self.charExp.setPattern('.')
+
+ self.colorExp = QtCore.QRegExp()
+ self.colorExp.setPattern('\\(([0-9]*),([0-9]*),([0-9]*),([0-9]*)\\)')
+
+ self.doubleExp = QtCore.QRegExp()
+ self.doubleExp.setPattern('')
+
+ self.pointExp = QtCore.QRegExp()
+ self.pointExp.setPattern('\\((-?[0-9]*),(-?[0-9]*)\\)')
+
+ self.rectExp = QtCore.QRegExp()
+ self.rectExp.setPattern('\\((-?[0-9]*),(-?[0-9]*),(-?[0-9]*),(-?[0-9]*)\\)')
+
+ self.signedIntegerExp = QtCore.QRegExp()
+ self.signedIntegerExp.setPattern('-?[0-9]*')
+
+ self.sizeExp = QtCore.QRegExp(self.pointExp)
+
+ self.unsignedIntegerExp = QtCore.QRegExp()
+ self.unsignedIntegerExp.setPattern('[0-9]*')
+
+ self.dateExp = QtCore.QRegExp()
+ self.dateExp.setPattern('([0-9]{,4})-([0-9]{,2})-([0-9]{,2})')
+
+ self.timeExp = QtCore.QRegExp()
+ self.timeExp.setPattern('([0-9]{,2}):([0-9]{,2}):([0-9]{,2})')
+
+ self.dateTimeExp = QtCore.QRegExp()
+ self.dateTimeExp.setPattern(self.dateExp.pattern() + 'T' + self.timeExp.pattern())
+
+ def paint(self, painter, option, index):
+ if index.column() == 2:
+ value = index.model().data(index, QtCore.Qt.UserRole)
+ if not self.isSupportedType(value):
+ myOption = QtWidgets.QStyleOptionViewItem(option)
+ myOption.state &= ~QtWidgets.QStyle.State_Enabled
+ super(VariantDelegate, self).paint(painter, myOption, index)
+ return
+
+ super(VariantDelegate, self).paint(painter, option, index)
+
+ def createEditor(self, parent, option, index):
+ if index.column() != 2:
+ return None
+
+ originalValue = index.model().data(index, QtCore.Qt.UserRole)
+ if not self.isSupportedType(originalValue):
+ return None
+
+ lineEdit = QtWidgets.QLineEdit(parent)
+ lineEdit.setFrame(False)
+
+ if isinstance(originalValue, bool):
+ regExp = self.boolExp
+ elif isinstance(originalValue, float):
+ regExp = self.doubleExp
+ elif isinstance(originalValue, int):
+ regExp = self.signedIntegerExp
+ elif isinstance(originalValue, QtCore.QByteArray):
+ regExp = self.byteArrayExp
+ elif isinstance(originalValue, QtGui.QColor):
+ regExp = self.colorExp
+ elif isinstance(originalValue, QtCore.QDate):
+ regExp = self.dateExp
+ elif isinstance(originalValue, QtCore.QDateTime):
+ regExp = self.dateTimeExp
+ elif isinstance(originalValue, QtCore.QTime):
+ regExp = self.timeExp
+ elif isinstance(originalValue, QtCore.QPoint):
+ regExp = self.pointExp
+ elif isinstance(originalValue, QtCore.QRect):
+ regExp = self.rectExp
+ elif isinstance(originalValue, QtCore.QSize):
+ regExp = self.sizeExp
+ else:
+ regExp = QtCore.QRegExp()
+
+ if not regExp.isEmpty():
+ validator = QtGui.QRegExpValidator(regExp, lineEdit)
+ lineEdit.setValidator(validator)
+
+ return lineEdit
+
+ def setEditorData(self, editor, index):
+ value = index.model().data(index, QtCore.Qt.UserRole)
+ if editor is not None:
+ editor.setText(self.displayText(value))
+
+ def setModelData(self, editor, model, index):
+ if not editor.isModified():
+ return
+
+ text = editor.text()
+ validator = editor.validator()
+ if validator is not None:
+ state, text, _ = validator.validate(text, 0)
+ if state != QtGui.QValidator.Acceptable:
+ return
+
+ originalValue = index.model().data(index, QtCore.Qt.UserRole)
+
+ if isinstance(originalValue, QtGui.QColor):
+ self.colorExp.exactMatch(text)
+ value = QtGui.QColor(min(int(self.colorExp.cap(1)), 255),
+ min(int(self.colorExp.cap(2)), 255),
+ min(int(self.colorExp.cap(3)), 255),
+ min(int(self.colorExp.cap(4)), 255))
+ elif isinstance(originalValue, QtCore.QDate):
+ value = QtCore.QDate.fromString(text, QtCore.Qt.ISODate)
+ if not value.isValid():
+ return
+ elif isinstance(originalValue, QtCore.QDateTime):
+ value = QtCore.QDateTime.fromString(text, QtCore.Qt.ISODate)
+ if not value.isValid():
+ return
+ elif isinstance(originalValue, QtCore.QTime):
+ value = QtCore.QTime.fromString(text, QtCore.Qt.ISODate)
+ if not value.isValid():
+ return
+ elif isinstance(originalValue, QtCore.QPoint):
+ self.pointExp.exactMatch(text)
+ value = QtCore.QPoint(int(self.pointExp.cap(1)),
+ int(self.pointExp.cap(2)))
+ elif isinstance(originalValue, QtCore.QRect):
+ self.rectExp.exactMatch(text)
+ value = QtCore.QRect(int(self.rectExp.cap(1)),
+ int(self.rectExp.cap(2)),
+ int(self.rectExp.cap(3)),
+ int(self.rectExp.cap(4)))
+ elif isinstance(originalValue, QtCore.QSize):
+ self.sizeExp.exactMatch(text)
+ value = QtCore.QSize(int(self.sizeExp.cap(1)),
+ int(self.sizeExp.cap(2)))
+ elif isinstance(originalValue, list):
+ value = text.split(',')
+ else:
+ value = type(originalValue)(text)
+
+ model.setData(index, self.displayText(value), QtCore.Qt.DisplayRole)
+ model.setData(index, value, QtCore.Qt.UserRole)
+
+ @staticmethod
+ def isSupportedType(value):
+ return isinstance(value, (bool, float, int, QtCore.QByteArray,
+ str, QtGui.QColor, QtCore.QDate, QtCore.QDateTime,
+ QtCore.QTime, QtCore.QPoint, QtCore.QRect, QtCore.QSize,
+ list))
+
+ @staticmethod
+ def displayText(value):
+ if isinstance(value, (bool, int, QtCore.QByteArray)):
+ return str(value)
+ if isinstance(value, str):
+ return value
+ elif isinstance(value, float):
+ return '%g' % value
+ elif isinstance(value, QtGui.QColor):
+ return '(%u,%u,%u,%u)' % (value.red(), value.green(), value.blue(), value.alpha())
+ elif isinstance(value, (QtCore.QDate, QtCore.QDateTime, QtCore.QTime)):
+ return value.toString(QtCore.Qt.ISODate)
+ elif isinstance(value, QtCore.QPoint):
+ return '(%d,%d)' % (value.x(), value.y())
+ elif isinstance(value, QtCore.QRect):
+ return '(%d,%d,%d,%d)' % (value.x(), value.y(), value.width(), value.height())
+ elif isinstance(value, QtCore.QSize):
+ return '(%d,%d)' % (value.width(), value.height())
+ elif isinstance(value, list):
+ return ','.join(value)
+ elif value is None:
+ return '<Invalid>'
+
+ return '<%s>' % value
+
+
+if __name__ == '__main__':
+ app = QtWidgets.QApplication(sys.argv)
+ mainWin = MainWindow()
+ mainWin.show()
+ sys.exit(app.exec_())