aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorDennis Oberst <dennis.oberst@qt.io>2023-01-26 12:35:32 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-03-30 12:09:44 +0000
commitc65128387e82b997efa9840943d1bf1cc0ca5ec3 (patch)
tree179bdae33ebbb93146be1a98bfc123f6e5550385 /sources
parent7c5fe1f178a62a54e88d26f945004161cfbc7145 (diff)
docs: add extendedexplorer tutorial
Extended the filesystemexplorer example with interactive scheme switching and wrote a tutorial about it. This tutorial uses Qml features from 6.5. The tutorial is intended to provide users with an overview of how to create modern applications with PySide/QtQuick Task-number: QTBUG-108289 Task-number: PYSIDE-2224 Change-Id: I114824680156d0eacbbfe3363c67d1d5784a2219 Reviewed-by: Adrian Herrmann <adrian.herrmann@qt.io> Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> (cherry picked from commit 3813faa6dac1377e390c9b89fff236bbc0bf8bbb) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/Main.qml203
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/app.qrc15
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons.qrc14
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/folder_closed.svg38
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/folder_open.svg38
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/generic_file.svg38
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/globe.svg38
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/info_sign.svg38
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/leaf.svg7
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/light_bulb.svg43
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/qt_logo.svg26
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/read.svg38
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/resize.svg6
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/About.qml59
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ColorScheme.qml118
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/FileSystemView.qml99
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Icon.qml44
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenu.qml42
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenuBar.qml135
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ResizeButton.qml23
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Sidebar.qml124
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/WindowDragHandler.qml16
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qmldir11
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.md210
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.py70
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.pyproject29
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/resources/Colors.qml22
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/resources/colorscheme.pngbin0 -> 27675 bytes
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.gifbin0 -> 2082470 bytes
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.webpbin0 -> 42602 bytes
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/scheme_manager.py99
-rw-r--r--sources/pyside6/doc/tutorials/extendedexplorer/schemes.json82
-rw-r--r--sources/pyside6/doc/tutorials/index.rst7
33 files changed, 1732 insertions, 0 deletions
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/Main.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/Main.qml
new file mode 100644
index 000000000..b699720dd
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/Main.qml
@@ -0,0 +1,203 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls.Basic
+import QtQuick.Layouts
+import FileSystemModule
+
+ApplicationWindow {
+ id: root
+ width: 1100
+ height: 600
+ visible: true
+ flags: Qt.Window | Qt.FramelessWindowHint
+ title: qsTr("Qt Quick Controls - File System Explorer")
+
+ property string currentFilePath: ""
+ property bool expandPath: false
+
+ menuBar: MyMenuBar {
+ rootWindow: root
+
+ infoText: currentFilePath
+ ? (expandPath ? currentFilePath
+ : currentFilePath.substring(currentFilePath.lastIndexOf("/") + 1, currentFilePath.length))
+ : "File System Explorer"
+
+ MyMenu {
+ title: qsTr("File")
+
+ Action {
+ text: qsTr("Increase Font")
+ shortcut: "Ctrl++"
+ onTriggered: textArea.font.pixelSize += 1
+ }
+ Action {
+ text: qsTr("Decrease Font")
+ shortcut: "Ctrl+-"
+ onTriggered: textArea.font.pixelSize -= 1
+ }
+ Action {
+ text: expandPath ? qsTr("Toggle Short Path") : qsTr("Toggle Expand Path")
+ enabled: currentFilePath
+ onTriggered: expandPath = !expandPath
+ }
+ Action {
+ text: qsTr("Exit")
+ onTriggered: Qt.exit(0)
+ }
+ }
+
+ MyMenu {
+ title: qsTr("Edit")
+
+ Action {
+ text: qsTr("Cut")
+ shortcut: StandardKey.Cut
+ enabled: textArea.selectedText.length > 0
+ onTriggered: textArea.cut()
+ }
+ Action {
+ text: qsTr("Copy")
+ shortcut: StandardKey.Copy
+ enabled: textArea.selectedText.length > 0
+ onTriggered: textArea.copy()
+ }
+ Action {
+ text: qsTr("Paste")
+ shortcut: StandardKey.Paste
+ enabled: textArea.canPaste
+ onTriggered: textArea.paste()
+ }
+ Action {
+ text: qsTr("Select All")
+ shortcut: StandardKey.SelectAll
+ enabled: textArea.length > 0
+ onTriggered: textArea.selectAll()
+ }
+ Action {
+ text: qsTr("Undo")
+ shortcut: StandardKey.Undo
+ enabled: textArea.canUndo
+ onTriggered: textArea.undo()
+ }
+ }
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ color: Colors.background
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: 0
+
+ // Stores the buttons that navigate the application.
+ Sidebar {
+ id: sidebar
+ z: 2
+ rootWindow: root
+
+ Layout.preferredWidth: 60
+ Layout.fillHeight: true
+ }
+
+ // Allows resizing parts of the UI.
+ SplitView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ handle: Rectangle {
+ implicitWidth: 10
+ color: SplitHandle.pressed ? Colors.color2 : Colors.background
+ border.color: Colors.color2
+ opacity: SplitHandle.hovered || SplitHandle.pressed ? 1.0 : 0.0
+
+ Behavior on opacity {
+ OpacityAnimator {
+ duration: 900
+ }
+ }
+ }
+
+ // We use an inline component to make a reusable TextArea component.
+ // This is convenient when the component is only used in one file.
+ component MyTextArea: TextArea {
+ antialiasing: true
+ color: Colors.textFile
+ selectedTextColor: Colors.textFile
+ selectionColor: Colors.selection
+ renderType: Text.QtRendering
+ textFormat: TextEdit.PlainText
+
+ background: null
+ }
+
+ Rectangle {
+ z: 1
+ color: Colors.surface1
+
+ SplitView.preferredWidth: 250
+ SplitView.fillHeight: true
+
+ StackLayout {
+ currentIndex: sidebar.currentTabIndex > 1 ? 1 : sidebar.currentTabIndex
+
+ anchors.fill: parent
+
+ // Shows the help text.
+ MyTextArea {
+ readOnly: true
+ text: qsTr("This example shows how to use and visualize the file system.\n\n"
+ + "Customized Qt Quick Components have been used to achieve this look.\n\n"
+ + "You can edit the files but they won't be changed on the file system.\n\n"
+ + "Click on the folder icon to the left to get started.")
+ wrapMode: TextArea.Wrap
+ }
+
+ // Shows the files on the file system.
+ FileSystemView {
+ id: fileSystemView
+ color: Colors.surface1
+
+ onFileClicked: (path) => root.currentFilePath = path
+ }
+ }
+ }
+
+ // The ScrollView that contains the TextArea which shows the file's content.
+ StackLayout {
+ currentIndex: sidebar.currentTabIndex > 1 ? 1 : 0
+
+ SplitView.fillWidth: true
+ SplitView.fillHeight: true
+ // TextArea is the first element inside the stack
+ ScrollView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ leftPadding: 20
+ topPadding: 20
+ bottomPadding: 20
+
+ clip: true
+
+ property alias textArea: textArea
+
+ MyTextArea {
+ id: textArea
+ text: FileSystemModel.readFile(root.currentFilePath)
+ }
+ }
+ // The ColorScheme is the second element in the stack
+ ColorScheme {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+ ResizeButton {}
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/app.qrc b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/app.qrc
new file mode 100644
index 000000000..7303ced8f
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/app.qrc
@@ -0,0 +1,15 @@
+<RCC>
+ <qresource prefix="/qt/qml/FileSystemModule">
+ <file>qmldir</file>
+ <file>Main.qml</file>
+ <file>qml/About.qml</file>
+ <file>qml/ColorScheme.qml</file>
+ <file>qml/FileSystemView.qml</file>
+ <file>qml/Icon.qml</file>
+ <file>qml/MyMenu.qml</file>
+ <file>qml/MyMenuBar.qml</file>
+ <file>qml/ResizeButton.qml</file>
+ <file>qml/Sidebar.qml</file>
+ <file>qml/WindowDragHandler.qml</file>
+ </qresource>
+</RCC>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons.qrc b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons.qrc
new file mode 100644
index 000000000..61323cef1
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons.qrc
@@ -0,0 +1,14 @@
+<RCC>
+ <qresource>
+ <file>icons/folder_closed.svg</file>
+ <file>icons/folder_open.svg</file>
+ <file>icons/generic_file.svg</file>
+ <file>icons/globe.svg</file>
+ <file>icons/info_sign.svg</file>
+ <file>icons/light_bulb.svg</file>
+ <file>icons/qt_logo.svg</file>
+ <file>icons/read.svg</file>
+ <file>icons/resize.svg</file>
+ <file>icons/leaf.svg</file>
+ </qresource>
+</RCC>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/folder_closed.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/folder_closed.svg
new file mode 100644
index 000000000..36f119c96
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/folder_closed.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ viewBox="-10 0 1792 1792"
+ id="svg51"
+ sodipodi:docname="folder_closed.svg"
+ width="1792"
+ height="1792"
+ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs55" />
+ <sodipodi:namedview
+ id="namedview53"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ showgrid="false"
+ inkscape:zoom="0.45033482"
+ inkscape:cx="842.70632"
+ inkscape:cy="896"
+ inkscape:window-width="1846"
+ inkscape:window-height="1016"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg51" />
+ <path
+ fill="currentColor"
+ d="m 1718,672 v 704 q 0,92 -66,158 -66,66 -158,66 H 278 q -92,0 -158,-66 -66,-66 -66,-158 V 416 q 0,-92 66,-158 66,-66 158,-66 h 320 q 92,0 158,66 66,66 66,158 v 32 h 672 q 92,0 158,66 66,66 66,158 z"
+ id="path49" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/folder_open.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/folder_open.svg
new file mode 100644
index 000000000..daa55a7a1
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/folder_open.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ viewBox="-10 0 1792 1792"
+ id="svg139"
+ sodipodi:docname="folder_open.svg"
+ width="1792"
+ height="1792"
+ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs143" />
+ <sodipodi:namedview
+ id="namedview141"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ showgrid="false"
+ inkscape:zoom="0.24358259"
+ inkscape:cx="149.84651"
+ inkscape:cy="1098.1901"
+ inkscape:window-width="1846"
+ inkscape:window-height="1016"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg139" />
+ <path
+ fill="currentColor"
+ d="M 1590,1376 V 672 q 0,-40 -28,-68 -28,-28 -68,-28 H 790 q -40,0 -68,-28 -28,-28 -28,-68 v -64 q 0,-40 -28,-68 -28,-28 -68,-28 H 278 q -40,0 -68,28 -28,28 -28,68 v 960 q 0,40 28,68 28,28 68,28 h 1216 q 40,0 68,-28 28,-28 28,-68 z m 128,-704 v 704 q 0,92 -66,158 -66,66 -158,66 H 278 q -92,0 -158,-66 -66,-66 -66,-158 V 416 q 0,-92 66,-158 66,-66 158,-66 h 320 q 92,0 158,66 66,66 66,158 v 32 h 672 q 92,0 158,66 66,66 66,158 z"
+ id="path137" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/generic_file.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/generic_file.svg
new file mode 100644
index 000000000..9c855676e
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/generic_file.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ viewBox="-10 0 1792 1792"
+ id="svg147"
+ sodipodi:docname="generic_file.svg"
+ width="1792"
+ height="1792"
+ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs151" />
+ <sodipodi:namedview
+ id="namedview149"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ showgrid="false"
+ inkscape:zoom="0.12179129"
+ inkscape:cx="-578.85911"
+ inkscape:cy="1687.3127"
+ inkscape:window-width="1846"
+ inkscape:window-height="1016"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg147" />
+ <path
+ fill="currentColor"
+ d="m 1586,476 q 14,14 28,36 H 1142 V 40 q 22,14 36,28 z m -476,164 h 544 v 1056 q 0,40 -28,68 -28,28 -68,28 H 214 q -40,0 -68,-28 -28,-28 -28,-68 V 96 Q 118,56 146,28 174,0 214,0 h 800 v 544 q 0,40 28,68 28,28 68,28 z m 160,736 v -64 q 0,-14 -9,-23 -9,-9 -23,-9 H 534 q -14,0 -23,9 -9,9 -9,23 v 64 q 0,14 9,23 9,9 23,9 h 704 q 14,0 23,-9 9,-9 9,-23 z m 0,-256 v -64 q 0,-14 -9,-23 -9,-9 -23,-9 H 534 q -14,0 -23,9 -9,9 -9,23 v 64 q 0,14 9,23 9,9 23,9 h 704 q 14,0 23,-9 9,-9 9,-23 z m 0,-256 v -64 q 0,-14 -9,-23 -9,-9 -23,-9 H 534 q -14,0 -23,9 -9,9 -9,23 v 64 q 0,14 9,23 9,9 23,9 h 704 q 14,0 23,-9 9,-9 9,-23 z"
+ id="path145" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/globe.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/globe.svg
new file mode 100644
index 000000000..081433813
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/globe.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ viewBox="-10 0 1792 1792"
+ id="svg155"
+ sodipodi:docname="globe.svg"
+ width="1792"
+ height="1792"
+ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs159" />
+ <sodipodi:namedview
+ id="namedview157"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ showgrid="false"
+ inkscape:zoom="0.12179129"
+ inkscape:cx="504.9622"
+ inkscape:cy="1720.1558"
+ inkscape:window-width="1846"
+ inkscape:window-height="1016"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg155" />
+ <path
+ fill="currentColor"
+ d="m 886,128 q 209,0 385.5,103 176.5,103 279.5,279.5 103,176.5 103,385.5 0,209 -103,385.5 Q 1448,1458 1271.5,1561 1095,1664 886,1664 677,1664 500.5,1561 324,1458 221,1281.5 118,1105 118,896 118,687 221,510.5 324,334 500.5,231 677,128 886,128 Z m 274,521 q -2,1 -9.5,9.5 -7.5,8.5 -13.5,9.5 2,0 4.5,-5 2.5,-5 5,-11 2.5,-6 3.5,-7 6,-7 22,-15 14,-6 52,-12 34,-8 51,11 -2,-2 9.5,-13 11.5,-11 14.5,-12 3,-2 15,-4.5 12,-2.5 15,-7.5 l 2,-22 q -12,1 -17.5,-7 -5.5,-8 -6.5,-21 0,2 -6,8 0,-7 -4.5,-8 -4.5,-1 -11.5,1 -7,2 -9,1 -10,-3 -15,-7.5 -5,-4.5 -8,-16.5 -3,-12 -4,-15 -2,-5 -9.5,-10.5 -7.5,-5.5 -9.5,-10.5 -1,-2 -2.5,-5.5 -1.5,-3.5 -3,-6.5 -1.5,-3 -4,-5.5 -2.5,-2.5 -5.5,-2.5 -3,0 -7,5 -4,5 -7.5,10 -3.5,5 -4.5,5 -3,-2 -6,-1.5 -3,0.5 -4.5,1 -1.5,0.5 -4.5,3 -3,2.5 -5,3.5 -3,2 -8.5,3 -5.5,1 -8.5,2 15,-5 -1,-11 -10,-4 -16,-3 9,-4 7.5,-12 -1.5,-8 -8.5,-14 h 5 q -1,-4 -8.5,-8.5 -7.5,-4.5 -17.5,-8.5 -10,-4 -13,-6 -8,-5 -34,-9.5 -26,-4.5 -33,-0.5 -5,6 -4.5,10.5 0.5,4.5 4,14 3.5,9.5 3.5,12.5 1,6 -5.5,13 -6.5,7 -6.5,12 0,7 14,15.5 14,8.5 10,21.5 -3,8 -16,16 -13,8 -16,12 -5,8 -1.5,18.5 3.5,10.5 10.5,16.5 2,2 1.5,4 -0.5,2 -3.5,4.5 -3,2.5 -5.5,4 -2.5,1.5 -6.5,3.5 l -3,2 q -11,5 -20.5,-6 -9.5,-11 -13.5,-26 -7,-25 -16,-30 -23,-8 -29,1 -5,-13 -41,-26 -25,-9 -58,-4 6,-1 0,-15 -7,-15 -19,-12 3,-6 4,-17.5 1,-11.5 1,-13.5 3,-13 12,-23 1,-1 7,-8.5 6,-7.5 9.5,-13.5 3.5,-6 0.5,-6 35,4 50,-11 5,-5 11.5,-17 6.5,-12 10.5,-17 9,-6 14,-5.5 5,0.5 14.5,5.5 9.5,5 14.5,5 14,1 15.5,-11 1.5,-12 -7.5,-20 12,1 3,-17 -5,-7 -8,-9 -12,-4 -27,5 -8,4 2,8 -1,-1 -9.5,10.5 Q 927,340 919,346 q -8,6 -16,-5 -1,-1 -5.5,-13.5 Q 893,315 888,314 q -8,0 -16,15 3,-8 -11,-15 -14,-7 -24,-8 19,-12 -8,-27 -7,-4 -20.5,-5 -13.5,-1 -19.5,4 -5,7 -5.5,11.5 -0.5,4.5 5,8 5.5,3.5 10.5,5.5 5,2 11.5,4 6.5,2 8.5,3 14,10 8,14 -2,1 -8.5,3.5 -6.5,2.5 -11.5,4.5 -5,2 -6,4 -3,4 0,14 3,10 -2,14 -5,-5 -9,-17.5 -4,-12.5 -7,-16.5 7,9 -25,6 l -10,-1 q -4,0 -16,2 -12,2 -20.5,1 -8.5,-1 -13.5,-8 -4,-8 0,-20 1,-4 4,-2 -4,-3 -11,-9.5 -7,-6.5 -10,-8.5 -46,15 -94,41 6,1 12,-1 5,-2 13,-6.5 8,-4.5 10,-5.5 34,-14 42,-7 l 5,-5 q 14,16 20,25 -7,-4 -30,-1 -20,6 -22,12 7,12 5,18 -4,-3 -11.5,-10 -7.5,-7 -14.5,-11 -7,-4 -15,-5 -16,0 -22,1 -146,80 -235,222 7,7 12,8 4,1 5,9 1,8 2.5,11 1.5,3 11.5,-3 9,8 3,19 1,-1 44,27 19,17 21,21 3,11 -10,18 -1,-2 -9,-9 -8,-7 -9,-4 -3,5 0.5,18.5 3.5,13.5 10.5,12.5 -7,0 -9.5,16 -2.5,16 -2.5,35.5 0,19.5 -1,23.5 l 2,1 q -3,12 5.5,34.5 8.5,22.5 21.5,19.5 -13,3 20,43 6,8 8,9 3,2 12,7.5 9,5.5 15,10 6,4.5 10,10.5 4,5 10,22.5 6,17.5 14,23.5 -2,6 9.5,20 11.5,14 10.5,23 -1,0 -2.5,1 -1.5,1 -2.5,1 3,7 15.5,14 12.5,7 15.5,13 1,3 2,10 1,7 3,11 2,4 8,2 2,-20 -24,-62 -15,-25 -17,-29 -3,-5 -5.5,-15.5 Q 541,919 539,915 q 2,0 6,1.5 4,1.5 8.5,3.5 4.5,2 7.5,4 3,2 2,3 -3,7 2,17.5 5,10.5 12,18.5 7,8 17,19 10,11 12,13 6,6 14,19.5 8,13.5 0,13.5 9,0 20,10 11,10 17,20 5,8 8,26 3,18 5,24 2,7 8.5,13.5 6.5,6.5 12.5,9.5 l 16,8 q 0,0 13,7 5,2 18.5,10.5 13.5,8.5 21.5,11.5 10,4 16,4 6,0 14.5,-2.5 8.5,-2.5 13.5,-3.5 15,-2 29,15 14,17 21,21 36,19 55,11 -2,1 0.5,7.5 2.5,6.5 8,15.5 5.5,9 9,14.5 3.5,5.5 5.5,8.5 5,6 18,15 13,9 18,15 6,-4 7,-9 -3,8 7,20 10,12 18,10 14,-3 14,-32 -31,15 -49,-18 0,-1 -2.5,-5.5 -2.5,-4.5 -4,-8.5 -1.5,-4 -2.5,-8.5 -1,-4.5 0,-7.5 1,-3 5,-3 9,0 10,-3.5 1,-3.5 -2,-12.5 -3,-9 -4,-13 -1,-8 -11,-20 -10,-12 -12,-15 -5,9 -16,8 -11,-1 -16,-9 0,1 -1.5,5.5 -1.5,4.5 -1.5,6.5 -13,0 -15,-1 1,-3 2.5,-17.5 1.5,-14.5 3.5,-22.5 1,-4 5.5,-12 4.5,-8 7.5,-14.5 3,-6.5 4,-12.5 1,-6 -4.5,-9.5 -5.5,-3.5 -17.5,-2.5 -19,1 -26,20 -1,3 -3,10.5 -2,7.5 -5,11.5 -3,4 -9,7 -7,3 -24,2 -17,-1 -24,-5 -13,-8 -22.5,-29 -9.5,-21 -9.5,-37 0,-10 2.5,-26.5 2.5,-16.5 3,-25 0.5,-8.5 -5.5,-24.5 3,-2 9,-9.5 6,-7.5 10,-10.5 2,-1 4.5,-1.5 2.5,-0.5 4.5,0 2,0.5 4,-1.5 2,-2 3,-6 -1,-1 -4,-3 -3,-3 -4,-3 7,3 28.5,-1.5 21.5,-4.5 27.5,1.5 15,11 22,-2 0,-1 -2.5,-9.5 Q 870,931 872,926 q 5,27 29,9 3,3 15.5,5 12.5,2 17.5,5 3,2 7,5.5 4,3.5 5.5,4.5 1.5,1 5,-0.5 3.5,-1.5 8.5,-6.5 10,14 12,24 11,40 19,44 7,3 11,2 4,-1 4.5,-9.5 0.5,-8.5 0,-14 Q 1006,989 1005,982 l -1,-8 v -18 l -1,-8 q -15,-3 -18.5,-12 -3.5,-9 1.5,-18.5 5,-9.5 15,-18.5 1,-1 8,-3.5 7,-2.5 15.5,-6.5 8.5,-4 12.5,-8 21,-19 15,-35 7,0 11,-9 -1,0 -5,-3 -4,-3 -7.5,-5 -3.5,-2 -4.5,-2 9,-5 2,-16 5,-3 7.5,-11 2.5,-8 7.5,-10 9,12 21,2 7,-8 1,-16 5,-7 20.5,-10.5 15.5,-3.5 18.5,-9.5 7,2 8,-2 1,-4 1,-12 0,-8 3,-12 4,-5 15,-9 11,-4 13,-5 l 17,-11 q 3,-4 0,-4 18,2 31,-11 10,-11 -6,-20 3,-6 -3,-9.5 -6,-3.5 -15,-5.5 3,-1 11.5,-0.5 8.5,0.5 10.5,-1.5 15,-10 -7,-16 -17,-5 -43,12 z m -163,877 q 206,-36 351,-189 -3,-3 -12.5,-4.5 -9.5,-1.5 -12.5,-3.5 -18,-7 -24,-8 1,-7 -2.5,-13 -3.5,-6 -8,-9 -4.5,-3 -12.5,-8 -8,-5 -11,-7 -2,-2 -7,-6 -5,-4 -7,-5.5 -2,-1.5 -7.5,-4.5 -5.5,-3 -8.5,-2 -3,1 -10,1 l -3,1 q -3,1 -5.5,2.5 -2.5,1.5 -5.5,3 -3,1.5 -4,3 -1,1.5 0,2.5 -21,-17 -36,-22 -5,-1 -11,-5.5 -6,-4.5 -10.5,-7 -4.5,-2.5 -10,-1.5 -5.5,1 -11.5,7 -5,5 -6,15 -1,10 -2,13 -7,-5 0,-17.5 7,-12.5 2,-18.5 -3,-6 -10.5,-4.5 -7.5,1.5 -12,4.5 -4.5,3 -11.5,8.5 -7,5.5 -9,6.5 -2,1 -8.5,5.5 -6.5,4.5 -8.5,7.5 -3,4 -6,12 -3,8 -5,11 -2,-4 -11.5,-6.5 -9.5,-2.5 -9.5,-5.5 2,10 4,35 2,25 5,38 7,31 -12,48 -27,25 -29,40 -4,22 12,26 0,7 -8,20.5 -8,13.5 -7,21.5 0,6 2,16 z"
+ id="path153" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/info_sign.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/info_sign.svg
new file mode 100644
index 000000000..517f76360
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/info_sign.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ viewBox="-10 0 1792 1792"
+ id="svg163"
+ sodipodi:docname="info_sign.svg"
+ width="1792"
+ height="1792"
+ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs167" />
+ <sodipodi:namedview
+ id="namedview165"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ showgrid="false"
+ inkscape:zoom="0.48716518"
+ inkscape:cx="72.870561"
+ inkscape:cy="896"
+ inkscape:window-width="1846"
+ inkscape:window-height="1016"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg163" />
+ <path
+ fill="currentColor"
+ d="m 1142,1376 v -160 q 0,-14 -9,-23 -9,-9 -23,-9 h -96 V 672 q 0,-14 -9,-23 -9,-9 -23,-9 H 662 q -14,0 -23,9 -9,9 -9,23 v 160 q 0,14 9,23 9,9 23,9 h 96 v 320 h -96 q -14,0 -23,9 -9,9 -9,23 v 160 q 0,14 9,23 9,9 23,9 h 448 q 14,0 23,-9 9,-9 9,-23 z M 1014,480 V 320 q 0,-14 -9,-23 -9,-9 -23,-9 H 790 q -14,0 -23,9 -9,9 -9,23 v 160 q 0,14 9,23 9,9 23,9 h 192 q 14,0 23,-9 9,-9 9,-23 z m 640,416 q 0,209 -103,385.5 Q 1448,1458 1271.5,1561 1095,1664 886,1664 677,1664 500.5,1561 324,1458 221,1281.5 118,1105 118,896 118,687 221,510.5 324,334 500.5,231 677,128 886,128 1095,128 1271.5,231 1448,334 1551,510.5 1654,687 1654,896 Z"
+ id="path161" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/leaf.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/leaf.svg
new file mode 100644
index 000000000..c1cabb5cf
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/leaf.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="-10 0 1034 1024">
+ <path fill="currentColor"
+d="M765 327l-14 -11l-538 502l503 -533l-14 -12q-48 -26 -106 -23.5t-109 19.5q-14 4 -28.5 10t-28.5 13q-30 14 -57.5 32.5t-52.5 41.5q-55 52 -90.5 119t-52.5 140q-5 21 -9 42t-7 42q-3 26 -5.5 52.5t-4.5 53.5q-1 22 1.5 45.5t33.5 21.5h11.5h10.5q78 -2 156 -6t153 -29
+q49 -16 94 -42.5t82 -62.5q27 -27 50 -60t39 -69.5t24 -75.5t5 -78q-3 -35 -12.5 -70t-33.5 -62v0zM844 160l30 30l-563 531z" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/light_bulb.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/light_bulb.svg
new file mode 100644
index 000000000..ed2ed55fb
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/light_bulb.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ viewBox="-10 0 1538 1538"
+ id="svg4"
+ sodipodi:docname="light_bulb.svg"
+ width="1538"
+ height="1538"
+ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ id="namedview6"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ showgrid="false"
+ fit-margin-top="1"
+ fit-margin-left="1"
+ fit-margin-right="1"
+ fit-margin-bottom="1"
+ lock-margins="true"
+ inkscape:zoom="0.16"
+ inkscape:cx="1234.375"
+ inkscape:cy="409.375"
+ inkscape:window-width="1846"
+ inkscape:window-height="1016"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4" />
+ <path
+ fill="currentColor"
+ d="m 983,449 q 0,13 -9.5,22.5 Q 964,481 951,481 938,481 928.5,471.5 919,462 919,449 919,403 865,378 811,353 759,353 746,353 736.5,343.5 727,334 727,321 q 0,-13 9.5,-22.5 9.5,-9.5 22.5,-9.5 50,0 99.5,16 49.5,16 87,54 37.5,38 37.5,90 z m 160,0 q 0,-72 -34.5,-134 -34.5,-62 -90,-101.5 Q 963,174 895.5,151.5 828,129 759,129 690,129 622.5,151.5 555,174 499.5,213.5 444,253 409.5,315 375,377 375,449 q 0,101 68,180 10,11 30.5,33 20.5,22 30.5,33 128,153 141,298 h 228 q 13,-145 141,-298 10,-11 30.5,-33 20.5,-22 30.5,-33 68,-79 68,-180 z m 128,0 q 0,155 -103,268 -45,49 -74.5,87 -29.5,38 -59.5,95.5 -30,57.5 -34,107.5 47,28 47,82 0,37 -25,64 25,27 25,64 0,52 -45,81 13,23 13,47 0,46 -31.5,71 -31.5,25 -77.5,25 -20,44 -60,70 -40,26 -87,26 -47,0 -87,-26 -40,-26 -60,-70 -46,0 -77.5,-25 -31.5,-25 -31.5,-71 0,-24 13,-47 -45,-29 -45,-81 0,-37 25,-64 -25,-27 -25,-64 0,-54 47,-82 Q 514,957 484,899.5 454,842 424.5,804 395,766 350,717 247,604 247,449 247,350 291.5,264.5 336,179 408.5,122.5 481,66 572.5,33.5 664,1 759,1 q 95,0 186.5,32.5 91.5,32.5 164,89 72.5,56.5 117,142 Q 1271,350 1271,449 Z"
+ id="path2" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/qt_logo.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/qt_logo.svg
new file mode 100644
index 000000000..062daff3e
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/qt_logo.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="462pt"
+ height="339pt"
+ viewBox="0 0 462 339"
+ version="1.1"
+ id="svg2"
+>
+ <path
+ fill="#41cd52"
+ d=" M 63.50 0.00 L 462.00 0.00 L 462.00 274.79 C 440.60 296.26 419.13 317.66 397.61 339.00 L 0.00 339.00 L 0.00 63.39 C 21.08 42.18 42.34 21.13 63.50 0.00 Z"
+ id="path6"/>
+ <path
+ d=" M 122.37 71.33 C 137.50 61.32 156.21 58.79 174.00 58.95 C 190.94 59.16 208.72 62.13 222.76 72.24 C 232.96 79.41 239.59 90.48 244.01 101.93 C 251.16 120.73 253.26 141.03 253.50 161.01 C 253.53 181.13 252.62 201.69 245.96 220.86 C 241.50 233.90 233.01 245.48 221.81 253.52 C 229.87 266.58 238.09 279.54 246.15 292.60 C 236.02 297.27 225.92 301.97 215.78 306.62 C 207.15 292.38 198.56 278.11 189.90 263.89 C 178.19 265.81 166.21 265.66 154.44 264.36 C 140.34 262.67 125.97 258.37 115.09 248.88 C 106.73 241.64 101.48 231.51 97.89 221.21 C 92.01 203.79 90.43 185.25 90.16 166.97 C 90.02 147.21 91.28 127.14 97.24 108.18 C 101.85 93.92 109.48 79.69 122.37 71.33 Z"
+ id="path8"
+ fill="#ffffff"/>
+ <path
+ d=" M 294.13 70.69 C 304.73 70.68 315.33 70.68 325.93 70.69 C 325.96 84.71 325.92 98.72 325.95 112.74 C 339.50 112.76 353.05 112.74 366.60 112.75 C 366.37 121.85 366.12 130.95 365.86 140.05 C 352.32 140.08 338.79 140.04 325.25 140.07 C 325.28 163.05 325.18 186.03 325.30 209.01 C 325.56 215.30 325.42 221.94 328.19 227.75 C 330.21 232.23 335.65 233.38 340.08 233.53 C 348.43 233.50 356.77 233.01 365.12 232.86 C 365.63 241.22 366.12 249.59 366.60 257.95 C 349.99 260.74 332.56 264.08 316.06 258.86 C 309.11 256.80 302.63 252.19 299.81 245.32 C 294.76 233.63 294.35 220.62 294.13 208.07 C 294.11 185.40 294.13 162.74 294.12 140.07 C 286.73 140.05 279.34 140.08 271.95 140.05 C 271.93 130.96 271.93 121.86 271.95 112.76 C 279.34 112.73 286.72 112.77 294.11 112.74 C 294.14 98.72 294.10 84.71 294.13 70.69 Z"
+ id="path10"
+ fill="#ffffff"/>
+ <path
+ fill="#41cd52"
+ d=" M 160.51 87.70 C 170.80 86.36 181.60 86.72 191.34 90.61 C 199.23 93.73 205.93 99.84 209.47 107.58 C 214.90 119.31 216.98 132.26 218.03 145.05 C 219.17 162.07 219.01 179.25 216.66 196.17 C 215.01 206.24 212.66 216.85 205.84 224.79 C 198.92 232.76 188.25 236.18 178.01 236.98 C 167.21 237.77 155.82 236.98 146.07 231.87 C 140.38 228.84 135.55 224.09 132.73 218.27 C 129.31 211.30 127.43 203.69 126.11 196.07 C 122.13 171.91 121.17 146.91 126.61 122.89 C 128.85 113.83 132.11 104.53 138.73 97.70 C 144.49 91.85 152.51 88.83 160.51 87.70 Z"
+ id="path12"/>
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/read.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/read.svg
new file mode 100644
index 000000000..c3af473d2
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/read.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ viewBox="-11 0 1792 1792"
+ id="svg184"
+ sodipodi:docname="read.svg"
+ width="1792"
+ height="1792"
+ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs188" />
+ <sodipodi:namedview
+ id="namedview186"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ showgrid="false"
+ inkscape:zoom="0.24358259"
+ inkscape:cx="519.33104"
+ inkscape:cy="1089.9794"
+ inkscape:window-width="1846"
+ inkscape:window-height="1016"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg184" />
+ <path
+ fill="currentColor"
+ d="m 1691.8576,478 q 40,57 18,129 l -275,906 q -19,64 -76.5,107.5 -57.5,43.5 -122.5,43.5 H 312.85764 q -77,0 -148.5,-53.5 Q 92.857644,1557 64.857644,1479 q -24,-67 -2,-127 0,-4 3,-27 3,-23 4,-37 1,-8 -3,-21.5 -4,-13.5 -3,-19.5 2,-11 8,-21 6,-10 16.5,-23.5 10.5,-13.5 16.499996,-23.5 23,-38 45,-91.5 22,-53.5 30,-91.5 3,-10 0.5,-30 -2.5,-20 -0.5,-28 3,-11 17,-28 14,-17 17,-23 21,-36 42,-92 21,-56 25,-90 1,-9 -2.5,-32 -3.5,-23 0.5,-28 4,-13 22,-30.5 18,-17.5 22,-22.5 19,-26 42.5,-84.5 23.5,-58.5 27.5,-96.5 1,-8 -3,-25.5 -4,-17.5 -2,-26.5 2,-8 9,-18 7,-10 18,-23 11,-13 17,-21 8,-12 16.5,-30.5 8.5,-18.5 15,-35 6.5,-16.5 16,-36 9.5,-19.5 19.5,-32 10,-12.5 26.5,-23.5 16.5,-11 36,-11.5 19.5,-0.5 47.5,5.5 l -1,3 q 38,-9 51,-9 h 760.99996 q 74,0 114,56 40,56 18,130 l -274,906 q -36,119 -71.5,153.5 -35.5,34.5 -128.5,34.5 H 208.85764 q -27,0 -38,15 -11,16 -1,43 24,70 144,70 h 922.99996 q 29,0 56,-15.5 27,-15.5 35,-41.5 l 300,-987 q 7,-22 5,-57 38,15 59,43 z m -1063.99996,2 q -4,13 2,22.5 6,9.5 20,9.5 h 607.99996 q 13,0 25.5,-9.5 12.5,-9.5 16.5,-22.5 l 21,-64 q 4,-13 -2,-22.5 -6,-9.5 -20,-9.5 H 690.85764 q -13,0 -25.5,9.5 -12.5,9.5 -16.5,22.5 z m -83,256 q -4,13 2,22.5 6,9.5 20,9.5 h 607.99996 q 13,0 25.5,-9.5 12.5,-9.5 16.5,-22.5 l 21,-64 q 4,-13 -2,-22.5 -6,-9.5 -20,-9.5 H 607.85764 q -13,0 -25.5,9.5 -12.5,9.5 -16.5,22.5 z"
+ id="path182" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/resize.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/resize.svg
new file mode 100644
index 000000000..e86d612f3
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/resize.svg
@@ -0,0 +1,6 @@
+<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'>
+ <line x1="00" y1="100" x2="100" y2="00" stroke="black" stroke-width="3" />
+ <line x1="20" y1="100" x2="100" y2="20" stroke="black" stroke-width="3" />
+ <line x1="40" y1="100" x2="100" y2="40" stroke="black" stroke-width="3" />
+ <line x1="60" y1="100" x2="100" y2="60" stroke="black" stroke-width="3" />
+</svg>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/About.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/About.qml
new file mode 100644
index 000000000..b7bc0ac6f
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/About.qml
@@ -0,0 +1,59 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls.Basic
+import FileSystemModule
+
+ApplicationWindow {
+ id: root
+ width: 500
+ height: 360
+ flags: Qt.Window | Qt.FramelessWindowHint
+ color: Colors.surface1
+
+ menuBar: MyMenuBar {
+ id: menuBar
+ implicitHeight: 20
+ rootWindow: root
+ infoText: "About Qt"
+ }
+
+ Image {
+ id: logo
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.margins: 20
+ source: "../icons/qt_logo.svg"
+ sourceSize: Qt.size(80, 80)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+ antialiasing: true
+ asynchronous: true
+ }
+
+ TextArea {
+ anchors.top: logo.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.margins: 20
+ antialiasing: true
+ wrapMode: Text.WrapAnywhere
+ color: Colors.textFile
+ horizontalAlignment: Text.AlignHCenter
+ readOnly: true
+ selectionColor: Colors.selection
+ text: qsTr("Qt Group (Nasdaq Helsinki: QTCOM) is a global software company with a strong \
+presence in more than 70 industries and is the leading independent technology behind 1+ billion \
+devices and applications. Qt is used by major global companies and developers worldwide, and the \
+technology enables its customers to deliver exceptional user experiences and advance their digital \
+transformation initiatives. Qt achieves this through its cross-platform software framework for the \
+development of apps and devices, under both commercial and open-source licenses.")
+ background: Rectangle {
+ color: "transparent"
+ }
+ }
+ ResizeButton {}
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ColorScheme.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ColorScheme.qml
new file mode 100644
index 000000000..19c8cd905
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ColorScheme.qml
@@ -0,0 +1,118 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import FileSystemModule
+
+ColumnLayout {
+ id: colorScheme
+
+ spacing: 20
+
+ // Inline component that customizes TabButton
+ component MyTabButton: TabButton {
+ id: root
+
+ implicitWidth: 150
+ implicitHeight: 30
+ padding: 6
+ spacing: 6
+
+ contentItem: Text {
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ text: root.text
+ font.bold: true
+ color: Colors.text
+ }
+
+ background: Rectangle {
+ anchors.fill: parent
+ implicitHeight: 40
+
+ color: root.checked ? Colors.active : Colors.selection
+ Rectangle {
+ height: 4
+ width: parent.width
+ color: root.checked ? Colors.color1 : Colors.selection
+ }
+ }
+ }
+
+ Item {
+ // Spacer item
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ Text {
+ Layout.alignment: Qt.AlignHCenter
+
+ text: "Select a Scheme!"
+ font.pointSize: 30
+ font.bold: true
+ color: Colors.text
+ }
+
+ // Display all the color-scheme names. The model is a string-list provided
+ // by our python class.
+ TabBar {
+ id: schemeSelector
+
+ Layout.alignment: Qt.AlignHCenter
+
+ background: Rectangle {
+ color: Colors.surface1
+ }
+
+ Repeater {
+ model: Colors.getKeys()
+ MyTabButton {
+ text: modelData
+ onClicked: {
+ Colors.setScheme(modelData)
+ themePreviewContainer.background
+ = (modelData === "Solarized") ? "#777777" : "#FEFAEC"
+ }
+ }
+ }
+ }
+
+ // The current colors can be visualized using the same method as above.
+ Rectangle {
+ id: themePreviewContainer
+
+ property color background: "#FEFAEC"
+
+ Layout.alignment: Qt.AlignHCenter
+
+ width: 700
+ height: 50
+ radius: 10
+ color: background
+
+ // Display all used colors inside a row
+ Row {
+ anchors.centerIn: parent
+ spacing: 10
+
+ Repeater {
+ model: Colors.currentColors
+ Rectangle {
+ width: 35
+ height: width
+ radius: width / 2
+ color: modelData
+ }
+ }
+ }
+ }
+ Item {
+ // Spacer item
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/FileSystemView.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/FileSystemView.qml
new file mode 100644
index 000000000..ade2e48c1
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/FileSystemView.qml
@@ -0,0 +1,99 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls.Basic
+import FileSystemModule
+
+// This is the file system view which gets populated by the C++ model.
+Rectangle {
+ id: root
+
+ signal fileClicked(string filePath)
+
+ TreeView {
+ id: fileSystemTreeView
+ anchors.fill: parent
+ model: FileSystemModel
+ boundsBehavior: Flickable.StopAtBounds
+ boundsMovement: Flickable.StopAtBounds
+ clip: true
+
+ property int lastIndex: -1
+
+ Component.onCompleted: fileSystemTreeView.toggleExpanded(0)
+
+ // The delegate represents a single entry in the filesystem.
+ delegate: TreeViewDelegate {
+ id: treeDelegate
+ indentation: 8
+ implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250
+ implicitHeight: 25
+
+ required property int index
+ required property url filePath
+
+ indicator: null
+
+ contentItem: Item {
+ anchors.fill: parent
+
+ Icon {
+ id: directoryIcon
+ x: leftMargin + (depth * indentation)
+ anchors.verticalCenter: parent.verticalCenter
+ path: treeDelegate.hasChildren
+ ? (treeDelegate.expanded ? "../icons/folder_open.svg" : "../icons/folder_closed.svg")
+ : "../icons/generic_file.svg"
+ iconColor: (treeDelegate.expanded && treeDelegate.hasChildren) ? Colors.color2 : Colors.folder
+ }
+ Text {
+ anchors.left: directoryIcon.right
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ text: model.fileName
+ color: Colors.text
+ }
+ }
+
+ background: Rectangle {
+ color: treeDelegate.index === fileSystemTreeView.lastIndex
+ ? Colors.selection
+ : (hoverHandler.hovered ? Colors.active : "transparent")
+ }
+
+ TapHandler {
+ onSingleTapped: {
+ fileSystemTreeView.toggleExpanded(row)
+ fileSystemTreeView.lastIndex = index
+ // If this model item doesn't have children, it means it's representing a file.
+ if (!treeDelegate.hasChildren)
+ root.fileClicked(filePath)
+ }
+ }
+ HoverHandler {
+ id: hoverHandler
+ }
+ }
+
+ // Provide our own custom ScrollIndicator for the TreeView.
+ ScrollIndicator.vertical: ScrollIndicator {
+ active: true
+ implicitWidth: 15
+
+ contentItem: Rectangle {
+ implicitWidth: 6
+ implicitHeight: 6
+ color: Colors.color1
+ opacity: fileSystemTreeView.movingVertically ? 0.5 : 0.0
+
+ Behavior on opacity {
+ OpacityAnimator {
+ duration: 500
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Icon.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Icon.qml
new file mode 100644
index 000000000..25162d9d3
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Icon.qml
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Effects
+
+// Custom Component for displaying Icons
+Item {
+ id: root
+
+ required property url path
+ property real padding: 5
+ property real size: 30
+ property alias iconColor: overlay.colorizationColor
+ property alias hovered: mouse.hovered
+
+ width: size
+ height: size
+
+ Image {
+ id: icon
+ anchors.fill: root
+ anchors.margins: padding
+ source: path
+ sourceSize: Qt.size(size, size)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+ antialiasing: true
+ asynchronous: true
+ }
+
+ MultiEffect {
+ id: overlay
+ anchors.fill: icon
+ source: icon
+ colorization: 1.0
+ brightness: 1.0
+ }
+
+ HoverHandler {
+ id: mouse
+ acceptedDevices: PointerDevice.Mouse
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenu.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenu.qml
new file mode 100644
index 000000000..99795b5e5
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenu.qml
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls.Basic
+import FileSystemModule
+
+Menu {
+ id: root
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ color: Colors.surface2
+ }
+
+ delegate: MenuItem {
+ id: menuItem
+ implicitWidth: 200
+ implicitHeight: 40
+ contentItem: Item {
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 5
+ text: menuItem.text
+ color: enabled ? Colors.text : Colors.disabledText
+ }
+ Rectangle {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ width: 6
+ height: parent.height
+ visible: menuItem.highlighted
+ color: Colors.color2
+ }
+ }
+ background: Rectangle {
+ color: menuItem.highlighted ? Colors.active : "transparent"
+ }
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenuBar.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenuBar.qml
new file mode 100644
index 000000000..a2a3fea88
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenuBar.qml
@@ -0,0 +1,135 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls.Basic
+import FileSystemModule
+
+// The MenuBar also serves as a controller for our Window as we don't use any decorations.
+MenuBar {
+ id: root
+
+ required property ApplicationWindow rootWindow
+ property alias infoText: windowInfo.text
+
+ implicitHeight: 25
+
+ // The top level menus on the left side
+ delegate: MenuBarItem {
+ id: menuBarItem
+ implicitHeight: 25
+
+ contentItem: Text {
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ color: menuBarItem.highlighted ? Colors.textFile : Colors.text
+ opacity: enabled ? 1.0 : 0.3
+ text: menuBarItem.text
+ elide: Text.ElideRight
+ font: menuBarItem.font
+ }
+
+ background: Rectangle {
+ color: menuBarItem.highlighted ? Colors.selection : "transparent"
+ Rectangle {
+ id: indicator
+ width: 0; height: 3
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ color: Colors.color1
+
+ states: State {
+ name: "active"; when: menuBarItem.highlighted
+ PropertyChanges { target: indicator; width: parent.width }
+ }
+
+ transitions: Transition {
+ NumberAnimation {
+ properties: "width"
+ duration: 300
+ }
+ }
+
+ }
+ }
+ }
+
+ // The background property contains an information text in the middle as well as the
+ // Minimize, Maximize and Close Buttons.
+ background: Rectangle {
+ color: Colors.surface2
+ // Make the empty space drag the specified root window.
+ WindowDragHandler { dragWindow: rootWindow }
+
+ Text {
+ id: windowInfo
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ color: Colors.text
+ }
+
+ component InteractionButton: Rectangle {
+ signal action;
+ property alias hovered: hoverHandler.hovered
+
+ width: root.height
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ color: hovered ? Colors.background : "transparent"
+
+ HoverHandler { id: hoverHandler }
+ TapHandler { onTapped: action() }
+ }
+
+ InteractionButton {
+ id: minimize
+
+ anchors.right: maximize.left
+ onAction: rootWindow.showMinimized()
+ Rectangle {
+ width: parent.height - 10; height: 2
+ anchors.centerIn: parent
+ color: parent.hovered ? Colors.iconIndicator : Colors.icon
+ }
+ }
+
+ InteractionButton {
+ id: maximize
+
+ anchors.right: close.left
+ onAction: rootWindow.showMaximized()
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 5
+ border.width: 2
+ color: "transparent"
+ border.color: parent.hovered ? Colors.iconIndicator : Colors.icon
+ }
+ }
+
+ InteractionButton {
+ id: close
+
+ color: hovered ? "#ec4143" : "transparent"
+ anchors.right: parent.right
+ onAction: rootWindow.close()
+ Rectangle {
+ width: parent.height - 8; height: 2
+ anchors.centerIn: parent
+ color: parent.hovered ? Colors.iconIndicator : Colors.icon
+ rotation: 45
+ transformOrigin: Item.Center
+ antialiasing: true
+ Rectangle {
+ width: parent.height
+ height: parent.width
+ anchors.centerIn: parent
+ color: parent.color
+ antialiasing: true
+ }
+ }
+ }
+ }
+
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ResizeButton.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ResizeButton.qml
new file mode 100644
index 000000000..eb2e5bc02
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ResizeButton.qml
@@ -0,0 +1,23 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick.Controls
+import FileSystemModule
+
+Button {
+ icon.width: 20; icon.height: 20
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ rightPadding: 3
+ bottomPadding: 3
+
+ icon.source: "../icons/resize.svg"
+ icon.color: down || checked ? Colors.iconIndicator : Colors.icon
+
+ checkable: false
+ display: AbstractButton.IconOnly
+ background: null
+ onPressed: {
+ root.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Sidebar.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Sidebar.qml
new file mode 100644
index 000000000..29062a9bb
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Sidebar.qml
@@ -0,0 +1,124 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls.Basic
+import FileSystemModule
+
+Rectangle {
+ id: root
+ color: Colors.surface2
+
+ required property ApplicationWindow rootWindow
+ property alias currentTabIndex: tabBar.currentIndex
+
+ ColumnLayout {
+ anchors.fill: root
+ anchors.topMargin: 10
+ anchors.bottomMargin: 10
+ spacing: 10
+
+ // TabBar is designed to be horizontal, whereas we need a vertical bar.
+ // We can easily achieve that by using a Container.
+ Container {
+ id: tabBar
+
+ Layout.fillWidth: true
+
+ // ButtonGroup ensures that only one button can be checked at a time.
+ ButtonGroup {
+ buttons: tabBar.contentItem.children
+ // We have to manage the currentIndex ourselves, which we do by setting it to the
+ // index of the currently checked button.
+ // We use setCurrentIndex instead of setting the currentIndex property to avoid breaking bindings.
+ // See "Managing the Current Index" in Container's documentation for more information.
+ onCheckedButtonChanged: tabBar.setCurrentIndex(Math.max(0, buttons.indexOf(checkedButton)))
+ }
+
+ contentItem: ColumnLayout {
+ spacing: tabBar.spacing
+
+ Repeater {
+ model: tabBar.contentModel
+ }
+ }
+
+ component SidebarEntry: Button {
+ id: sidebarButton
+ icon.color: down || checked ? Colors.iconIndicator : Colors.icon
+ icon.width: 35
+ icon.height: 35
+ leftPadding: 8 + indicator.width
+
+ background: null
+
+ Rectangle {
+ id: indicator
+ x: 4
+ anchors.verticalCenter: parent.verticalCenter
+ width: 4
+ height: sidebarButton.icon.width
+ color: Colors.color1
+ visible: sidebarButton.checked
+ }
+ }
+
+ // Shows help text when clicked.
+ SidebarEntry {
+ icon.source: "../icons/light_bulb.svg"
+ checkable: true
+ checked: true
+
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ // Shows the file system when clicked.
+ SidebarEntry {
+ icon.source: "../icons/read.svg"
+ checkable: true
+
+ Layout.alignment: Qt.AlignHCenter
+ }
+ // Shows the scheme switcher
+ SidebarEntry {
+ icon.source: "../icons/leaf.svg"
+ checkable: true
+
+ Layout.alignment: Qt.AlignHCenter
+ }
+ }
+
+ // This item acts as a spacer to expand between the checkable and non-checkable buttons.
+ Item {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ // Make the empty space drag our main window.
+ WindowDragHandler { dragWindow: rootWindow }
+ }
+
+ // Opens the Qt website in the system's web browser.
+ SidebarEntry {
+ id: qtWebsiteButton
+ icon.source: "../icons/globe.svg"
+ checkable: false
+
+ onClicked: Qt.openUrlExternally("https://www.qt.io/")
+ }
+
+ // Opens the About Qt Window.
+ SidebarEntry {
+ id: aboutQtButton
+ icon.source: "../icons/info_sign.svg"
+ checkable: false
+
+ onClicked: aboutQtWindow.visible = !aboutQtWindow.visible
+ }
+ }
+
+ About {
+ id: aboutQtWindow
+ visible: false
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/WindowDragHandler.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/WindowDragHandler.qml
new file mode 100644
index 000000000..0e140aca3
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/WindowDragHandler.qml
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+// Allows dragging the window when placed on an unused section of the UI.
+DragHandler {
+
+ required property ApplicationWindow dragWindow
+
+ target: null
+ onActiveChanged: {
+ if (active) dragWindow.startSystemMove()
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qmldir b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qmldir
new file mode 100644
index 000000000..6c9e3ed9b
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qmldir
@@ -0,0 +1,11 @@
+module FileSystemModule
+Main 1.0 Main.qml
+Icon 1.0 qml/Icon.qml
+About 1.0 qml/About.qml
+MyMenu 1.0 qml/MyMenu.qml
+Sidebar 1.0 qml/Sidebar.qml
+MyMenuBar 1.0 qml/MyMenuBar.qml
+ColorScheme 1.0 qml/ColorScheme.qml
+ResizeButton 1.0 qml/ResizeButton.qml
+FileSystemView 1.0 qml/FileSystemView.qml
+WindowDragHandler 1.0 qml/WindowDragHandler.qml
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.md b/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.md
new file mode 100644
index 000000000..7e265a7ef
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.md
@@ -0,0 +1,210 @@
+# Extending the file system explorer example
+
+This tutorial shows how to extend the
+[Filesystem Explorer Example](filesystemexplorer_example)
+by adding a simple scheme manager. This feature will allow you to switch color
+schemes during the application's runtime. The color schemes will be declared in
+JSON format and made available through a custom Python-QML plugin.
+
+![Extended Explorer GIF](resources/extendedexplorer.gif)
+
+## Defining the color schemes
+
+To define your color scheme, you can use the same color names as the original
+example, so you don't have to rename every occurrence. The original colors are
+defined in the `Colors.qml` file as follows:
+
+```{literalinclude} resources/Colors.qml
+---
+language: QML
+caption: true
+linenos: true
+lines: 7-22
+---
+```
+
+The `schemes.json` file holds the color schemes. To start implementing this, you
+can use the [Catppuccin](https://github.com/catppuccin/catppuccin) scheme.
+
+```{literalinclude} schemes.json
+---json
+caption: true
+linenos: true
+start-at: "Catppuccin"
+end-at: "},"
+---
+```
+
+In addition to the "Catppuccin" color scheme, four other color schemes got
+implemented: Nordic, One Dark, Gruvbox, and Solarized. However, feel free to get
+creative and experiment with **your** schemes.
+
+To define a new color scheme, copy the structure from above and provide your
+color values
+
+## Implement the scheme manager
+
+After defining the color schemes, you can implement the actual scheme manager.
+The manager will read the `schemes.json` file and provide QML bindings to switch
+between schemes during runtime.
+
+To implement the scheme manager, create a Python-QML plugin that exposes the
+`SchemeManager` object to QML. This object will have methods to load the color
+schemes from the `schemes.json` file and switch between them.
+
+Create a new Python file called `schememanager.py` in your project directory. In
+this file, define the **SchemeManager** class:
+
+```{literalinclude} scheme_manager.py
+---
+language: python
+caption: true
+linenos: true
+start-at: "QML_IMPORT_NAME"
+end-at: "class SchemeManager"
+---
+```
+
+To integrate smoothly into the already existing code, attach the SchemeManager
+to the same QML module that's already present with
+`QML_IMPORT_NAME = "FileSystemModule"`. Additionally, use the`@QmlNamedElement`
+decorator to smoothly transition to using the custom plugin instead of the
+`Colors.qml` file. With these changes, we can avoid editing all previous
+assignments like:
+
+```QML
+import FileSystemModule
+...
+Rectangle {
+ color: Colors.background
+}
+```
+
+The constructor reads the `schemes.json` file once upon application start and
+then calls the `setTheme` member function.
+
+```{literalinclude} scheme_manager.py
+---
+language: python
+caption: true
+linenos: true
+lines: 18-24
+---
+```
+
+By adding the `SchemeManager` as a callable QML element named **Colors** to the
+FileSystemModule, the class is now accessible in the code without the need to
+import it each time or edit previous assignments. This, in turn, will streamline
+the workflow.
+
+After defining the schemes in the JSON format and making the `SchemeManager`
+class a callable element from QML under the name **Colors**, there are two
+remaining steps to fully integrate the new scheme manager in the example.
+
+The **first step** is to create a function in the `SchemeManager` class that
+loads a color scheme from the JSON file. The **second step** is to make the
+individual colors available in QML with the *same name* as used before with the
+syntax `Colors.<previousName>` as assignable properties.
+
+
+```{literalinclude} scheme_manager.py
+---
+language: python
+caption: true
+linenos: true
+lines: 26-31
+---
+```
+
+The `setScheme` method is responsible for switching between color schemes. To
+make this method accessible in QML, use the `@Slot(str)` decorator and specify
+that it takes a string as its input parameter. In this method, we populate a
+dictionary with the color values from the JSON file.
+
+> Note: For simplicity reasons no other error checking is performed.
+> You would probably want to validate the keys contained in the json.
+
+```{literalinclude} scheme_manager.py
+---
+language: python
+caption: true
+linenos: true
+start-at: "@Property(QColor"
+end-at: "return"
+---
+```
+
+To make the color property assignable in QML, use the `@Property` decorator.
+We simply return the corresponding color value from the dictionary for each
+property. This process is repeated for all other colors that are used in the
+application.
+At this point the application should start with the colors provided by the
+active scheme in the constructor.
+
+## Add the scheme switching to QML
+
+To visualize the current scheme and enable interactive scheme switching, start
+by adding a new entry to the `Sidebar.qml` file.
+
+```{literalinclude} FileSystemModule/qml/Sidebar.qml
+---
+language: QML
+caption: true
+linenos: true
+lines: 83-90
+---
+```
+
+To update the main content area of the application to display the `ColorScheme`,
+the logic that checks the active index from the Sidebar buttons needs to be
+modified. The necessary changes will be made to the Main.qml file:
+
+```{literalinclude} FileSystemModule/Main.qml
+---
+language: QML
+caption: true
+linenos: true
+lines: 169-198
+---
+```
+
+In addition, change the behavior of the application so that there are two
+`StackLayouts`: one for the resizable navigation and one for the main content
+area where we display our color scheme switching functionality. These changes
+will also be made to the Main.qml file.
+
+```{literalinclude} FileSystemModule/Main.qml
+---
+language: QML
+caption: true
+linenos: true
+lines: 144-145
+---
+```
+
+To complete our implementation, the `ColorScheme.qml` file needs to be created.
+The implementation is straightforward and follows the same principles as in the
+original example. If anything is unclear, please refer to the documentation
+provided there. To display all colors and scheme names, use a `Repeater`. The
+model for the Repeater is provided by our `scheme_manager.py`file as a
+`QStringList`.
+
+```{literalinclude} FileSystemModule/qml/ColorScheme.qml
+---
+language: QML
+caption: true
+linenos: true
+lines: 97-111
+---
+```
+
+When examining the code in more detail, you will notice that there are different
+ways to retrieve the models. The `getKeys()` method is defined as a **Slot** and
+therefore requires parentheses when called. On the other hand, the `currentColors`
+model is defined as a **property** and is therefore assigned as a property in QML.
+The reason for this is to receive notifications when the color scheme is switched
+so that the colors displayed in the application can be updated. The keys for the
+color schemes are loaded only once at application startup and do not rely on any
+notifications.
+
+![Extended Explorer GIF](resources/colorscheme.png)
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.py b/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.py
new file mode 100644
index 000000000..6ad6e926c
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.py
@@ -0,0 +1,70 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""
+This example shows how to customize Qt Quick Controls by implementing a simple filesystem explorer.
+"""
+
+# Compile both resource files app.qrc and icons.qrc and include them here if you wish
+# to load them from the resource system. Currently, all resources are loaded locally
+# import FileSystemModule.rc_icons
+# import FileSystemModule.rc_app
+from scheme_manager import SchemeManager
+
+from PySide6.QtWidgets import QFileSystemModel
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import (QQmlApplicationEngine, QmlElement, QmlSingleton)
+from PySide6.QtCore import (Slot, QFile, QTextStream, QMimeDatabase, QFileInfo, QStandardPaths)
+
+import sys
+
+
+QML_IMPORT_NAME = "FileSystemModule"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+@QmlSingleton
+class FileSystemModel(QFileSystemModel):
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.setRootPath(QStandardPaths.writableLocation(QStandardPaths.HomeLocation))
+ self.db = QMimeDatabase()
+
+ # we only need one column in this example
+ def columnCount(self, parent):
+ return 1
+
+ # check for the correct mime type and then read the file.
+ # returns the text file's content or an error message on failure
+ @Slot(str, result=str)
+ def readFile(self, path):
+ if path == "":
+ return ""
+
+ file = QFile(path)
+
+ mime = self.db.mimeTypeForFile(QFileInfo(file))
+ if 'text' in mime.comment().lower() or any('text' in s.lower() for s in mime.parentMimeTypes()):
+ if file.open(QFile.ReadOnly | QFile.Text):
+ stream = QTextStream(file).readAll()
+ return stream
+ else:
+ return self.tr("Error opening the file!")
+ return self.tr("File type not supported!")
+
+
+if __name__ == '__main__':
+ app = QGuiApplication(sys.argv)
+ app.setOrganizationName("QtProject")
+ app.setApplicationName("File System Explorer")
+ engine = QQmlApplicationEngine()
+ # Include the path of this file to search for the 'qmldir' module
+ engine.addImportPath(sys.path[0])
+
+ engine.loadFromModule("FileSystemModule", "Main")
+
+ if not engine.rootObjects():
+ sys.exit(-1)
+
+ sys.exit(app.exec())
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.pyproject b/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.pyproject
new file mode 100644
index 000000000..f6f2e4e89
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.pyproject
@@ -0,0 +1,29 @@
+{
+ "files": [
+ "extendedexplorer.py",
+ "color_scheme.py",
+ "FileSystemModule/qmldir",
+ "FileSystemModule/app.qrc",
+ "FileSystemModule/icons.qrc",
+ "FileSystemModule/qmldir",
+ "FileSystemModule/Main.qml",
+ "FileSystemModule/qml/About.qml",
+ "FileSystemModule/qml/ColorScheme.qml",
+ "FileSystemModule/qml/FileSystemView.qml",
+ "FileSystemModule/qml/Icon.qml",
+ "FileSystemModule/qml/MyMenu.qml",
+ "FileSystemModule/qml/MyMenuBar.qml",
+ "FileSystemModule/qml/ResizeButton.qml",
+ "FileSystemModule/qml/Sidebar.qml",
+ "FileSystemModule/qml/WindowDragHandler.qml",
+ "FileSystemModule/icons/folder_closed.svg",
+ "FileSystemModule/icons/folder_open.svg",
+ "FileSystemModule/icons/generic_file.svg",
+ "FileSystemModule/icons/globe.svg",
+ "FileSystemModule/icons/info_sign.svg",
+ "FileSystemModule/icons/light_bulb.svg",
+ "FileSystemModule/icons/qt_logo.svg",
+ "FileSystemModule/icons/read.svg",
+ "FileSystemModule/icons/resize.svg"
+ ]
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/resources/Colors.qml b/sources/pyside6/doc/tutorials/extendedexplorer/resources/Colors.qml
new file mode 100644
index 000000000..280f89286
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/resources/Colors.qml
@@ -0,0 +1,22 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma Singleton
+import QtQuick
+
+QtObject {
+ readonly property color background: "#23272E"
+ readonly property color surface1: "#1E2227"
+ readonly property color surface2: "#090A0C"
+ readonly property color text: "#ABB2BF"
+ readonly property color textFile: "#C5CAD3"
+ readonly property color disabledText: "#454D5F"
+ readonly property color selection: "#2C313A"
+ readonly property color active: "#23272E"
+ readonly property color inactive: "#3E4452"
+ readonly property color folder: "#3D4451"
+ readonly property color icon: "#3D4451"
+ readonly property color iconIndicator: "#E5C07B"
+ readonly property color color1: "#E06B74"
+ readonly property color color2: "#62AEEF"
+}
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/resources/colorscheme.png b/sources/pyside6/doc/tutorials/extendedexplorer/resources/colorscheme.png
new file mode 100644
index 000000000..410538ca3
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/resources/colorscheme.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.gif b/sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.gif
new file mode 100644
index 000000000..9e59f64aa
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.gif
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.webp b/sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.webp
new file mode 100644
index 000000000..1f4e2cfa7
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.webp
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/scheme_manager.py b/sources/pyside6/doc/tutorials/extendedexplorer/scheme_manager.py
new file mode 100644
index 000000000..e6ecb8d2a
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/scheme_manager.py
@@ -0,0 +1,99 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import json
+from pathlib import Path
+from PySide6.QtCore import Slot, QObject, Property, Signal
+from PySide6.QtGui import QColor
+from PySide6.QtQml import QmlNamedElement, QmlSingleton
+
+QML_IMPORT_NAME = "FileSystemModule"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlNamedElement("Colors")
+@QmlSingleton
+class SchemeManager(QObject):
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ with open(Path(__file__).parent / "schemes.json", 'r') as f:
+ self.m_schemes = json.load(f)
+ self.m_activeScheme = {}
+ self.m_activeSchemeName = "Catppuccin"
+ self.setScheme(self.m_activeSchemeName)
+
+ @Slot(str)
+ def setScheme(self, theme):
+ for k, v in self.m_schemes[theme].items():
+ self.m_activeScheme[k] = QColor.fromString(v)
+ self.m_activeSchemeName = theme
+ self.schemeChanged.emit()
+
+ @Slot(result='QStringList')
+ def getKeys(self):
+ return self.m_schemes.keys()
+
+ @Signal
+ def schemeChanged(self):
+ pass
+
+ @Property('QStringList', notify=schemeChanged)
+ def currentColors(self):
+ return self.m_schemes[self.m_activeSchemeName].values()
+
+ @Property(QColor, notify=schemeChanged)
+ def background(self):
+ return self.m_activeScheme["background"]
+
+ @Property(QColor, notify=schemeChanged)
+ def surface1(self):
+ return self.m_activeScheme["surface1"]
+
+ @Property(QColor, notify=schemeChanged)
+ def surface2(self):
+ return self.m_activeScheme["surface2"]
+
+ @Property(QColor, notify=schemeChanged)
+ def text(self):
+ return self.m_activeScheme["text"]
+
+ @Property(QColor, notify=schemeChanged)
+ def textFile(self):
+ return self.m_activeScheme["textFile"]
+
+ @Property(QColor, notify=schemeChanged)
+ def disabledText(self):
+ return self.m_activeScheme["disabledText"]
+
+ @Property(QColor, notify=schemeChanged)
+ def selection(self):
+ return self.m_activeScheme["selection"]
+
+ @Property(QColor, notify=schemeChanged)
+ def active(self):
+ return self.m_activeScheme["active"]
+
+ @Property(QColor, notify=schemeChanged)
+ def inactive(self):
+ return self.m_activeScheme["inactive"]
+
+ @Property(QColor, notify=schemeChanged)
+ def folder(self):
+ return self.m_activeScheme["folder"]
+
+ @Property(QColor, notify=schemeChanged)
+ def icon(self):
+ return self.m_activeScheme["icon"]
+
+ @Property(QColor, notify=schemeChanged)
+ def iconIndicator(self):
+ return self.m_activeScheme["iconIndicator"]
+
+ @Property(QColor, notify=schemeChanged)
+ def color1(self):
+ return self.m_activeScheme["color1"]
+
+ @Property(QColor, notify=schemeChanged)
+ def color2(self):
+ return self.m_activeScheme["color2"]
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/schemes.json b/sources/pyside6/doc/tutorials/extendedexplorer/schemes.json
new file mode 100644
index 000000000..e4f2d8c81
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/extendedexplorer/schemes.json
@@ -0,0 +1,82 @@
+{
+ "Catppuccin": {
+ "background": "#1E1E2E",
+ "surface1": "#181825",
+ "surface2": "#11111B",
+ "text": "#CDD6F4",
+ "textFile": "#CDD6F4",
+ "disabledText": "#363659",
+ "selection": "#45475A",
+ "active": "#1E1E2E",
+ "inactive": "#6C7086",
+ "folder": "#6C7086",
+ "icon": "#6C7086",
+ "iconIndicator": "#FFCC66",
+ "color1": "#CBA6F7",
+ "color2": "#89DCEB"
+ },
+ "Nordic": {
+ "background": "#2E3440",
+ "surface1": "#2B2F3A",
+ "surface2": "#262A35",
+ "text": "#D8DEE9",
+ "textFile": "#D8DEE9",
+ "disabledText": "#4D556A",
+ "selection": "#495468",
+ "active": "#2E3440",
+ "inactive": "#555B6A",
+ "folder": "#495468",
+ "icon": "#495468",
+ "iconIndicator": "#FFC40D",
+ "color1": "#81B6C6",
+ "color2": "#5E81AC"
+ },
+ "One Dark": {
+ "background": "#23272E",
+ "surface1": "#1E2227",
+ "surface2": "#090A0C",
+ "text": "#ABB2BF",
+ "textFile": "#C5CAD3",
+ "disabledText": "#2B303B",
+ "selection": "#2C313A",
+ "active": "#23272E",
+ "inactive": "#3E4452",
+ "folder": "#3D4451",
+ "icon": "#3D4451",
+ "iconIndicator": "#E5C07B",
+ "color1": "#E06B74",
+ "color2": "#62AEEF"
+ },
+ "Gruvbox": {
+ "background": "#292828",
+ "surface1": "#171819",
+ "surface2": "#090A0C",
+ "text": "#D4BE98",
+ "textFile": "#E1D2B7",
+ "disabledText": "#2C313A",
+ "selection": "#333130",
+ "active": "#292828",
+ "inactive": "#383737",
+ "folder": "#383737",
+ "icon": "#383737",
+ "iconIndicator": "#FFCC66",
+ "color1": "#A7B464",
+ "color2": "#D3869B"
+ },
+ "Solarized": {
+ "background": "#FDF6E3",
+ "surface1": "#EEE8D5",
+ "surface2": "#DDD6C1",
+ "text": "#6D6D6D",
+ "textFile": "#333333",
+ "disabledText": "#ADADAD",
+ "selection": "#D1CBB8",
+ "active": "#FDF6E3",
+ "inactive": "#8C8364",
+ "folder": "#5F5944",
+ "icon": "#5F5944",
+ "iconIndicator": "#002B36",
+ "color1": "#B58900",
+ "color2": "#6B9E75"
+ }
+}
diff --git a/sources/pyside6/doc/tutorials/index.rst b/sources/pyside6/doc/tutorials/index.rst
index 85466937f..920e646c4 100644
--- a/sources/pyside6/doc/tutorials/index.rst
+++ b/sources/pyside6/doc/tutorials/index.rst
@@ -137,6 +137,12 @@ Quick/QML: Basic tutorials
QML, SQL and PySide Integration Tutorial
+ .. grid-item-card:: Extended Explorer
+ :class-item: cover-img
+ :link: extendedexplorer/extendedexplorer.html
+ :img-top: extendedexplorer/resources/extendedexplorer.webp
+
+ Extending an Qt Quick Controls example
.. toctree::
:maxdepth: 1
@@ -146,6 +152,7 @@ Quick/QML: Basic tutorials
qmlintegration/qmlintegration.rst
qmlapp/qmlapplication.rst
qmlsqlintegration/qmlsqlintegration.rst
+ extendedexplorer/extendedexplorer.md
General Applications
--------------------