diff options
Diffstat (limited to 'examples/widgets/richtext')
8 files changed, 1132 insertions, 0 deletions
diff --git a/examples/widgets/richtext/orderform.py b/examples/widgets/richtext/orderform.py new file mode 100755 index 000000000..e068db2b2 --- /dev/null +++ b/examples/widgets/richtext/orderform.py @@ -0,0 +1,297 @@ +#!/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/richtext/orderform example from Qt v5.x""" + +from PySide2 import QtCore, QtGui, QtWidgets, QtPrintSupport + + +class MainWindow(QtWidgets.QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + + fileMenu = QtWidgets.QMenu("&File", self) + newAction = fileMenu.addAction("&New...") + newAction.setShortcut("Ctrl+N") + self.printAction = fileMenu.addAction("&Print...", self.printFile) + self.printAction.setShortcut("Ctrl+P") + self.printAction.setEnabled(False) + quitAction = fileMenu.addAction("E&xit") + quitAction.setShortcut("Ctrl+Q") + self.menuBar().addMenu(fileMenu) + + self.letters = QtWidgets.QTabWidget() + + newAction.triggered.connect(self.openDialog) + quitAction.triggered.connect(self.close) + + self.setCentralWidget(self.letters) + self.setWindowTitle("Order Form") + + def createLetter(self, name, address, orderItems, sendOffers): + editor = QtWidgets.QTextEdit() + tabIndex = self.letters.addTab(editor, name) + self.letters.setCurrentIndex(tabIndex) + + cursor = editor.textCursor() + cursor.movePosition(QtGui.QTextCursor.Start) + topFrame = cursor.currentFrame() + topFrameFormat = topFrame.frameFormat() + topFrameFormat.setPadding(16) + topFrame.setFrameFormat(topFrameFormat) + + textFormat = QtGui.QTextCharFormat() + boldFormat = QtGui.QTextCharFormat() + boldFormat.setFontWeight(QtGui.QFont.Bold) + + referenceFrameFormat = QtGui.QTextFrameFormat() + referenceFrameFormat.setBorder(1) + referenceFrameFormat.setPadding(8) + referenceFrameFormat.setPosition(QtGui.QTextFrameFormat.FloatRight) + referenceFrameFormat.setWidth(QtGui.QTextLength(QtGui.QTextLength.PercentageLength, 40)) + cursor.insertFrame(referenceFrameFormat) + + cursor.insertText("A company", boldFormat) + cursor.insertBlock() + cursor.insertText("321 City Street") + cursor.insertBlock() + cursor.insertText("Industry Park") + cursor.insertBlock() + cursor.insertText("Another country") + + cursor.setPosition(topFrame.lastPosition()) + + cursor.insertText(name, textFormat) + for line in address.split("\n"): + cursor.insertBlock() + cursor.insertText(line) + + cursor.insertBlock() + cursor.insertBlock() + + date = QtCore.QDate.currentDate() + cursor.insertText("Date: %s" % date.toString('d MMMM yyyy'), + textFormat) + cursor.insertBlock() + + bodyFrameFormat = QtGui.QTextFrameFormat() + bodyFrameFormat.setWidth(QtGui.QTextLength(QtGui.QTextLength.PercentageLength, 100)) + cursor.insertFrame(bodyFrameFormat) + + cursor.insertText("I would like to place an order for the following " + "items:", textFormat) + cursor.insertBlock() + cursor.insertBlock() + + orderTableFormat = QtGui.QTextTableFormat() + orderTableFormat.setAlignment(QtCore.Qt.AlignHCenter) + orderTable = cursor.insertTable(1, 2, orderTableFormat) + + orderFrameFormat = cursor.currentFrame().frameFormat() + orderFrameFormat.setBorder(1) + cursor.currentFrame().setFrameFormat(orderFrameFormat) + + cursor = orderTable.cellAt(0, 0).firstCursorPosition() + cursor.insertText("Product", boldFormat) + cursor = orderTable.cellAt(0, 1).firstCursorPosition() + cursor.insertText("Quantity", boldFormat) + + for text, quantity in orderItems: + row = orderTable.rows() + + orderTable.insertRows(row, 1) + cursor = orderTable.cellAt(row, 0).firstCursorPosition() + cursor.insertText(text, textFormat) + cursor = orderTable.cellAt(row, 1).firstCursorPosition() + cursor.insertText(str(quantity), textFormat) + + cursor.setPosition(topFrame.lastPosition()) + + cursor.insertBlock() + + cursor.insertText("Please update my records to take account of the " + "following privacy information:") + cursor.insertBlock() + + offersTable = cursor.insertTable(2, 2) + + cursor = offersTable.cellAt(0, 1).firstCursorPosition() + cursor.insertText("I want to receive more information about your " + "company's products and special offers.", textFormat) + cursor = offersTable.cellAt(1, 1).firstCursorPosition() + cursor.insertText("I do not want to receive any promotional " + "information from your company.", textFormat) + + if sendOffers: + cursor = offersTable.cellAt(0, 0).firstCursorPosition() + else: + cursor = offersTable.cellAt(1, 0).firstCursorPosition() + + cursor.insertText('X', boldFormat) + + cursor.setPosition(topFrame.lastPosition()) + cursor.insertBlock() + cursor.insertText("Sincerely,", textFormat) + cursor.insertBlock() + cursor.insertBlock() + cursor.insertBlock() + cursor.insertText(name) + + self.printAction.setEnabled(True) + + def createSample(self): + dialog = DetailsDialog('Dialog with default values', self) + self.createLetter('Mr Smith', + '12 High Street\nSmall Town\nThis country', + dialog.orderItems(), True) + + def openDialog(self): + dialog = DetailsDialog("Enter Customer Details", self) + + if dialog.exec_() == QtWidgets.QDialog.Accepted: + self.createLetter(dialog.senderName(), dialog.senderAddress(), + dialog.orderItems(), dialog.sendOffers()) + + def printFile(self): + editor = self.letters.currentWidget() + printer = QtPrintSupport.QPrinter() + + dialog = QtPrintSupport.QPrintDialog(printer, self) + dialog.setWindowTitle("Print Document") + + if editor.textCursor().hasSelection(): + dialog.addEnabledOption(QtPrintSupport.QAbstractPrintDialog.PrintSelection) + + if dialog.exec_() != QtWidgets.QDialog.Accepted: + return + + editor.print_(printer) + + +class DetailsDialog(QtWidgets.QDialog): + def __init__(self, title, parent): + super(DetailsDialog, self).__init__(parent) + + self.items = ("T-shirt", "Badge", "Reference book", "Coffee cup") + + nameLabel = QtWidgets.QLabel("Name:") + addressLabel = QtWidgets.QLabel("Address:") + addressLabel.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) + + self.nameEdit = QtWidgets.QLineEdit() + self.addressEdit = QtWidgets.QTextEdit() + self.offersCheckBox = QtWidgets.QCheckBox("Send information about " + "products and special offers:") + + self.setupItemsTable() + + buttonBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) + + buttonBox.accepted.connect(self.verify) + buttonBox.rejected.connect(self.reject) + + mainLayout = QtWidgets.QGridLayout() + mainLayout.addWidget(nameLabel, 0, 0) + mainLayout.addWidget(self.nameEdit, 0, 1) + mainLayout.addWidget(addressLabel, 1, 0) + mainLayout.addWidget(self.addressEdit, 1, 1) + mainLayout.addWidget(self.itemsTable, 0, 2, 2, 1) + mainLayout.addWidget(self.offersCheckBox, 2, 1, 1, 2) + mainLayout.addWidget(buttonBox, 3, 0, 1, 3) + self.setLayout(mainLayout) + + self.setWindowTitle(title) + + def setupItemsTable(self): + self.itemsTable = QtWidgets.QTableWidget(len(self.items), 2) + + for row, item in enumerate(self.items): + name = QtWidgets.QTableWidgetItem(item) + name.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) + self.itemsTable.setItem(row, 0, name) + quantity = QtWidgets.QTableWidgetItem('1') + self.itemsTable.setItem(row, 1, quantity) + + def orderItems(self): + orderList = [] + + for row in range(len(self.items)): + text = self.itemsTable.item(row, 0).text() + quantity = int(self.itemsTable.item(row, 1).data(QtCore.Qt.DisplayRole)) + orderList.append((text, max(0, quantity))) + + return orderList + + def senderName(self): + return self.nameEdit.text() + + def senderAddress(self): + return self.addressEdit.toPlainText() + + def sendOffers(self): + return self.offersCheckBox.isChecked() + + def verify(self): + if self.nameEdit.text() and self.addressEdit.toPlainText(): + self.accept() + return + + answer = QtWidgets.QMessageBox.warning(self, "Incomplete Form", + "The form does not contain all the necessary information.\n" + "Do you want to discard it?", + QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) + + if answer == QtWidgets.QMessageBox.Yes: + self.reject() + + +if __name__ == '__main__': + + import sys + + app = QtWidgets.QApplication(sys.argv) + window = MainWindow() + window.resize(640, 480) + window.show() + window.createSample() + sys.exit(app.exec_()) diff --git a/examples/widgets/richtext/syntaxhighlighter.py b/examples/widgets/richtext/syntaxhighlighter.py new file mode 100755 index 000000000..8a14632fe --- /dev/null +++ b/examples/widgets/richtext/syntaxhighlighter.py @@ -0,0 +1,203 @@ +#!/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/richtext/syntaxhighlighter example from Qt v5.x""" + +from PySide2 import QtCore, QtGui, QtWidgets + + +class MainWindow(QtWidgets.QMainWindow): + def __init__(self, parent=None): + super(MainWindow, self).__init__(parent) + + self.setupFileMenu() + self.setupHelpMenu() + self.setupEditor() + + self.setCentralWidget(self.editor) + self.setWindowTitle("Syntax Highlighter") + + def about(self): + QtWidgets.QMessageBox.about(self, "About Syntax Highlighter", + "<p>The <b>Syntax Highlighter</b> example shows how to " \ + "perform simple syntax highlighting by subclassing the " \ + "QSyntaxHighlighter class and describing highlighting " \ + "rules using regular expressions.</p>") + + def newFile(self): + self.editor.clear() + + def openFile(self, path=None): + if not path: + path = QtWidgets.QFileDialog.getOpenFileName(self, "Open File", + '', "C++ Files (*.cpp *.h)") + + if path: + inFile = QtCore.QFile(path[0]) + if inFile.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text): + text = inFile.readAll() + + try: + # Python v3. + text = str(text, encoding='ascii') + except TypeError: + # Python v2. + text = str(text) + + self.editor.setPlainText(text) + + def setupEditor(self): + font = QtGui.QFont() + font.setFamily('Courier') + font.setFixedPitch(True) + font.setPointSize(10) + + self.editor = QtWidgets.QTextEdit() + self.editor.setFont(font) + + self.highlighter = Highlighter(self.editor.document()) + + def setupFileMenu(self): + fileMenu = QtWidgets.QMenu("&File", self) + self.menuBar().addMenu(fileMenu) + + fileMenu.addAction("&New...", self.newFile, "Ctrl+N") + fileMenu.addAction("&Open...", self.openFile, "Ctrl+O") + fileMenu.addAction("E&xit", QtWidgets.qApp.quit, "Ctrl+Q") + + def setupHelpMenu(self): + helpMenu = QtWidgets.QMenu("&Help", self) + self.menuBar().addMenu(helpMenu) + + helpMenu.addAction("&About", self.about) + helpMenu.addAction("About &Qt", QtWidgets.qApp.aboutQt) + + +class Highlighter(QtGui.QSyntaxHighlighter): + def __init__(self, parent=None): + super(Highlighter, self).__init__(parent) + + keywordFormat = QtGui.QTextCharFormat() + keywordFormat.setForeground(QtCore.Qt.darkBlue) + keywordFormat.setFontWeight(QtGui.QFont.Bold) + + keywordPatterns = ["\\bchar\\b", "\\bclass\\b", "\\bconst\\b", + "\\bdouble\\b", "\\benum\\b", "\\bexplicit\\b", "\\bfriend\\b", + "\\binline\\b", "\\bint\\b", "\\blong\\b", "\\bnamespace\\b", + "\\boperator\\b", "\\bprivate\\b", "\\bprotected\\b", + "\\bpublic\\b", "\\bshort\\b", "\\bsignals\\b", "\\bsigned\\b", + "\\bslots\\b", "\\bstatic\\b", "\\bstruct\\b", + "\\btemplate\\b", "\\btypedef\\b", "\\btypename\\b", + "\\bunion\\b", "\\bunsigned\\b", "\\bvirtual\\b", "\\bvoid\\b", + "\\bvolatile\\b"] + + self.highlightingRules = [(QtCore.QRegExp(pattern), keywordFormat) + for pattern in keywordPatterns] + + classFormat = QtGui.QTextCharFormat() + classFormat.setFontWeight(QtGui.QFont.Bold) + classFormat.setForeground(QtCore.Qt.darkMagenta) + self.highlightingRules.append((QtCore.QRegExp("\\bQ[A-Za-z]+\\b"), + classFormat)) + + singleLineCommentFormat = QtGui.QTextCharFormat() + singleLineCommentFormat.setForeground(QtCore.Qt.red) + self.highlightingRules.append((QtCore.QRegExp("//[^\n]*"), + singleLineCommentFormat)) + + self.multiLineCommentFormat = QtGui.QTextCharFormat() + self.multiLineCommentFormat.setForeground(QtCore.Qt.red) + + quotationFormat = QtGui.QTextCharFormat() + quotationFormat.setForeground(QtCore.Qt.darkGreen) + self.highlightingRules.append((QtCore.QRegExp("\".*\""), + quotationFormat)) + + functionFormat = QtGui.QTextCharFormat() + functionFormat.setFontItalic(True) + functionFormat.setForeground(QtCore.Qt.blue) + self.highlightingRules.append((QtCore.QRegExp("\\b[A-Za-z0-9_]+(?=\\()"), + functionFormat)) + + self.commentStartExpression = QtCore.QRegExp("/\\*") + self.commentEndExpression = QtCore.QRegExp("\\*/") + + def highlightBlock(self, text): + for pattern, format in self.highlightingRules: + expression = QtCore.QRegExp(pattern) + index = expression.indexIn(text) + while index >= 0: + length = expression.matchedLength() + self.setFormat(index, length, format) + index = expression.indexIn(text, index + length) + + self.setCurrentBlockState(0) + + startIndex = 0 + if self.previousBlockState() != 1: + startIndex = self.commentStartExpression.indexIn(text) + + while startIndex >= 0: + endIndex = self.commentEndExpression.indexIn(text, startIndex) + + if endIndex == -1: + self.setCurrentBlockState(1) + commentLength = len(text) - startIndex + else: + commentLength = endIndex - startIndex + self.commentEndExpression.matchedLength() + + self.setFormat(startIndex, commentLength, + self.multiLineCommentFormat) + startIndex = self.commentStartExpression.indexIn(text, + startIndex + commentLength); + + +if __name__ == '__main__': + + import sys + + app = QtWidgets.QApplication(sys.argv) + window = MainWindow() + window.resize(640, 512) + window.show() + sys.exit(app.exec_()) diff --git a/examples/widgets/richtext/syntaxhighlighter/examples/example b/examples/widgets/richtext/syntaxhighlighter/examples/example new file mode 100644 index 000000000..db8e7b189 --- /dev/null +++ b/examples/widgets/richtext/syntaxhighlighter/examples/example @@ -0,0 +1,79 @@ +TEMPLATE = app +LANGUAGE = C++ +TARGET = assistant + +CONFIG += qt warn_on +QT += xml network + +PROJECTNAME = Assistant +DESTDIR = ../../bin + +FORMS += finddialog.ui \ + helpdialog.ui \ + mainwindow.ui \ + settingsdialog.ui \ + tabbedbrowser.ui \ + topicchooser.ui + +SOURCES += main.cpp \ + helpwindow.cpp \ + topicchooser.cpp \ + docuparser.cpp \ + settingsdialog.cpp \ + index.cpp \ + profile.cpp \ + config.cpp \ + finddialog.cpp \ + helpdialog.cpp \ + mainwindow.cpp \ + tabbedbrowser.cpp + +HEADERS += helpwindow.h \ + topicchooser.h \ + docuparser.h \ + settingsdialog.h \ + index.h \ + profile.h \ + finddialog.h \ + helpdialog.h \ + mainwindow.h \ + tabbedbrowser.h \ + config.h + +RESOURCES += assistant.qrc + +DEFINES += QT_KEYWORDS +#DEFINES += QT_PALMTOPCENTER_DOCS +!network:DEFINES += QT_INTERNAL_NETWORK +else:QT += network +!xml: DEFINES += QT_INTERNAL_XML +else:QT += xml +include( ../../src/qt_professional.pri ) + +win32 { + LIBS += -lshell32 + RC_FILE = assistant.rc +} + +macos { + ICON = assistant.icns + TARGET = assistant +# QMAKE_INFO_PLIST = Info_mac.plist +} + +#target.path = $$[QT_INSTALL_BINS] +#INSTALLS += target + +#assistanttranslations.files = *.qm +#assistanttranslations.path = $$[QT_INSTALL_TRANSLATIONS] +#INSTALLS += assistanttranslations + +TRANSLATIONS = assistant_de.ts \ + assistant_fr.ts + + +unix:!contains(QT_CONFIG, zlib):LIBS += -lz + + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target diff --git a/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.py b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.py new file mode 100644 index 000000000..6b913f177 --- /dev/null +++ b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.py @@ -0,0 +1,180 @@ +#!/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/richtext/syntaxhighlighter example from Qt v5.x""" + +import sys +import re +from PySide2 import QtCore, QtGui, QtWidgets + +import syntaxhighlighter_rc + + +class MainWindow(QtWidgets.QMainWindow): + def __init__(self, parent=None): + QtWidgets.QMainWindow.__init__(self, parent) + + self.highlighter = Highlighter() + + self.setupFileMenu() + self.setupEditor() + + self.setCentralWidget(self.editor) + self.setWindowTitle(self.tr("Syntax Highlighter")) + + def newFile(self): + self.editor.clear() + + def openFile(self, path=""): + fileName = path + + if fileName=="": + fileName,_ = QtWidgets.QFileDialog.getOpenFileName(self, self.tr("Open File"), "", + "qmake Files (*.pro *.prf *.pri)") + + if fileName!="": + inFile = QtCore.QFile(fileName) + if inFile.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text): + self.editor.setPlainText(unicode(inFile.readAll())) + + def setupEditor(self): + variableFormat = QtGui.QTextCharFormat() + variableFormat.setFontWeight(QtGui.QFont.Bold) + variableFormat.setForeground(QtCore.Qt.blue) + self.highlighter.addMapping("\\b[A-Z_]+\\b", variableFormat) + + singleLineCommentFormat = QtGui.QTextCharFormat() + singleLineCommentFormat.setBackground(QtGui.QColor("#77ff77")) + self.highlighter.addMapping("#[^\n]*", singleLineCommentFormat) + + quotationFormat = QtGui.QTextCharFormat() + quotationFormat.setBackground(QtCore.Qt.cyan) + quotationFormat.setForeground(QtCore.Qt.blue) + self.highlighter.addMapping("\".*\"", quotationFormat) + + functionFormat = QtGui.QTextCharFormat() + functionFormat.setFontItalic(True) + functionFormat.setForeground(QtCore.Qt.blue) + self.highlighter.addMapping("\\b[a-z0-9_]+\\(.*\\)", functionFormat) + + font = QtGui.QFont() + font.setFamily("Courier") + font.setFixedPitch(True) + font.setPointSize(10) + + self.editor = QtWidgets.QTextEdit() + self.editor.setFont(font) + self.highlighter.addToDocument(self.editor.document()) + + def setupFileMenu(self): + fileMenu = QtWidgets.QMenu(self.tr("&File"), self) + self.menuBar().addMenu(fileMenu) + + newFileAct = QtWidgets.QAction(self.tr("&New..."), self) + newFileAct.setShortcut(QtGui.QKeySequence(self.tr("Ctrl+N", "File|New"))) + self.connect(newFileAct, QtCore.SIGNAL("triggered()"), self.newFile) + fileMenu.addAction(newFileAct) + + openFileAct = QtWidgets.QAction(self.tr("&Open..."), self) + openFileAct.setShortcut(QtGui.QKeySequence(self.tr("Ctrl+O", "File|Open"))) + self.connect(openFileAct, QtCore.SIGNAL("triggered()"), self.openFile) + fileMenu.addAction(openFileAct) + + fileMenu.addAction(self.tr("E&xit"), QtWidgets.qApp, QtCore.SLOT("quit()"), + QtGui.QKeySequence(self.tr("Ctrl+Q", "File|Exit"))) + + +class Highlighter(QtCore.QObject): + def __init__(self, parent=None): + QtCore.QObject.__init__(self, parent) + + self.mappings = {} + + def addToDocument(self, doc): + self.connect(doc, QtCore.SIGNAL("contentsChange(int, int, int)"), self.highlight) + + def addMapping(self, pattern, format): + self.mappings[pattern] = format + + def highlight(self, position, removed, added): + doc = self.sender() + + block = doc.findBlock(position) + if not block.isValid(): + return + + if added > removed: + endBlock = doc.findBlock(position + added) + else: + endBlock = block + + while block.isValid() and not (endBlock < block): + self.highlightBlock(block) + block = block.next() + + def highlightBlock(self, block): + layout = block.layout() + text = block.text() + + overrides = [] + + for pattern in self.mappings: + for m in re.finditer(pattern,text): + range = QtGui.QTextLayout.FormatRange() + s,e = m.span() + range.start = s + range.length = e-s + range.format = self.mappings[pattern] + overrides.append(range) + + layout.setAdditionalFormats(overrides) + block.document().markContentsDirty(block.position(), block.length()) + + +if __name__ == '__main__': + app = QtWidgets.QApplication(sys.argv) + window = MainWindow() + window.resize(640, 512) + window.show() + window.openFile(":/examples/example") + sys.exit(app.exec_()) diff --git a/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.qrc b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.qrc new file mode 100644 index 000000000..e5f9abf1e --- /dev/null +++ b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/" > + <file>examples/example</file> +</qresource> +</RCC> diff --git a/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter_rc.py b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter_rc.py new file mode 100644 index 000000000..81321bb65 --- /dev/null +++ b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter_rc.py @@ -0,0 +1,183 @@ +############################################################################# +## +## 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$ +## +############################################################################# + +# Resource object code +# +# Created: Wed Dec 28 19:56:58 2005 +# by: The Resource Compiler for PyQt (Qt v4.1.0) +# +# WARNING! All changes made in this file will be lost! + +from PySide2 import QtCore + +qt_resource_data = b"\ +\x00\x00\x06\x79\ +\x54\ +\x45\x4d\x50\x4c\x41\x54\x45\x20\x3d\x20\x61\x70\x70\x0a\x4c\x41\ +\x4e\x47\x55\x41\x47\x45\x20\x3d\x20\x43\x2b\x2b\x0a\x54\x41\x52\ +\x47\x45\x54\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3d\x20\x61\x73\ +\x73\x69\x73\x74\x61\x6e\x74\x0a\x0a\x43\x4f\x4e\x46\x49\x47\x20\ +\x20\x20\x20\x20\x20\x20\x20\x2b\x3d\x20\x71\x74\x20\x77\x61\x72\ +\x6e\x5f\x6f\x6e\x0a\x51\x54\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x2b\x3d\x20\x78\x6d\x6c\x20\x6e\x65\x74\x77\x6f\x72\ +\x6b\x0a\x0a\x50\x52\x4f\x4a\x45\x43\x54\x4e\x41\x4d\x45\x20\x20\ +\x20\x20\x20\x20\x20\x20\x3d\x20\x41\x73\x73\x69\x73\x74\x61\x6e\ +\x74\x0a\x44\x45\x53\x54\x44\x49\x52\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x3d\x20\x2e\x2e\x2f\x2e\x2e\x2f\x62\x69\x6e\ +\x0a\x0a\x46\x4f\x52\x4d\x53\x20\x2b\x3d\x20\x66\x69\x6e\x64\x64\ +\x69\x61\x6c\x6f\x67\x2e\x75\x69\x20\x5c\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x68\x65\x6c\x70\x64\x69\x61\x6c\x6f\x67\x2e\x75\x69\ +\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6d\x61\x69\x6e\x77\ +\x69\x6e\x64\x6f\x77\x2e\x75\x69\x20\x5c\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x64\x69\x61\x6c\x6f\ +\x67\x2e\x75\x69\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x74\ +\x61\x62\x62\x65\x64\x62\x72\x6f\x77\x73\x65\x72\x2e\x75\x69\x20\ +\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x74\x6f\x70\x69\x63\x63\ +\x68\x6f\x6f\x73\x65\x72\x2e\x75\x69\x0a\x0a\x53\x4f\x55\x52\x43\ +\x45\x53\x20\x2b\x3d\x20\x6d\x61\x69\x6e\x2e\x63\x70\x70\x20\x5c\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x68\x65\x6c\x70\x77\x69\x6e\ +\x64\x6f\x77\x2e\x63\x70\x70\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x74\x6f\x70\x69\x63\x63\x68\x6f\x6f\x73\x65\x72\x2e\x63\ +\x70\x70\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x64\x6f\x63\ +\x75\x70\x61\x72\x73\x65\x72\x2e\x63\x70\x70\x20\x5c\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x64\x69\ +\x61\x6c\x6f\x67\x2e\x63\x70\x70\x20\x5c\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x69\x6e\x64\x65\x78\x2e\x63\x70\x70\x20\x5c\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x70\x72\x6f\x66\x69\x6c\x65\x2e\x63\ +\x70\x70\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x63\x6f\x6e\ +\x66\x69\x67\x2e\x63\x70\x70\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x66\x69\x6e\x64\x64\x69\x61\x6c\x6f\x67\x2e\x63\x70\x70\ +\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x68\x65\x6c\x70\x64\ +\x69\x61\x6c\x6f\x67\x2e\x63\x70\x70\x20\x5c\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x6d\x61\x69\x6e\x77\x69\x6e\x64\x6f\x77\x2e\x63\ +\x70\x70\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x74\x61\x62\ +\x62\x65\x64\x62\x72\x6f\x77\x73\x65\x72\x2e\x63\x70\x70\x0a\x0a\ +\x48\x45\x41\x44\x45\x52\x53\x20\x20\x20\x20\x20\x20\x20\x20\x2b\ +\x3d\x20\x68\x65\x6c\x70\x77\x69\x6e\x64\x6f\x77\x2e\x68\x20\x5c\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x74\x6f\x70\x69\x63\x63\x68\ +\x6f\x6f\x73\x65\x72\x2e\x68\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x64\x6f\x63\x75\x70\x61\x72\x73\x65\x72\x2e\x68\x20\x5c\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x74\x74\x69\x6e\x67\ +\x73\x64\x69\x61\x6c\x6f\x67\x2e\x68\x20\x5c\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x69\x6e\x64\x65\x78\x2e\x68\x20\x5c\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x70\x72\x6f\x66\x69\x6c\x65\x2e\x68\x20\ +\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x69\x6e\x64\x64\x69\ +\x61\x6c\x6f\x67\x2e\x68\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x68\x65\x6c\x70\x64\x69\x61\x6c\x6f\x67\x2e\x68\x20\x5c\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x20\x6d\x61\x69\x6e\x77\x69\x6e\x64\ +\x6f\x77\x2e\x68\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x74\ +\x61\x62\x62\x65\x64\x62\x72\x6f\x77\x73\x65\x72\x2e\x68\x20\x5c\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x63\x6f\x6e\x66\x69\x67\x2e\ +\x68\x0a\x0a\x52\x45\x53\x4f\x55\x52\x43\x45\x53\x20\x2b\x3d\x20\ +\x61\x73\x73\x69\x73\x74\x61\x6e\x74\x2e\x71\x72\x63\x0a\x0a\x44\ +\x45\x46\x49\x4e\x45\x53\x20\x2b\x3d\x20\x51\x54\x5f\x4b\x45\x59\ +\x57\x4f\x52\x44\x53\x0a\x23\x44\x45\x46\x49\x4e\x45\x53\x20\x2b\ +\x3d\x20\x20\x51\x54\x5f\x50\x41\x4c\x4d\x54\x4f\x50\x43\x45\x4e\ +\x54\x45\x52\x5f\x44\x4f\x43\x53\x0a\x21\x6e\x65\x74\x77\x6f\x72\ +\x6b\x3a\x44\x45\x46\x49\x4e\x45\x53\x20\x20\x20\x20\x20\x20\x20\ +\x20\x2b\x3d\x20\x51\x54\x5f\x49\x4e\x54\x45\x52\x4e\x41\x4c\x5f\ +\x4e\x45\x54\x57\x4f\x52\x4b\x0a\x65\x6c\x73\x65\x3a\x51\x54\x20\ +\x2b\x3d\x20\x6e\x65\x74\x77\x6f\x72\x6b\x0a\x21\x78\x6d\x6c\x3a\ +\x20\x44\x45\x46\x49\x4e\x45\x53\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x2b\x3d\x20\x51\x54\x5f\x49\x4e\ +\x54\x45\x52\x4e\x41\x4c\x5f\x58\x4d\x4c\x0a\x65\x6c\x73\x65\x3a\ +\x51\x54\x20\x2b\x3d\x20\x78\x6d\x6c\x0a\x69\x6e\x63\x6c\x75\x64\ +\x65\x28\x20\x2e\x2e\x2f\x2e\x2e\x2f\x73\x72\x63\x2f\x71\x74\x5f\ +\x70\x72\x6f\x66\x65\x73\x73\x69\x6f\x6e\x61\x6c\x2e\x70\x72\x69\ +\x20\x29\x0a\x0a\x77\x69\x6e\x33\x32\x20\x7b\x0a\x20\x20\x20\x20\ +\x4c\x49\x42\x53\x20\x2b\x3d\x20\x2d\x6c\x73\x68\x65\x6c\x6c\x33\ +\x32\x0a\x20\x20\x20\x20\x52\x43\x5f\x46\x49\x4c\x45\x20\x3d\x20\ +\x61\x73\x73\x69\x73\x74\x61\x6e\x74\x2e\x72\x63\x0a\x7d\x0a\x0a\ +\x6d\x61\x63\x20\x7b\x0a\x20\x20\x20\x20\x49\x43\x4f\x4e\x20\x3d\ +\x20\x61\x73\x73\x69\x73\x74\x61\x6e\x74\x2e\x69\x63\x6e\x73\x0a\ +\x20\x20\x20\x20\x54\x41\x52\x47\x45\x54\x20\x3d\x20\x61\x73\x73\ +\x69\x73\x74\x61\x6e\x74\x0a\x23\x20\x20\x20\x20\x51\x4d\x41\x4b\ +\x45\x5f\x49\x4e\x46\x4f\x5f\x50\x4c\x49\x53\x54\x20\x3d\x20\x49\ +\x6e\x66\x6f\x5f\x6d\x61\x63\x2e\x70\x6c\x69\x73\x74\x0a\x7d\x0a\ +\x0a\x23\x74\x61\x72\x67\x65\x74\x2e\x70\x61\x74\x68\x20\x3d\x20\ +\x24\x24\x5b\x51\x54\x5f\x49\x4e\x53\x54\x41\x4c\x4c\x5f\x42\x49\ +\x4e\x53\x5d\x0a\x23\x49\x4e\x53\x54\x41\x4c\x4c\x53\x20\x2b\x3d\ +\x20\x74\x61\x72\x67\x65\x74\x0a\x0a\x23\x61\x73\x73\x69\x73\x74\ +\x61\x6e\x74\x74\x72\x61\x6e\x73\x6c\x61\x74\x69\x6f\x6e\x73\x2e\ +\x66\x69\x6c\x65\x73\x20\x3d\x20\x2a\x2e\x71\x6d\x0a\x23\x61\x73\ +\x73\x69\x73\x74\x61\x6e\x74\x74\x72\x61\x6e\x73\x6c\x61\x74\x69\ +\x6f\x6e\x73\x2e\x70\x61\x74\x68\x20\x3d\x20\x24\x24\x5b\x51\x54\ +\x5f\x49\x4e\x53\x54\x41\x4c\x4c\x5f\x54\x52\x41\x4e\x53\x4c\x41\ +\x54\x49\x4f\x4e\x53\x5d\x0a\x23\x49\x4e\x53\x54\x41\x4c\x4c\x53\ +\x20\x2b\x3d\x20\x61\x73\x73\x69\x73\x74\x61\x6e\x74\x74\x72\x61\ +\x6e\x73\x6c\x61\x74\x69\x6f\x6e\x73\x0a\x0a\x54\x52\x41\x4e\x53\ +\x4c\x41\x54\x49\x4f\x4e\x53\x20\x20\x20\x20\x20\x20\x20\x20\x3d\ +\x20\x61\x73\x73\x69\x73\x74\x61\x6e\x74\x5f\x64\x65\x2e\x74\x73\ +\x20\x5c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x61\x73\x73\x69\x73\x74\x61\x6e\x74\x5f\x66\ +\x72\x2e\x74\x73\x0a\x0a\x0a\x75\x6e\x69\x78\x3a\x21\x63\x6f\x6e\ +\x74\x61\x69\x6e\x73\x28\x51\x54\x5f\x43\x4f\x4e\x46\x49\x47\x2c\ +\x20\x7a\x6c\x69\x62\x29\x3a\x4c\x49\x42\x53\x20\x2b\x3d\x20\x2d\ +\x6c\x7a\x0a\x0a\x0a\x74\x61\x72\x67\x65\x74\x2e\x70\x61\x74\x68\ +\x3d\x24\x24\x5b\x51\x54\x5f\x49\x4e\x53\x54\x41\x4c\x4c\x5f\x42\ +\x49\x4e\x53\x5d\x0a\x49\x4e\x53\x54\x41\x4c\x4c\x53\x20\x2b\x3d\ +\x20\x74\x61\x72\x67\x65\x74\x0a\ +" + +qt_resource_name = b"\ +\x00\x08\ +\x0e\x84\x7f\x43\ +\x00\x65\ +\x00\x78\x00\x61\x00\x6d\x00\x70\x00\x6c\x00\x65\x00\x73\ +\x00\x07\ +\x0c\xe8\x47\xe5\ +\x00\x65\ +\x00\x78\x00\x61\x00\x6d\x00\x70\x00\x6c\x00\x65\ +" + +qt_resource_struct = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ +\x00\x00\x00\x16\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/examples/widgets/richtext/textobject/files/heart.svg b/examples/widgets/richtext/textobject/files/heart.svg new file mode 100644 index 000000000..ba5f050b0 --- /dev/null +++ b/examples/widgets/richtext/textobject/files/heart.svg @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --><svg viewBox="100 200 550 500" height="595.27559pt" id="svg1" inkscape:version="0.40+cvs" sodipodi:docbase="C:\Documents and Settings\Jon Phillips\My Documents\projects\clipart-project\submissions" sodipodi:docname="heart-left-highlight.svg" sodipodi:version="0.32" width="595.27559pt" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"> +<metadata> +<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> +<cc:Work rdf:about=""> +<dc:title>Heart Left-Highlight</dc:title> +<dc:description>This is a normal valentines day heart.</dc:description> +<dc:subject> +<rdf:Bag> +<rdf:li>holiday</rdf:li> +<rdf:li>valentines</rdf:li> +<rdf:li></rdf:li> +<rdf:li>valentine</rdf:li> +<rdf:li>hash(0x8a091c0)</rdf:li> +<rdf:li>hash(0x8a0916c)</rdf:li> +<rdf:li>signs_and_symbols</rdf:li> +<rdf:li>hash(0x8a091f0)</rdf:li> +<rdf:li>day</rdf:li> +</rdf:Bag> +</dc:subject> +<dc:publisher> +<cc:Agent rdf:about="http://www.openclipart.org"> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:publisher> +<dc:creator> +<cc:Agent> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:creator> +<dc:rights> +<cc:Agent> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:rights> +<dc:date></dc:date> +<dc:format>image/svg+xml</dc:format> +<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> +<cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/> +<dc:language>en</dc:language> +</cc:Work> +<cc:License rdf:about="http://web.resource.org/cc/PublicDomain"> +<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/> +<cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/> +<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/> +</cc:License> +</rdf:RDF> +</metadata> +<defs id="defs3"/> +<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:current-layer="layer1" inkscape:cx="549.40674" inkscape:cy="596.00159" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="615" inkscape:window-width="866" inkscape:window-x="88" inkscape:window-y="116" inkscape:zoom="0.35000000" pagecolor="#ffffff" showguides="true"/> +<g id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1"> +<path d="M 263.41570,235.14588 C 197.17570,235.14588 143.41575,288.90587 143.41575,355.14588 C 143.41575,489.90139 279.34890,525.23318 371.97820,658.45392 C 459.55244,526.05056 600.54070,485.59932 600.54070,355.14588 C 600.54070,288.90588 546.78080,235.14587 480.54070,235.14588 C 432.49280,235.14588 391.13910,263.51631 371.97820,304.33338 C 352.81740,263.51630 311.46370,235.14587 263.41570,235.14588 z " id="path7" sodipodi:nodetypes="ccccccc" style="fill:#e60000;fill-opacity:1.0000000;stroke:#000000;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> +<path d="M 265.00000,253.59375 C 207.04033,253.59375 160.00000,300.63407 160.00000,358.59375 C 160.00000,476.50415 278.91857,507.43251 359.96875,624.00000 C 366.52868,614.08205 220.00000,478.47309 220.00000,378.59375 C 220.00000,320.63407 267.04033,273.59375 325.00000,273.59375 C 325.50453,273.59375 325.99718,273.64912 326.50000,273.65625 C 309.22436,261.07286 288.00557,253.59374 265.00000,253.59375 z " id="path220" sodipodi:nodetypes="ccccccc" style="fill:#e6e6e6;fill-opacity:0.64556962;stroke:none;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> +</g> +</svg> diff --git a/examples/widgets/richtext/textobject/textobject.py b/examples/widgets/richtext/textobject/textobject.py new file mode 100755 index 000000000..3e7b75ddc --- /dev/null +++ b/examples/widgets/richtext/textobject/textobject.py @@ -0,0 +1,130 @@ +#!/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/richtext/textobject example from Qt v5.x""" + +from PySide2 import QtCore, QtGui, QtWidgets, QtSvg + + +class SvgTextObject(QtCore.QObject, QtGui.QTextObjectInterface): + + def intrinsicSize(self, doc, posInDocument, format): + renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData).toByteArray()) + size = renderer.defaultSize() + + if size.height() > 25: + size *= 25.0 / size.height() + + return QtCore.QSizeF(size) + + def drawObject(self, painter, rect, doc, posInDocument, format): + renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData).toByteArray()) + renderer.render(painter, rect) + + +class Window(QtWidgets.QWidget): + + SvgTextFormat = QtGui.QTextFormat.UserObject + 1 + + SvgData = 1 + + def __init__(self): + super(Window, self).__init__() + + self.setupGui() + self.setupTextObject() + + self.setWindowTitle(self.tr("Text Object Example")) + + def insertTextObject(self): + fileName = self.fileNameLineEdit.text() + file = QtCore.QFile(fileName) + + if not file.open(QtCore.QIODevice.ReadOnly): + QtWidgets.QMessageBox.warning(self, self.tr("Error Opening File"), + self.tr("Could not open '%1'").arg(fileName)) + + svgData = file.readAll() + + svgCharFormat = QtGui.QTextCharFormat() + svgCharFormat.setObjectType(Window.SvgTextFormat) + svgCharFormat.setProperty(Window.SvgData, svgData) + + cursor = self.textEdit.textCursor() + cursor.insertText(u"\uFFFD", svgCharFormat) + self.textEdit.setTextCursor(cursor) + + def setupTextObject(self): + svgInterface = SvgTextObject(self) + self.textEdit.document().documentLayout().registerHandler(Window.SvgTextFormat, svgInterface) + + def setupGui(self): + fileNameLabel = QtWidgets.QLabel(self.tr("Svg File Name:")) + self.fileNameLineEdit = QtWidgets.QLineEdit() + insertTextObjectButton = QtWidgets.QPushButton(self.tr("Insert Image")) + + self.fileNameLineEdit.setText('./files/heart.svg') + QtCore.QObject.connect(insertTextObjectButton, QtCore.SIGNAL('clicked()'), self.insertTextObject) + + bottomLayout = QtWidgets.QHBoxLayout() + bottomLayout.addWidget(fileNameLabel) + bottomLayout.addWidget(self.fileNameLineEdit) + bottomLayout.addWidget(insertTextObjectButton) + + self.textEdit = QtWidgets.QTextEdit() + + mainLayout = QtWidgets.QVBoxLayout() + mainLayout.addWidget(self.textEdit) + mainLayout.addLayout(bottomLayout) + + self.setLayout(mainLayout) + + +if __name__ == '__main__': + + import sys + + app = QtWidgets.QApplication(sys.argv) + window = Window() + window.show() + sys.exit(app.exec_()) |