aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2022-08-09 11:30:47 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2022-08-12 15:50:44 +0200
commit658f0bffaa7b84c1a1058c94e0175123283cfd81 (patch)
tree2e1abe7c0eb8d311729a6f8fde55b910faaad60b
parenta324390fea8832db6ab806e5939a99f1feaf4796 (diff)
Fix the modelview programming tutorial
Add some documentation examples and snippets to fix most outstanding C++ to Python conversion errors. The rest looks roughly ok and could be improved by further fixing up the snippet conversion. Task-number: PYSIDE-1984 Change-Id: I8c1bdcbc4a07847b2731ef7e2b9ba666cc00ccd6 Reviewed-by: Christian Tismer <tismer@stackless.com> (cherry picked from commit 2d7a4fc710e59d0e766ffa101dba383eff46bb50)
-rw-r--r--sources/pyside6/doc/snippets/qtbase/examples/widgets/itemviews/spinboxdelegate/delegate_0.h.py18
-rw-r--r--sources/pyside6/doc/snippets/qtbase/src/widgets/doc/snippets/stringlistmodel/model_0.h.py24
-rw-r--r--sources/pyside6/doc/tutorials/modelviewprogramming/qlistview-dnd.py174
-rw-r--r--sources/pyside6/doc/tutorials/modelviewprogramming/simplemodel-use.py81
-rw-r--r--sources/pyside6/doc/tutorials/modelviewprogramming/stringlistmodel.py161
-rw-r--r--tools/snippets_translate/override.py39
6 files changed, 496 insertions, 1 deletions
diff --git a/sources/pyside6/doc/snippets/qtbase/examples/widgets/itemviews/spinboxdelegate/delegate_0.h.py b/sources/pyside6/doc/snippets/qtbase/examples/widgets/itemviews/spinboxdelegate/delegate_0.h.py
new file mode 100644
index 000000000..de386a5ac
--- /dev/null
+++ b/sources/pyside6/doc/snippets/qtbase/examples/widgets/itemviews/spinboxdelegate/delegate_0.h.py
@@ -0,0 +1,18 @@
+class SpinBoxDelegate(QStyledItemDelegate):
+ """A delegate that allows the user to change integer values from the model
+ using a spin box widget. """
+
+ def __init__(self, parent=None):
+ ...
+
+ def createEditor(self, parent, option, index):
+ ...
+
+ def setEditorData(self, editor, index):
+ ...
+
+ def setModelData(self, editor, model, index):
+ ...
+
+ def updateEditorGeometry(self, editor, option, index):
+ ...
diff --git a/sources/pyside6/doc/snippets/qtbase/src/widgets/doc/snippets/stringlistmodel/model_0.h.py b/sources/pyside6/doc/snippets/qtbase/src/widgets/doc/snippets/stringlistmodel/model_0.h.py
new file mode 100644
index 000000000..02a02aaf8
--- /dev/null
+++ b/sources/pyside6/doc/snippets/qtbase/src/widgets/doc/snippets/stringlistmodel/model_0.h.py
@@ -0,0 +1,24 @@
+class StringListModel(QAbstractListModel):
+ def __init__(self, strings, parent=None):
+ ...
+
+ def rowCount(self, parent=QModelIndex()):
+ ...
+
+ def data(self, index, role):
+ ...
+
+ def headerData(self, section, orientation, role=Qt.DisplayRole):
+ ...
+
+ def flags(self, index):
+ ...
+
+ def setData(self, index, value, role=Qt.EditRole):
+ ...
+
+ def insertRows(self, position, rows, parent):
+ ...
+
+ def removeRows(self, position, rows, parent):
+ ...
diff --git a/sources/pyside6/doc/tutorials/modelviewprogramming/qlistview-dnd.py b/sources/pyside6/doc/tutorials/modelviewprogramming/qlistview-dnd.py
new file mode 100644
index 000000000..cebc99447
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/modelviewprogramming/qlistview-dnd.py
@@ -0,0 +1,174 @@
+#############################################################################
+##
+## Copyright (C) 2022 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python 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$
+##
+#############################################################################
+
+import sys
+
+from PySide6.QtWidgets import (QAbstractItemView, QApplication, QMainWindow,
+ QListView)
+from PySide6.QtCore import (QByteArray, QDataStream, QIODevice, QMimeData,
+ QModelIndex, QStringListModel, Qt)
+
+
+class DragDropListModel(QStringListModel):
+ """A simple model that uses a QStringList as its data source."""
+
+ def __init__(self, strings, parent=None):
+ super().__init__(strings, parent)
+
+#! [0]
+
+ def canDropMimeData(self, data, action, row, column, parent):
+ if not data.hasFormat("application/vnd.text.list"):
+ return False
+
+ if column > 0:
+ return False
+
+ return True
+#! [0]
+#! [1]
+ def dropMimeData(self, data, action, row, column, parent):
+ if not self.canDropMimeData(data, action, row, column, parent):
+ return False
+
+ if action == Qt.IgnoreAction:
+ return True
+#! [1]
+
+#! [2]
+ begin_row = 0
+
+ if row != -1:
+ begin_row = row
+#! [2] #! [3]
+ elif parent.isValid():
+ begin_row = parent.row()
+#! [3] #! [4]
+ else:
+ begin_row = self.rowCount(QModelIndex())
+#! [4]
+
+#! [5]
+ encoded_data = data.data("application/vnd.text.list")
+ stream = QDataStream(encoded_data, QIODevice.ReadOnly)
+ new_items = []
+ while not stream.atEnd():
+ new_items.append(stream.readQString())
+#! [5]
+
+#! [6]
+ self.insertRows(begin_row, len(new_items), QModelIndex())
+ for text in new_items:
+ idx = self.index(begin_row, 0, QModelIndex())
+ self.setData(idx, text)
+ begin_row += 1
+
+ return True
+#! [6]
+
+#! [7]
+ def flags(self, index):
+ default_flags = super().flags(index)
+ if index.isValid():
+ return Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled | default_flags
+ return Qt.ItemIsDropEnabled | default_flags
+#! [7]
+
+#! [8]
+ def mimeData(self, indexes):
+ mime_data = QMimeData()
+ encoded_data = QByteArray()
+ stream = QDataStream(encoded_data, QIODevice.WriteOnly)
+ for index in indexes:
+ if index.isValid():
+ text = self.data(index, Qt.DisplayRole)
+ stream.writeQString(text)
+
+ mime_data.setData("application/vnd.text.list", encoded_data)
+ return mime_data
+#! [8]
+
+#! [9]
+ def mimeTypes(self):
+ return ["application/vnd.text.list"]
+#! [9]
+
+#! [10]
+ def supportedDropActions(self):
+ return Qt.CopyAction | Qt.MoveAction
+#! [10]
+
+
+class MainWindow(QMainWindow):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ file_menu = self.menuBar().addMenu("&File")
+ quit_action = file_menu.addAction("E&xit")
+ quit_action.setShortcut("Ctrl+Q")
+
+#! [mainwindow0]
+ self._list_view = QListView(self)
+ self._list_view.setSelectionMode(QAbstractItemView.ExtendedSelection)
+ self._list_view.setDragEnabled(True)
+ self._list_view.setAcceptDrops(True)
+ self._list_view.setDropIndicatorShown(True)
+#! [mainwindow0]
+
+ quit_action.triggered.connect(self.close)
+
+ self.setup_list_items()
+
+ self.setCentralWidget(self._list_view)
+ self.setWindowTitle("List View")
+
+ def setup_list_items(self):
+ items = ["Oak", "Fir", "Pine", "Birch", "Hazel", "Redwood", "Sycamore",
+ "Chestnut", "Mahogany"]
+ model = DragDropListModel(items, self)
+ self._list_view.setModel(model)
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+ window = MainWindow()
+ window.show()
+ sys.exit(app.exec())
diff --git a/sources/pyside6/doc/tutorials/modelviewprogramming/simplemodel-use.py b/sources/pyside6/doc/tutorials/modelviewprogramming/simplemodel-use.py
new file mode 100644
index 000000000..503834aaf
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/modelviewprogramming/simplemodel-use.py
@@ -0,0 +1,81 @@
+#############################################################################
+##
+## Copyright (C) 2022 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python 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$
+##
+#############################################################################
+
+import sys
+
+from PySide6.QtWidgets import (QApplication, QFileSystemModel, QLabel,
+ QVBoxLayout, QWidget)
+from PySide6.QtGui import QPalette
+from PySide6.QtCore import QDir, Qt
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+
+ window = QWidget()
+ layout = QVBoxLayout(window)
+ title = QLabel("Some items from the directory model", window)
+ title.setBackgroundRole(QPalette.Base)
+ title.setMargin(8)
+ layout.addWidget(title)
+
+#! [0]
+ model = QFileSystemModel()
+ model.setRootPath(QDir.currentPath())
+
+ def on_directory_loaded(directory):
+ parent_index = model.index(directory)
+ num_rows = model.rowCount(parent_index)
+#! [1]
+ for row in range(num_rows):
+ index = model.index(row, 0, parent_index)
+#! [1]
+#! [2]
+ text = model.data(index, Qt.DisplayRole)
+#! [2]
+ label = QLabel(text, window)
+ layout.addWidget(label)
+
+ model.directoryLoaded.connect(on_directory_loaded)
+#! [0]
+
+ window.setWindowTitle("A simple model example")
+ window.show()
+ sys.exit(app.exec())
diff --git a/sources/pyside6/doc/tutorials/modelviewprogramming/stringlistmodel.py b/sources/pyside6/doc/tutorials/modelviewprogramming/stringlistmodel.py
new file mode 100644
index 000000000..9d3631f62
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/modelviewprogramming/stringlistmodel.py
@@ -0,0 +1,161 @@
+#############################################################################
+##
+## Copyright (C) 2022 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python 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$
+##
+#############################################################################
+
+import sys
+
+from PySide6.QtWidgets import (QApplication, QListView)
+from PySide6.QtCore import QAbstractListModel, QStringListModel, QModelIndex, Qt
+
+
+#! [0]
+class StringListModel(QAbstractListModel):
+ def __init__(self, strings, parent=None):
+ super().__init__(parent)
+ self._strings = strings
+
+#! [0]
+ def rowCount(self, parent=QModelIndex()):
+ """Returns the number of items in the string list as the number of rows
+ in the model."""
+ return len(self._strings)
+#! [0]
+
+#! [1]
+ def data(self, index, role):
+ """Returns an appropriate value for the requested data.
+ If the view requests an invalid index, an invalid variant is returned.
+ Any valid index that corresponds to a string in the list causes that
+ string to be returned."""
+ row = index.row()
+ if not index.isValid() or row >= len(self._strings):
+ return None
+ if role != Qt.DisplayRole and role != Qt.EditRole:
+ return None
+ return self._strings[row]
+#! [1]
+
+#! [2]
+ def headerData(self, section, orientation, role=Qt.DisplayRole):
+ """Returns the appropriate header string depending on the orientation of
+ the header and the section. If anything other than the display role is
+ requested, we return an invalid variant."""
+ if role != Qt.DisplayRole:
+ return None
+ if orientation == Qt.Horizontal:
+ return f"Column {section}"
+ return f"Row {section}"
+#! [2]
+
+#! [3]
+ def flags(self, index):
+ """Returns an appropriate value for the item's flags. Valid items are
+ enabled, selectable, and editable."""
+
+ if not index.isValid():
+ return Qt.ItemIsEnabled
+ return super().flags(index) | Qt.ItemIsEditable
+#! [3]
+
+ #! [4]
+ def setData(self, index, value, role=Qt.EditRole):
+ """Changes an item in the string list, but only if the following conditions
+ are met:
+
+ # The index supplied is valid.
+ # The index corresponds to an item to be shown in a view.
+ # The role associated with editing text is specified.
+
+ The dataChanged() signal is emitted if the item is changed."""
+
+ if index.isValid() and role == Qt.EditRole:
+ self._strings[index.row()] = value
+ self.dataChanged.emit(index, index, {role})
+ return True
+#! [4] #! [5]
+ return False
+#! [5]
+
+#! [6]
+ def insertRows(self, position, rows, parent):
+ """Inserts a number of rows into the model at the specified position."""
+ self.beginInsertRows(QModelIndex(), position, position + rows - 1)
+ for row in range(rows):
+ self._strings.insert(position, "")
+ self.endInsertRows()
+ return True
+#! [6] #! [7]
+#! [7]
+
+#! [8]
+ def removeRows(self, position, rows, parent):
+ """Removes a number of rows from the model at the specified position."""
+ self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
+ for row in range(rows):
+ del self._strings[position]
+ self.endRemoveRows()
+ return True
+#! [8] #! [9]
+#! [9]
+
+
+#! [main0]
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+
+#! [main1]
+ numbers = ["One", "Two", "Three", "Four", "Five"]
+ model = StringListModel(numbers)
+#! [main0] #! [main1] #! [main2] #! [main3]
+ view = QListView()
+#! [main2]
+ view.setWindowTitle("View onto a string list model")
+#! [main4]
+ view.setModel(model)
+#! [main3] #! [main4]
+
+ model.insertRows(5, 7, QModelIndex())
+ for row in range(5, 12):
+ index = model.index(row, 0, QModelIndex())
+ model.setData(index, f"{row+1}")
+
+#! [main5]
+ view.show()
+ sys.exit(app.exec())
+#! [main5]
diff --git a/tools/snippets_translate/override.py b/tools/snippets_translate/override.py
index f0f76fd2b..c9d5d149f 100644
--- a/tools/snippets_translate/override.py
+++ b/tools/snippets_translate/override.py
@@ -41,6 +41,7 @@ from pathlib import Path
ROOT_PATH = Path(__file__).parents[2]
EXAMPLES_PATH = ROOT_PATH / "examples"
+TUTORIAL_EXAMPLES_PATH = ROOT_PATH / "sources" / "pyside6" / "doc" / "tutorials"
_PYTHON_EXAMPLE_SNIPPET_MAPPING = {
@@ -76,7 +77,9 @@ _PYTHON_EXAMPLE_SNIPPET_MAPPING = {
(EXAMPLES_PATH / "widgets" / "tutorials" / "modelview" / "7_selections.py", "1"),
("qtbase/examples/widgets/tutorials/modelview/7_selections/mainwindow.cpp",
"quoting modelview_b"):
- (EXAMPLES_PATH / "widgets" / "tutorials" / "modelview" / "7_selections.py", "2")
+ (EXAMPLES_PATH / "widgets" / "tutorials" / "modelview" / "7_selections.py", "2"),
+ ("qtbase/src/widgets/doc/snippets/qlistview-dnd/mainwindow.cpp.cpp", "0"):
+ (TUTORIAL_EXAMPLES_PATH / "modelviewprogramming" / "qlistview-dnd.py", "mainwindow0")
}
@@ -87,6 +90,40 @@ def python_example_snippet_mapping():
global _python_example_snippet_mapping
if not _python_example_snippet_mapping:
result = _PYTHON_EXAMPLE_SNIPPET_MAPPING
+
+ qt_path = "qtbase/src/widgets/doc/snippets/simplemodel-use/main.cpp"
+ pyside_path = TUTORIAL_EXAMPLES_PATH / "modelviewprogramming" / "stringlistmodel.py"
+ for i in range(3):
+ snippet_id = str(i)
+ result[(qt_path, snippet_id)] = pyside_path, snippet_id
+
+ qt_path = "qtbase/src/widgets/doc/snippets/stringlistmodel/main.cpp"
+ pyside_path = TUTORIAL_EXAMPLES_PATH / "modelviewprogramming" / "stringlistmodel.py"
+ for i in range(6):
+ snippet_id = str(i)
+ result[(qt_path, snippet_id)] = pyside_path, f"main{snippet_id}"
+
+ qt_path = "qtbase/examples/widgets/itemviews/spinboxdelegate/delegate.cpp"
+ pyside_path = (EXAMPLES_PATH / "widgets" / "itemviews" / "spinboxdelegate"
+ / "spinboxdelegate.py")
+ for i in range(5):
+ snippet_id = str(i)
+ result[(qt_path, snippet_id)] = pyside_path, snippet_id
+
+ qt_path = "qtbase/src/widgets/doc/snippets/stringlistmodel/model.cpp"
+ pyside_path = (TUTORIAL_EXAMPLES_PATH / "modelviewprogramming"
+ / "stringlistmodel.py")
+ for i in range(10):
+ snippet_id = str(i)
+ result[(qt_path, snippet_id)] = pyside_path, snippet_id
+
+ qt_path = "qtbase/src/widgets/doc/snippets/qlistview-dnd/model.cpp"
+ pyside_path = (TUTORIAL_EXAMPLES_PATH / "modelviewprogramming"
+ / "qlistview-dnd.py")
+ for i in range(11):
+ snippet_id = str(i)
+ result[(qt_path, snippet_id)] = pyside_path, snippet_id
+
_python_example_snippet_mapping = result
return _python_example_snippet_mapping