aboutsummaryrefslogtreecommitdiffstats
path: root/examples/quickcontrols
diff options
context:
space:
mode:
Diffstat (limited to 'examples/quickcontrols')
-rw-r--r--examples/quickcontrols/contactslist/Contact/ContactDelegate.ui.qml82
-rw-r--r--examples/quickcontrols/contactslist/Contact/ContactDialog.qml45
-rw-r--r--examples/quickcontrols/contactslist/Contact/ContactForm.ui.qml72
-rw-r--r--examples/quickcontrols/contactslist/Contact/ContactList.qml70
-rw-r--r--examples/quickcontrols/contactslist/Contact/ContactView.ui.qml36
-rw-r--r--examples/quickcontrols/contactslist/Contact/SectionDelegate.ui.qml17
-rw-r--r--examples/quickcontrols/contactslist/Contact/qmldir7
-rw-r--r--examples/quickcontrols/contactslist/contactlist.pyproject10
-rw-r--r--examples/quickcontrols/contactslist/contactmodel.py116
-rw-r--r--examples/quickcontrols/contactslist/doc/contactslist.rst15
-rw-r--r--examples/quickcontrols/contactslist/doc/qtquickcontrols-contactlist.pngbin0 -> 23581 bytes
-rw-r--r--examples/quickcontrols/contactslist/main.py28
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/Main.qml229
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/app.qrc2
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/icons.qrc1
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/icons/app_icon.svg2
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml88
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml29
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml160
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml117
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Icon.qml44
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml19
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml184
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml10
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml147
-rw-r--r--examples/quickcontrols/filesystemexplorer/FileSystemModule/qmldir2
-rw-r--r--examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.rst13
-rw-r--r--examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.webpbin83086 -> 47416 bytes
-rw-r--r--examples/quickcontrols/filesystemexplorer/editormodels.py116
-rw-r--r--examples/quickcontrols/filesystemexplorer/filesystemexplorer.py69
-rw-r--r--examples/quickcontrols/filesystemexplorer/filesystemexplorer.pyproject6
-rw-r--r--examples/quickcontrols/filesystemexplorer/main.py48
-rw-r--r--examples/quickcontrols/gallery/doc/gallery.rst2
-rw-r--r--examples/quickcontrols/gallery/gallery.py2
34 files changed, 1336 insertions, 452 deletions
diff --git a/examples/quickcontrols/contactslist/Contact/ContactDelegate.ui.qml b/examples/quickcontrols/contactslist/Contact/ContactDelegate.ui.qml
new file mode 100644
index 000000000..affcccc3e
--- /dev/null
+++ b/examples/quickcontrols/contactslist/Contact/ContactDelegate.ui.qml
@@ -0,0 +1,82 @@
+// 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
+
+ItemDelegate {
+ id: delegate
+
+ checkable: true
+
+ contentItem: ColumnLayout {
+ spacing: 10
+
+ Label {
+ text: fullName
+ font.bold: true
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ }
+
+ GridLayout {
+ id: grid
+ visible: false
+
+ columns: 2
+ rowSpacing: 10
+ columnSpacing: 10
+
+ Label {
+ text: qsTr("Address:")
+ Layout.leftMargin: 60
+ }
+
+ Label {
+ text: address
+ font.bold: true
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("City:")
+ Layout.leftMargin: 60
+ }
+
+ Label {
+ text: city
+ font.bold: true
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("Number:")
+ Layout.leftMargin: 60
+ }
+
+ Label {
+ text: number
+ font.bold: true
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "expanded"
+ when: delegate.checked
+
+ PropertyChanges {
+ // TODO: When Qt Design Studio supports generalized grouped properties, change to:
+ // grid.visible: true
+ target: grid
+ visible: true
+ }
+ }
+ ]
+}
diff --git a/examples/quickcontrols/contactslist/Contact/ContactDialog.qml b/examples/quickcontrols/contactslist/Contact/ContactDialog.qml
new file mode 100644
index 000000000..d906f00e6
--- /dev/null
+++ b/examples/quickcontrols/contactslist/Contact/ContactDialog.qml
@@ -0,0 +1,45 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+Dialog {
+ id: dialog
+
+ signal finished(string fullName, string address, string city, string number)
+
+ function createContact() {
+ form.fullName.clear();
+ form.address.clear();
+ form.city.clear();
+ form.number.clear();
+
+ dialog.title = qsTr("Add Contact");
+ dialog.open();
+ }
+
+ function editContact(contact) {
+ form.fullName.text = contact.fullName;
+ form.address.text = contact.address;
+ form.city.text = contact.city;
+ form.number.text = contact.number;
+
+ dialog.title = qsTr("Edit Contact");
+ dialog.open();
+ }
+
+ x: parent.width / 2 - width / 2
+ y: parent.height / 2 - height / 2
+
+ focus: true
+ modal: true
+ title: qsTr("Add Contact")
+ standardButtons: Dialog.Ok | Dialog.Cancel
+
+ contentItem: ContactForm {
+ id: form
+ }
+
+ onAccepted: finished(form.fullName.text, form.address.text, form.city.text, form.number.text)
+}
diff --git a/examples/quickcontrols/contactslist/Contact/ContactForm.ui.qml b/examples/quickcontrols/contactslist/Contact/ContactForm.ui.qml
new file mode 100644
index 000000000..56c918619
--- /dev/null
+++ b/examples/quickcontrols/contactslist/Contact/ContactForm.ui.qml
@@ -0,0 +1,72 @@
+// 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
+
+GridLayout {
+ id: grid
+ property alias fullName: fullName
+ property alias address: address
+ property alias city: city
+ property alias number: number
+ property int minimumInputSize: 120
+ property string placeholderText: qsTr("<enter>")
+
+ rows: 4
+ columns: 2
+
+ Label {
+ text: qsTr("Full Name")
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline
+ }
+
+ TextField {
+ id: fullName
+ focus: true
+ Layout.fillWidth: true
+ Layout.minimumWidth: grid.minimumInputSize
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline
+ placeholderText: grid.placeholderText
+ }
+
+ Label {
+ text: qsTr("Address")
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline
+ }
+
+ TextField {
+ id: address
+ Layout.fillWidth: true
+ Layout.minimumWidth: grid.minimumInputSize
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline
+ placeholderText: grid.placeholderText
+ }
+
+ Label {
+ text: qsTr("City")
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline
+ }
+
+ TextField {
+ id: city
+ Layout.fillWidth: true
+ Layout.minimumWidth: grid.minimumInputSize
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline
+ placeholderText: grid.placeholderText
+ }
+
+ Label {
+ text: qsTr("Number")
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline
+ }
+
+ TextField {
+ id: number
+ Layout.fillWidth: true
+ Layout.minimumWidth: grid.minimumInputSize
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline
+ placeholderText: grid.placeholderText
+ }
+}
diff --git a/examples/quickcontrols/contactslist/Contact/ContactList.qml b/examples/quickcontrols/contactslist/Contact/ContactList.qml
new file mode 100644
index 000000000..0b7af32b5
--- /dev/null
+++ b/examples/quickcontrols/contactslist/Contact/ContactList.qml
@@ -0,0 +1,70 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: window
+
+ property int currentContact: -1
+
+ width: 320
+ height: 480
+ visible: true
+ title: qsTr("Contact List")
+
+ ContactDialog {
+ id: contactDialog
+ onFinished: function(fullName, address, city, number) {
+ if (currentContact == -1)
+ contactView.model.append(fullName, address, city, number)
+ else
+ contactView.model.set(currentContact, fullName, address, city, number)
+ }
+ }
+
+ Menu {
+ id: contactMenu
+ x: parent.width / 2 - width / 2
+ y: parent.height / 2 - height / 2
+ modal: true
+
+ Label {
+ padding: 10
+ font.bold: true
+ width: parent.width
+ horizontalAlignment: Qt.AlignHCenter
+ text: currentContact >= 0 ? contactView.model.get(currentContact).fullName : ""
+ }
+ MenuItem {
+ text: qsTr("Edit...")
+ onTriggered: contactDialog.editContact(contactView.model.get(currentContact))
+ }
+ MenuItem {
+ text: qsTr("Remove")
+ onTriggered: contactView.model.remove(currentContact)
+ }
+ }
+
+ ContactView {
+ id: contactView
+ anchors.fill: parent
+ onPressAndHold: {
+ currentContact = index
+ contactMenu.open()
+ }
+ }
+
+ RoundButton {
+ text: qsTr("+")
+ highlighted: true
+ anchors.margins: 10
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ onClicked: {
+ currentContact = -1
+ contactDialog.createContact()
+ }
+ }
+}
diff --git a/examples/quickcontrols/contactslist/Contact/ContactView.ui.qml b/examples/quickcontrols/contactslist/Contact/ContactView.ui.qml
new file mode 100644
index 000000000..3b82b681e
--- /dev/null
+++ b/examples/quickcontrols/contactslist/Contact/ContactView.ui.qml
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import Backend
+
+ListView {
+ id: listView
+
+ signal pressAndHold(int index)
+
+ width: 320
+ height: 480
+
+ focus: true
+ boundsBehavior: Flickable.StopAtBounds
+
+ section.property: "fullName"
+ section.criteria: ViewSection.FirstCharacter
+ section.delegate: SectionDelegate {
+ width: listView.width
+ }
+
+ delegate: ContactDelegate {
+ id: delegate
+ width: listView.width
+ onPressAndHold: listView.pressAndHold(index)
+ }
+
+ model: ContactModel {
+ id: contactModel
+ }
+
+ ScrollBar.vertical: ScrollBar { }
+}
diff --git a/examples/quickcontrols/contactslist/Contact/SectionDelegate.ui.qml b/examples/quickcontrols/contactslist/Contact/SectionDelegate.ui.qml
new file mode 100644
index 000000000..3a62409a8
--- /dev/null
+++ b/examples/quickcontrols/contactslist/Contact/SectionDelegate.ui.qml
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ToolBar {
+ id: background
+
+ Label {
+ id: label
+ text: section
+ anchors.fill: parent
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ }
+}
diff --git a/examples/quickcontrols/contactslist/Contact/qmldir b/examples/quickcontrols/contactslist/Contact/qmldir
new file mode 100644
index 000000000..339d45a1d
--- /dev/null
+++ b/examples/quickcontrols/contactslist/Contact/qmldir
@@ -0,0 +1,7 @@
+module Contact
+ContactList 1.0 ContactList.qml
+ContactDialog 1.0 ContactDialog.qml
+ContactDelegate 1.0 ContactDelegate.ui.qml
+ContactForm 1.0 ContactForm.ui.qml
+ContactView 1.0 ContactView.ui.qml
+SectionDelegate 1.0 SectionDelegate.ui.qml
diff --git a/examples/quickcontrols/contactslist/contactlist.pyproject b/examples/quickcontrols/contactslist/contactlist.pyproject
new file mode 100644
index 000000000..75b0bd693
--- /dev/null
+++ b/examples/quickcontrols/contactslist/contactlist.pyproject
@@ -0,0 +1,10 @@
+{
+ "files": ["main.py",
+ "contactmodel.py",
+ "Contact/ContactDialog.qml",
+ "Contact/ContactDelegate.ui.qml",
+ "Contact/ContactForm.ui.qml",
+ "Contact/ContactList.qml",
+ "Contact/ContactView.ui.qml",
+ "Contact/SectionDelegate.ui.qml"]
+}
diff --git a/examples/quickcontrols/contactslist/contactmodel.py b/examples/quickcontrols/contactslist/contactmodel.py
new file mode 100644
index 000000000..5d2746c2e
--- /dev/null
+++ b/examples/quickcontrols/contactslist/contactmodel.py
@@ -0,0 +1,116 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import bisect
+from dataclasses import dataclass
+from enum import IntEnum
+
+from PySide6.QtCore import (QAbstractListModel, QEnum, Qt, QModelIndex, Slot,
+ QByteArray)
+from PySide6.QtQml import QmlElement
+
+QML_IMPORT_NAME = "Backend"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class ContactModel(QAbstractListModel):
+
+ @QEnum
+ class ContactRole(IntEnum):
+ FullNameRole = Qt.DisplayRole
+ AddressRole = Qt.UserRole
+ CityRole = Qt.UserRole + 1
+ NumberRole = Qt.UserRole + 2
+
+ @dataclass
+ class Contact:
+ fullName: str
+ address: str
+ city: str
+ number: str
+
+ def __init__(self, parent=None) -> None:
+ super().__init__(parent)
+ self.m_contacts = []
+ self.m_contacts.append(self.Contact("Angel Hogan", "Chapel St. 368 ", "Clearwater",
+ "0311 1823993"))
+ self.m_contacts.append(self.Contact("Felicia Patton", "Annadale Lane 2", "Knoxville",
+ "0368 1244494"))
+ self.m_contacts.append(self.Contact("Grant Crawford", "Windsor Drive 34", "Riverdale",
+ "0351 7826892"))
+ self.m_contacts.append(self.Contact("Gretchen Little", "Sunset Drive 348", "Virginia Beach",
+ "0343 1234991"))
+ self.m_contacts.append(self.Contact("Geoffrey Richards", "University Lane 54", "Trussville",
+ "0423 2144944"))
+ self.m_contacts.append(self.Contact("Henrietta Chavez", "Via Volto San Luca 3",
+ "Piobesi Torinese", "0399 2826994"))
+ self.m_contacts.append(self.Contact("Harvey Chandler", "North Squaw Creek 11",
+ "Madisonville", "0343 1244492"))
+ self.m_contacts.append(self.Contact("Miguel Gomez", "Wild Rose Street 13", "Trussville",
+ "0343 9826996"))
+ self.m_contacts.append(self.Contact("Norma Rodriguez", " Glen Eagles Street 53",
+ "Buffalo", "0241 5826596"))
+ self.m_contacts.append(self.Contact("Shelia Ramirez", "East Miller Ave 68", "Pickerington",
+ "0346 4844556"))
+ self.m_contacts.append(self.Contact("Stephanie Moss", "Piazza Trieste e Trento 77",
+ "Roata Chiusani", "0363 0510490"))
+
+ def rowCount(self, parent=QModelIndex()):
+ return len(self.m_contacts)
+
+ def data(self, index: QModelIndex, role: int):
+ row = index.row()
+ if row < self.rowCount():
+ if role == ContactModel.ContactRole.FullNameRole:
+ return self.m_contacts[row].fullName
+ elif role == ContactModel.ContactRole.AddressRole:
+ return self.m_contacts[row].address
+ elif role == ContactModel.ContactRole.CityRole:
+ return self.m_contacts[row].city
+ elif role == ContactModel.ContactRole.NumberRole:
+ return self.m_contacts[row].number
+
+ def roleNames(self):
+ default = super().roleNames()
+ default[ContactModel.ContactRole.FullNameRole] = QByteArray(b"fullName")
+ default[ContactModel.ContactRole.AddressRole] = QByteArray(b"address")
+ default[ContactModel.ContactRole.CityRole] = QByteArray(b"city")
+ default[ContactModel.ContactRole.NumberRole] = QByteArray(b"number")
+ return default
+
+ @Slot(int)
+ def get(self, row: int):
+ contact = self.m_contacts[row]
+ return {"fullName": contact.fullName, "address": contact.address,
+ "city": contact.city, "number": contact.number}
+
+ @Slot(str, str, str, str)
+ def append(self, full_name: str, address: str, city: str, number: str):
+ contact = self.Contact(full_name, address, city, number)
+ contact_names = [contact.fullName for contact in self.m_contacts]
+ index = bisect.bisect(contact_names, contact.fullName)
+ self.beginInsertRows(QModelIndex(), index, index)
+ self.m_contacts.insert(index, contact)
+ self.endInsertRows()
+
+ @Slot(int, str, str, str, str)
+ def set(self, row: int, full_name: str, address: str, city: str, number: str):
+ if row < 0 or row >= len(self.m_contacts):
+ return
+
+ self.m_contacts[row] = self.Contact(full_name, address, city, number)
+ self.dataChanged(self.index(row, 0), self.index(row, 0),
+ [ContactModel.ContactRole.FullNameRole,
+ ContactModel.ContactRole.AddressRole,
+ ContactModel.ContactRole.CityRole,
+ ContactModel.ContactRole.NumberRole])
+
+ @Slot(int)
+ def remove(self, row):
+ if row < 0 or row >= len(self.m_contacts):
+ return
+
+ self.beginRemoveRows(QModelIndex(), row, row)
+ del self.m_contacts[row]
+ self.endRemoveRows()
diff --git a/examples/quickcontrols/contactslist/doc/contactslist.rst b/examples/quickcontrols/contactslist/doc/contactslist.rst
new file mode 100644
index 000000000..b5540e39b
--- /dev/null
+++ b/examples/quickcontrols/contactslist/doc/contactslist.rst
@@ -0,0 +1,15 @@
+Qt Quick Controls - Contact List
+================================
+
+.. tags:: Android
+
+A QML app using Qt Quick Controls and a Python class that implements a simple
+contact list. This example can also be deployed to Android using
+**pyside6-android-deploy**
+
+A PySide6 application that demonstrates the analogous example in Qt
+`ContactsList <https://doc.qt.io/qt-6.6/qtquickcontrols-contactlist-example.html>`_
+
+.. image:: qtquickcontrols-contactlist.png
+ :width: 400
+ :alt: ContactList Screenshot
diff --git a/examples/quickcontrols/contactslist/doc/qtquickcontrols-contactlist.png b/examples/quickcontrols/contactslist/doc/qtquickcontrols-contactlist.png
new file mode 100644
index 000000000..9f1c30654
--- /dev/null
+++ b/examples/quickcontrols/contactslist/doc/qtquickcontrols-contactlist.png
Binary files differ
diff --git a/examples/quickcontrols/contactslist/main.py b/examples/quickcontrols/contactslist/main.py
new file mode 100644
index 000000000..d501bbdb4
--- /dev/null
+++ b/examples/quickcontrols/contactslist/main.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""
+PySide6 port of Qt Quick Controls Contact List example from Qt v6.x
+"""
+import sys
+from pathlib import Path
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQml import QQmlApplicationEngine
+
+from contactmodel import ContactModel # noqa: F401
+
+if __name__ == '__main__':
+ app = QGuiApplication(sys.argv)
+ app.setOrganizationName("QtProject")
+ app.setApplicationName("ContactsList")
+ engine = QQmlApplicationEngine()
+
+ engine.addImportPath(Path(__file__).parent)
+ engine.loadFromModule("Contact", "ContactList")
+
+ if not engine.rootObjects():
+ sys.exit(-1)
+
+ ex = app.exec()
+ del engine
+ sys.exit(ex)
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/Main.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/Main.qml
index 4dfc1590d..7f7798ed8 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/Main.qml
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/Main.qml
@@ -6,46 +6,68 @@ import QtQuick.Controls.Basic
import QtQuick.Layouts
import FileSystemModule
+pragma ComponentBehavior: Bound
+
ApplicationWindow {
id: root
+
+ property bool expandPath: false
+ property bool showLineNumbers: true
+ property string currentFilePath: ""
+
width: 1100
height: 600
+ minimumWidth: 200
+ minimumHeight: 100
visible: true
+ color: Colors.background
flags: Qt.Window | Qt.FramelessWindowHint
- title: qsTr("Qt Quick Controls - File System Explorer")
+ title: qsTr("File System Explorer Example")
- property string currentFilePath: ""
- property bool expandPath: false
+ function getInfoText() : string {
+ let out = root.currentFilePath
+ if (!out)
+ return qsTr("File System Explorer")
+ return root.expandPath ? out : out.substring(out.lastIndexOf("/") + 1, out.length)
+ }
menuBar: MyMenuBar {
- rootWindow: root
-
- infoText: currentFilePath
- ? (expandPath ? currentFilePath
- : currentFilePath.substring(currentFilePath.lastIndexOf("/") + 1, currentFilePath.length))
- : "File System Explorer"
-
+ dragWindow: root
+ infoText: root.getInfoText()
MyMenu {
title: qsTr("File")
Action {
text: qsTr("Increase Font")
- shortcut: "Ctrl++"
- onTriggered: textArea.font.pixelSize += 1
+ shortcut: StandardKey.ZoomIn
+ onTriggered: editor.text.font.pixelSize += 1
}
Action {
text: qsTr("Decrease Font")
- shortcut: "Ctrl+-"
- onTriggered: textArea.font.pixelSize -= 1
+ shortcut: StandardKey.ZoomOut
+ onTriggered: editor.text.font.pixelSize -= 1
}
Action {
- text: expandPath ? qsTr("Toggle Short Path") : qsTr("Toggle Expand Path")
- enabled: currentFilePath
- onTriggered: expandPath = !expandPath
+ text: root.showLineNumbers ? qsTr("Toggle Line Numbers OFF")
+ : qsTr("Toggle Line Numbers ON")
+ shortcut: "Ctrl+L"
+ onTriggered: root.showLineNumbers = !root.showLineNumbers
+ }
+ Action {
+ text: root.expandPath ? qsTr("Toggle Short Path")
+ : qsTr("Toggle Expand Path")
+ enabled: root.currentFilePath
+ onTriggered: root.expandPath = !root.expandPath
+ }
+ Action {
+ text: qsTr("Reset Filesystem")
+ enabled: sidebar.currentTabIndex === 1
+ onTriggered: fileSystemView.rootIndex = undefined
}
Action {
text: qsTr("Exit")
onTriggered: Qt.exit(0)
+ shortcut: StandardKey.Quit
}
}
@@ -55,134 +77,109 @@ ApplicationWindow {
Action {
text: qsTr("Cut")
shortcut: StandardKey.Cut
- enabled: textArea.selectedText.length > 0
- onTriggered: textArea.cut()
+ enabled: editor.text.selectedText.length > 0
+ onTriggered: editor.text.cut()
}
Action {
text: qsTr("Copy")
shortcut: StandardKey.Copy
- enabled: textArea.selectedText.length > 0
- onTriggered: textArea.copy()
+ enabled: editor.text.selectedText.length > 0
+ onTriggered: editor.text.copy()
}
Action {
text: qsTr("Paste")
shortcut: StandardKey.Paste
- enabled: textArea.canPaste
- onTriggered: textArea.paste()
+ enabled: editor.text.canPaste
+ onTriggered: editor.text.paste()
}
Action {
text: qsTr("Select All")
shortcut: StandardKey.SelectAll
- enabled: textArea.length > 0
- onTriggered: textArea.selectAll()
+ enabled: editor.text.length > 0
+ onTriggered: editor.text.selectAll()
}
Action {
text: qsTr("Undo")
shortcut: StandardKey.Undo
- enabled: textArea.canUndo
- onTriggered: textArea.undo()
+ enabled: editor.text.canUndo
+ onTriggered: editor.text.undo()
}
}
}
-
- Rectangle {
+ // Set up the layout of the main components in a row:
+ // [ Sidebar, Navigation, Editor ]
+ RowLayout {
anchors.fill: parent
- color: Colors.background
-
- RowLayout {
- anchors.fill: parent
- spacing: 0
-
- // Stores the buttons that navigate the application.
- Sidebar {
- id: sidebar
- rootWindow: root
-
- Layout.preferredWidth: 60
- Layout.fillHeight: true
- }
+ spacing: 0
+
+ // Stores the buttons that navigate the application.
+ Sidebar {
+ id: sidebar
+ dragWindow: root
+ Layout.preferredWidth: 50
+ 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
- }
+ // Allows resizing parts of the UI.
+ SplitView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ // Customized handle to drag between the Navigation and the Editor.
+ handle: Rectangle {
+ implicitWidth: 10
+ color: SplitHandle.pressed ? Colors.color2 : Colors.background
+ border.color: SplitHandle.hovered ? Colors.color2 : Colors.background
+ opacity: SplitHandle.hovered || navigationView.width < 15 ? 1.0 : 0.0
+
+ Behavior on opacity {
+ OpacityAnimator {
+ duration: 1400
}
}
+ }
- // 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 {
- color: Colors.surface1
-
- SplitView.preferredWidth: 250
- SplitView.fillHeight: true
-
- StackLayout {
- currentIndex: 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
- }
+ Rectangle {
+ id: navigationView
+ color: Colors.surface1
+ SplitView.preferredWidth: 250
+ SplitView.fillHeight: true
+ // The stack-layout provides different views, based on the
+ // selected buttons inside the sidebar.
+ StackLayout {
+ anchors.fill: parent
+ currentIndex: sidebar.currentTabIndex
+
+ // Shows the help text.
+ Text {
+ 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
+ color: Colors.text
}
- }
-
- // The ScrollView that contains the TextArea which shows the file's content.
- ScrollView {
- leftPadding: 20
- topPadding: 20
- bottomPadding: 20
- clip: true
-
- SplitView.fillWidth: true
- SplitView.fillHeight: true
-
- property alias textArea: textArea
- MyTextArea {
- id: textArea
- text: FileSystemModel.readFile(root.currentFilePath)
+ // Shows the files on the file system.
+ FileSystemView {
+ id: fileSystemView
+ color: Colors.surface1
+ onFileClicked: path => root.currentFilePath = path
}
}
}
+
+ // The main view that contains the editor.
+ Editor {
+ id: editor
+ showLineNumbers: root.showLineNumbers
+ currentFilePath: root.currentFilePath
+ SplitView.fillWidth: true
+ SplitView.fillHeight: true
+ }
}
- ResizeButton {}
+ }
+
+ ResizeButton {
+ resizeWindow: root
}
}
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/app.qrc b/examples/quickcontrols/filesystemexplorer/FileSystemModule/app.qrc
index 05fc728e7..fec76fe67 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/app.qrc
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/app.qrc
@@ -3,9 +3,9 @@
<file>qmldir</file>
<file>Main.qml</file>
<file>qml/About.qml</file>
+ <file>qml/Editor.qml</file>
<file>qml/Colors.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>
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons.qrc b/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons.qrc
index 5793a62cf..97d8a3d79 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons.qrc
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons.qrc
@@ -1,5 +1,6 @@
<RCC>
<qresource>
+ <file>icons/app_icon.svg</file>
<file>icons/folder_closed.svg</file>
<file>icons/folder_open.svg</file>
<file>icons/generic_file.svg</file>
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons/app_icon.svg b/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons/app_icon.svg
new file mode 100644
index 000000000..5aae4221f
--- /dev/null
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons/app_icon.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="#EBDBB2" d="M13.25 8.5a.75.75 0 1 1-.75-.75.75.75 0 0 1 .75.75zM9.911 21.35l.816.578C10.819 21.798 13 18.666 13 13h-1a15.503 15.503 0 0 1-2.089 8.35zM4 6.703V10a2.002 2.002 0 0 1-2 2v1a2.002 2.002 0 0 1 2 2v3.297A3.707 3.707 0 0 0 7.703 22H9v-1H7.703A2.706 2.706 0 0 1 5 18.297V15a2.999 2.999 0 0 0-1.344-2.5A2.999 2.999 0 0 0 5 10V6.703A2.706 2.706 0 0 1 7.703 4H9V3H7.703A3.707 3.707 0 0 0 4 6.703zM20 10V6.703A3.707 3.707 0 0 0 16.297 3H15v1h1.297A2.706 2.706 0 0 1 19 6.703V10a2.999 2.999 0 0 0 1.344 2.5A2.999 2.999 0 0 0 19 15v3.297A2.706 2.706 0 0 1 16.297 21H15v1h1.297A3.707 3.707 0 0 0 20 18.297V15a2.002 2.002 0 0 1 2-2v-1a2.002 2.002 0 0 1-2-2z"/><path fill="none" d="M0 0h24v24H0z"/></svg>
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml
index b7bc0ac6f..178bf03e4 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml
@@ -7,53 +7,87 @@ import FileSystemModule
ApplicationWindow {
id: root
- width: 500
- height: 360
+ width: 650
+ height: 550
flags: Qt.Window | Qt.FramelessWindowHint
color: Colors.surface1
menuBar: MyMenuBar {
id: menuBar
- implicitHeight: 20
- rootWindow: root
+
+ dragWindow: root
+ implicitHeight: 27
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)
+ sourceSize.width: 80
+ sourceSize.height: 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"
- }
+ ScrollView {
+ anchors.top: logo.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.margins: 20
+
+ TextArea {
+ selectedTextColor: Colors.textFile
+ selectionColor: Colors.selection
+ horizontalAlignment: Text.AlignHCenter
+ textFormat: Text.RichText
+
+ text: qsTr("<h3>About Qt</h3>"
+ + "<p>This program uses Qt version %1.</p>"
+ + "<p>Qt is a C++ toolkit for cross-platform application "
+ + "development.</p>"
+ + "<p>Qt provides single-source portability across all major desktop "
+ + "operating systems. It is also available for embedded Linux and other "
+ + "embedded and mobile operating systems.</p>"
+ + "<p>Qt is available under multiple licensing options designed "
+ + "to accommodate the needs of our various users.</p>"
+ + "<p>Qt licensed under our commercial license agreement is appropriate "
+ + "for development of proprietary/commercial software where you do not "
+ + "want to share any source code with third parties or otherwise cannot "
+ + "comply with the terms of GNU (L)GPL.</p>"
+ + "<p>Qt licensed under GNU (L)GPL is appropriate for the "
+ + "development of Qt&nbsp;applications provided you can comply with the terms "
+ + "and conditions of the respective licenses.</p>"
+ + "<p>Please see <a href=\"http://%2/\">%2</a> "
+ + "for an overview of Qt licensing.</p>"
+ + "<p>Copyright (C) %3 The Qt Company Ltd and other "
+ + "contributors.</p>"
+ + "<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>"
+ + "<p>Qt is The Qt Company Ltd product developed as an open source "
+ + "project. See <a href=\"http://%4/\">%4</a> for more information.</p>")
+ .arg(Application.version).arg("qt.io/licensing").arg("2023").arg("qt.io")
+ color: Colors.textFile
+ wrapMode: Text.WordWrap
+ readOnly: true
+ antialiasing: true
+ background: null
+
+ onLinkActivated: function(link) {
+ Qt.openUrlExternally(link)
+ }
+ }
+ }
+
+ ResizeButton {
+ resizeWindow: root
}
- ResizeButton {}
}
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml
index 280f89286..285667773 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml
@@ -1,22 +1,23 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-pragma Singleton
import QtQuick
+pragma Singleton
+
QtObject {
- readonly property color background: "#23272E"
- readonly property color surface1: "#1E2227"
+ readonly property color background: "#292828"
+ readonly property color surface1: "#171819"
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"
+ readonly property color text: "#D4BE98"
+ readonly property color textFile: "#E1D2B7"
+ readonly property color disabledText: "#2C313A"
+ readonly property color selection: "#4B4A4A"
+ readonly property color active: "#292828"
+ readonly property color inactive: "#383737"
+ readonly property color folder: "#383737"
+ readonly property color icon: "#383737"
+ readonly property color iconIndicator: "#D5B35D"
+ readonly property color color1: "#A7B464"
+ readonly property color color2: "#D3869B"
}
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml
new file mode 100644
index 000000000..80f7c04c5
--- /dev/null
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml
@@ -0,0 +1,160 @@
+// 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
+
+pragma ComponentBehavior: Bound
+
+// This is the text editor that displays the currently open file, including
+// their corresponding line numbers.
+Rectangle {
+ id: root
+
+ required property string currentFilePath
+ required property bool showLineNumbers
+ property alias text: textArea
+ property int currentLineNumber: -1
+ property int rowHeight: Math.ceil(fontMetrics.lineSpacing)
+
+ color: Colors.background
+
+ onWidthChanged: textArea.update()
+ onHeightChanged: textArea.update()
+
+ RowLayout {
+ anchors.fill: parent
+ // We use a flickable to synchronize the position of the editor and
+ // the line numbers. This is necessary because the line numbers can
+ // extend the available height.
+ Flickable {
+ id: lineNumbers
+
+ // Calculate the width based on the logarithmic scale.
+ Layout.preferredWidth: fontMetrics.averageCharacterWidth
+ * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
+ Layout.fillHeight: true
+
+ interactive: false
+ contentY: editorFlickable.contentY
+ visible: textArea.text !== "" && root.showLineNumbers
+
+ Column {
+ anchors.fill: parent
+ Repeater {
+ id: repeatedLineNumbers
+
+ model: LineNumberModel {
+ lineCount: textArea.text !== "" ? textArea.lineCount : 0
+ }
+
+ delegate: Item {
+ required property int index
+
+ width: parent.width
+ height: root.rowHeight
+ Label {
+ id: numbers
+
+ text: parent.index + 1
+
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ color: (root.currentLineNumber === parent.index)
+ ? Colors.iconIndicator : Qt.darker(Colors.text, 2)
+ font: textArea.font
+ }
+ Rectangle {
+ id: indicator
+
+ anchors.left: numbers.right
+ width: 1
+ height: parent.height
+ color: Qt.darker(Colors.text, 3)
+ }
+ }
+ }
+ }
+ }
+
+ Flickable {
+ id: editorFlickable
+
+ property alias textArea: textArea
+
+ // We use an inline component to customize the horizontal and vertical
+ // scroll-bars. This is convenient when the component is only used in one file.
+ component MyScrollBar: ScrollBar {
+ id: scrollBar
+ background: Rectangle {
+ implicitWidth: scrollBar.interactive ? 8 : 4
+ implicitHeight: scrollBar.interactive ? 8 : 4
+
+ opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0
+ color: Colors.background
+ Behavior on opacity {
+ OpacityAnimator {
+ duration: 500
+ }
+ }
+ }
+ contentItem: Rectangle {
+ implicitWidth: scrollBar.interactive ? 8 : 4
+ implicitHeight: scrollBar.interactive ? 8 : 4
+ opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0
+ color: Colors.color1
+ Behavior on opacity {
+ OpacityAnimator {
+ duration: 1000
+ }
+ }
+ }
+ }
+
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ ScrollBar.horizontal: MyScrollBar {}
+ ScrollBar.vertical: MyScrollBar {}
+
+ boundsBehavior: Flickable.StopAtBounds
+
+ TextArea.flickable: TextArea {
+ id: textArea
+ anchors.fill: parent
+
+ focus: false
+ topPadding: 0
+ leftPadding: 10
+
+ text: FileSystemModel.readFile(root.currentFilePath)
+ tabStopDistance: fontMetrics.averageCharacterWidth * 4
+
+ // Grab the current line number from the C++ interface.
+ onCursorPositionChanged: {
+ root.currentLineNumber = FileSystemModel.currentLineNumber(
+ textArea.textDocument, textArea.cursorPosition)
+ }
+
+ color: Colors.textFile
+ selectedTextColor: Colors.textFile
+ selectionColor: Colors.selection
+
+ textFormat: TextEdit.PlainText
+ renderType: Text.QtRendering
+ selectByMouse: true
+ antialiasing: true
+ background: null
+ }
+
+ FontMetrics {
+ id: fontMetrics
+ font: textArea.font
+ }
+ }
+ }
+}
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml
index ade2e48c1..db955168c 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml
@@ -2,26 +2,31 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Layouts
+import QtQuick.Effects
import QtQuick.Controls.Basic
import FileSystemModule
+pragma ComponentBehavior: Bound
+
// This is the file system view which gets populated by the C++ model.
Rectangle {
id: root
signal fileClicked(string filePath)
+ property alias rootIndex: fileSystemTreeView.rootIndex
TreeView {
id: fileSystemTreeView
+
+ property int lastIndex: -1
+
anchors.fill: parent
model: FileSystemModel
+ rootIndex: FileSystemModel.rootIndex
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.
@@ -31,50 +36,101 @@ Rectangle {
implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250
implicitHeight: 25
+ // Since we have the 'ComponentBehavior Bound' pragma, we need to
+ // require these properties from our model. This is a convenient way
+ // to bind the properties provided by the model's role names.
required property int index
required property url filePath
+ required property string fileName
- indicator: null
-
- contentItem: Item {
- anchors.fill: parent
+ indicator: Image {
+ id: directoryIcon
- Icon {
- id: directoryIcon
- x: leftMargin + (depth * indentation)
- anchors.verticalCenter: parent.verticalCenter
- path: treeDelegate.hasChildren
- ? (treeDelegate.expanded ? "../icons/folder_open.svg" : "../icons/folder_closed.svg")
+ x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation)
+ anchors.verticalCenter: parent.verticalCenter
+ source: 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
- }
+ sourceSize.width: 20
+ sourceSize.height: 20
+ fillMode: Image.PreserveAspectFit
+
+ smooth: true
+ antialiasing: true
+ asynchronous: true
+ }
+
+ contentItem: Text {
+ text: treeDelegate.fileName
+ color: Colors.text
}
background: Rectangle {
- color: treeDelegate.index === fileSystemTreeView.lastIndex
+ 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)
+ // We color the directory icons with this MultiEffect, where we overlay
+ // the colorization color ontop of the SVG icons.
+ MultiEffect {
+ id: iconOverlay
+
+ anchors.fill: directoryIcon
+ source: directoryIcon
+ colorization: 1.0
+ brightness: 1.0
+ colorizationColor: {
+ const isFile = treeDelegate.index === fileSystemTreeView.lastIndex
+ && !treeDelegate.hasChildren;
+ if (isFile)
+ return Qt.lighter(Colors.folder, 3)
+
+ const isExpandedFolder = treeDelegate.expanded && treeDelegate.hasChildren;
+ if (isExpandedFolder)
+ return Colors.color2
+ else
+ return Colors.folder
}
}
+
HoverHandler {
id: hoverHandler
}
+
+ TapHandler {
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onSingleTapped: (eventPoint, button) => {
+ switch (button) {
+ case Qt.LeftButton:
+ fileSystemTreeView.toggleExpanded(treeDelegate.row)
+ fileSystemTreeView.lastIndex = treeDelegate.index
+ // If this model item doesn't have children, it means it's
+ // representing a file.
+ if (!treeDelegate.hasChildren)
+ root.fileClicked(treeDelegate.filePath)
+ break;
+ case Qt.RightButton:
+ if (treeDelegate.hasChildren)
+ contextMenu.popup();
+ break;
+ }
+ }
+ }
+
+ MyMenu {
+ id: contextMenu
+ Action {
+ text: qsTr("Set as root index")
+ onTriggered: {
+ fileSystemTreeView.rootIndex = fileSystemTreeView.index(treeDelegate.row, 0)
+ }
+ }
+ Action {
+ text: qsTr("Reset root index")
+ onTriggered: fileSystemTreeView.rootIndex = undefined
+ }
+ }
}
// Provide our own custom ScrollIndicator for the TreeView.
@@ -85,6 +141,7 @@ Rectangle {
contentItem: Rectangle {
implicitWidth: 6
implicitHeight: 6
+
color: Colors.color1
opacity: fileSystemTreeView.movingVertically ? 0.5 : 0.0
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Icon.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Icon.qml
deleted file mode 100644
index 25162d9d3..000000000
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Icon.qml
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml
index 99795b5e5..1f1d30c56 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml
@@ -8,35 +8,38 @@ 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 {
+ id: indicator
+
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
width: 6
height: parent.height
+
visible: menuItem.highlighted
color: Colors.color2
}
}
background: Rectangle {
+ implicitWidth: 210
+ implicitHeight: 35
color: menuItem.highlighted ? Colors.active : "transparent"
}
}
+ background: Rectangle {
+ implicitWidth: 210
+ implicitHeight: 35
+ color: Colors.surface2
+ }
}
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml
index a2a3fea88..4874a2c03 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml
@@ -6,130 +6,172 @@ 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.
+// The MenuBar also serves as a controller for our window as we don't use any decorations.
MenuBar {
id: root
- required property ApplicationWindow rootWindow
+ required property ApplicationWindow dragWindow
property alias infoText: windowInfo.text
- implicitHeight: 25
-
- // The top level menus on the left side
+ // Customization of the top level menus inside the MenuBar
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
+ elide: Text.ElideRight
+ color: menuBarItem.highlighted ? Colors.textFile : Colors.text
+ opacity: enabled ? 1.0 : 0.3
}
background: Rectangle {
+ id: background
+
color: menuBarItem.highlighted ? Colors.selection : "transparent"
Rectangle {
id: indicator
+
width: 0; height: 3
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
- color: Colors.color1
+ color: Colors.color1
states: State {
- name: "active"; when: menuBarItem.highlighted
- PropertyChanges { target: indicator; width: parent.width }
+ name: "active"
+ when: menuBarItem.highlighted
+ PropertyChanges {
+ indicator.width: background.width - 2
+ }
}
-
transitions: Transition {
NumberAnimation {
properties: "width"
- duration: 300
+ duration: 175
}
}
-
}
}
}
+ // We use the contentItem property as a place to attach our window decorations. Beneath
+ // the usual menu entries within a MenuBar, it includes a centered information text, along
+ // with the minimize, maximize, and close buttons.
+ contentItem: RowLayout {
+ id: windowBar
- // 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 }
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ spacing: root.spacing
+ Repeater {
+ id: menuBarItems
- Text {
- id: windowInfo
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.verticalCenter: parent.verticalCenter
- color: Colors.text
+ Layout.alignment: Qt.AlignLeft
+ model: root.contentModel
}
- component InteractionButton: Rectangle {
- signal action;
- property alias hovered: hoverHandler.hovered
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Text {
+ id: windowInfo
+
+ width: parent.width; height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ leftPadding: windowActions.width
+ color: Colors.text
+ clip: true
+ }
+ }
- width: root.height
- anchors.top: parent.top
- anchors.bottom: parent.bottom
- color: hovered ? Colors.background : "transparent"
+ RowLayout {
+ id: windowActions
- HoverHandler { id: hoverHandler }
- TapHandler { onTapped: action() }
- }
+ Layout.alignment: Qt.AlignRight
+ Layout.fillHeight: true
- InteractionButton {
- id: minimize
+ spacing: 0
- anchors.right: maximize.left
- onAction: rootWindow.showMinimized()
- Rectangle {
- width: parent.height - 10; height: 2
- anchors.centerIn: parent
- color: parent.hovered ? Colors.iconIndicator : Colors.icon
+ component InteractionButton: Rectangle {
+ id: interactionButton
+
+ signal action()
+ property alias hovered: hoverHandler.hovered
+
+ Layout.fillHeight: true
+ Layout.preferredWidth: height
+
+ color: hovered ? Colors.background : "transparent"
+ HoverHandler {
+ id: hoverHandler
+ }
+ TapHandler {
+ id: tapHandler
+ onTapped: interactionButton.action()
+ }
}
- }
- InteractionButton {
- id: maximize
+ InteractionButton {
+ id: minimize
- 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
+ onAction: root.dragWindow.showMinimized()
+ Rectangle {
+ anchors.centerIn: parent
+ color: parent.hovered ? Colors.iconIndicator : Colors.icon
+ height: 2
+ width: parent.height - 14
+ }
}
- }
- InteractionButton {
- id: close
+ InteractionButton {
+ id: maximize
- 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
+ onAction: root.dragWindow.showMaximized()
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 7
+ border.color: parent.hovered ? Colors.iconIndicator : Colors.icon
+ border.width: 2
+ color: "transparent"
+ }
+ }
+
+ InteractionButton {
+ id: close
+
+ color: hovered ? "#ec4143" : "transparent"
+ onAction: root.dragWindow.close()
Rectangle {
- width: parent.height
- height: parent.width
anchors.centerIn: parent
- color: parent.color
+ width: parent.height - 8; height: 2
+
+ rotation: 45
antialiasing: true
+ transformOrigin: Item.Center
+ color: parent.hovered ? Colors.iconIndicator : Colors.icon
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: parent.height
+ height: parent.width
+
+ antialiasing: true
+ color: parent.color
+ }
}
}
}
}
+ background: Rectangle {
+ color: Colors.surface2
+ // Make the empty space drag the specified root window.
+ WindowDragHandler {
+ dragWindow: root.dragWindow
+ }
+ }
}
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml
index eb2e5bc02..0df65bf82 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml
@@ -5,6 +5,8 @@ import QtQuick.Controls
import FileSystemModule
Button {
+ required property ApplicationWindow resizeWindow
+
icon.width: 20; icon.height: 20
anchors.right: parent.right
anchors.bottom: parent.bottom
@@ -12,12 +14,10 @@ Button {
bottomPadding: 3
icon.source: "../icons/resize.svg"
- icon.color: down || checked ? Colors.iconIndicator : Colors.icon
+ icon.color: hovered ? Colors.iconIndicator : Colors.icon
+ background: null
checkable: false
display: AbstractButton.IconOnly
- background: null
- onPressed: {
- root.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
- }
+ onPressed: resizeWindow.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
}
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml
index 9d08562d9..aac530394 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml
@@ -8,77 +8,92 @@ import FileSystemModule
Rectangle {
id: root
+
+ property alias currentTabIndex: topBar.currentIndex
+ required property ApplicationWindow dragWindow
+ readonly property int tabBarSpacing: 10
+
color: Colors.surface2
- required property ApplicationWindow rootWindow
- property alias currentTabIndex: tabBar.currentIndex
+ component SidebarEntry: Button {
+ id: sidebarButton
- ColumnLayout {
- anchors.fill: root
- anchors.topMargin: 10
- anchors.bottomMargin: 10
- spacing: 10
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
- // TabBar is designed to be horizontal, whereas we need a vertical bar.
- // We can easily achieve that by using a Container.
- Container {
- id: tabBar
+ icon.color: down || checked ? Colors.iconIndicator : Colors.icon
+ icon.width: 27
+ icon.height: 27
- Layout.fillWidth: true
+ topPadding: 0
+ rightPadding: 0
+ bottomPadding: 0
+ leftPadding: 0
+ background: null
- // 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)))
- }
+ Rectangle {
+ id: indicator
- contentItem: ColumnLayout {
- spacing: tabBar.spacing
+ anchors.verticalCenter: parent.verticalCenter
+ x: 2
+ width: 4
+ height: sidebarButton.icon.height * 1.2
- Repeater {
- model: tabBar.contentModel
- }
- }
+ visible: sidebarButton.checked
+ color: Colors.color1
+ }
+ }
+
+ // TabBar is designed to be horizontal, whereas we need a vertical bar.
+ // We can easily achieve that by using a Container.
+ component TabBar: Container {
+ id: tabBarComponent
+
+ Layout.fillWidth: true
+ // ButtonGroup ensures that only one button can be checked at a time.
+ ButtonGroup {
+ buttons: tabBarComponent.contentChildren
+
+ // 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: tabBarComponent.setCurrentIndex(
+ Math.max(0, buttons.indexOf(checkedButton)))
+ }
- 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
- }
+ contentItem: ColumnLayout {
+ spacing: tabBarComponent.spacing
+ Repeater {
+ model: tabBarComponent.contentModel
}
+ }
+ }
+ ColumnLayout {
+ anchors.fill: root
+ anchors.topMargin: root.tabBarSpacing
+ anchors.bottomMargin: root.tabBarSpacing
+
+ spacing: root.tabBarSpacing
+ TabBar {
+ id: topBar
+
+ spacing: root.tabBarSpacing
// Shows help text when clicked.
SidebarEntry {
+ id: infoTab
icon.source: "../icons/light_bulb.svg"
checkable: true
checked: true
-
- Layout.alignment: Qt.AlignHCenter
}
// Shows the file system when clicked.
SidebarEntry {
+ id: filesystemTab
+
icon.source: "../icons/read.svg"
checkable: true
-
- Layout.alignment: Qt.AlignHCenter
}
}
@@ -88,25 +103,31 @@ Rectangle {
Layout.fillWidth: true
// Make the empty space drag our main window.
- WindowDragHandler { dragWindow: rootWindow }
+ WindowDragHandler {
+ dragWindow: root.dragWindow
+ }
}
- // Opens the Qt website in the system's web browser.
- SidebarEntry {
- id: qtWebsiteButton
- icon.source: "../icons/globe.svg"
- checkable: false
+ TabBar {
+ id: bottomBar
- onClicked: Qt.openUrlExternally("https://www.qt.io/")
- }
+ spacing: root.tabBarSpacing
+ // 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
+ // Opens the About Qt Window.
+ SidebarEntry {
+ id: aboutQtButton
- onClicked: aboutQtWindow.visible = !aboutQtWindow.visible
+ icon.source: "../icons/info_sign.svg"
+ checkable: false
+ onClicked: aboutQtWindow.visible = !aboutQtWindow.visible
+ }
}
}
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qmldir b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qmldir
index ff7ecb757..b1f684600 100644
--- a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qmldir
+++ b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qmldir
@@ -1,7 +1,7 @@
module FileSystemModule
Main 1.0 Main.qml
-Icon 1.0 qml/Icon.qml
About 1.0 qml/About.qml
+Editor 1.0 qml/Editor.qml
MyMenu 1.0 qml/MyMenu.qml
Sidebar 1.0 qml/Sidebar.qml
MyMenuBar 1.0 qml/MyMenuBar.qml
diff --git a/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.rst b/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.rst
index 0260928b6..b46cbec79 100644
--- a/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.rst
+++ b/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.rst
@@ -37,3 +37,16 @@ pleasing UIs.
.. image:: filesystemexplorer.webp
:target: filesystemexplorer.webp
:alt: QtQuickControls Filesystem Explorer Screenshot
+
+References
+----------
+
+If you're interested in the C++ version of this example, you can find it
+`here <https://doc-snapshots.qt.io/qt6-dev/qtquickcontrols-filesystemexplorer-example.html>`_.
+
+Additionally, there is a detailed
+`tutorial <https://doc.qt.io/qtforpython-6/tutorials/extendedexplorer/extendedexplorer.html>`_
+available that provides step-by-step instructions on how to extend this example
+with additional features. This tutorial can be helpful if you want to explore
+and learn more about building upon the existing functionality of the filesystem
+explorer.
diff --git a/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.webp b/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.webp
index cce7e1daf..10ad0d26e 100644
--- a/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.webp
+++ b/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.webp
Binary files differ
diff --git a/examples/quickcontrols/filesystemexplorer/editormodels.py b/examples/quickcontrols/filesystemexplorer/editormodels.py
new file mode 100644
index 000000000..688147726
--- /dev/null
+++ b/examples/quickcontrols/filesystemexplorer/editormodels.py
@@ -0,0 +1,116 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtWidgets import QFileSystemModel
+from PySide6.QtQuick import QQuickTextDocument
+from PySide6.QtQml import QmlElement, QmlSingleton
+from PySide6.QtCore import (Qt, QDir, QAbstractListModel, Slot, QFile, QTextStream,
+ QMimeDatabase, QFileInfo, QStandardPaths, QModelIndex,
+ Signal, Property)
+
+QML_IMPORT_NAME = "FileSystemModule"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+@QmlSingleton
+class FileSystemModel(QFileSystemModel):
+
+ rootIndexChanged = Signal()
+
+ def getDefaultRootDir():
+ return QStandardPaths.writableLocation(QStandardPaths.StandardLocation.HomeLocation)
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.mRootIndex = QModelIndex()
+ self.mDb = QMimeDatabase()
+ self.setFilter(QDir.Filter.AllEntries | QDir.Filter.Hidden | QDir.Filter.NoDotAndDotDot)
+ self.setInitialDirectory()
+
+ # 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.mDb.mimeTypeForFile(QFileInfo(file))
+ if ('text' in mime.comment().lower()
+ or any('text' in s.lower() for s in mime.parentMimeTypes())):
+ if file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text):
+ stream = QTextStream(file).readAll()
+ file.close()
+ return stream
+ else:
+ return self.tr("Error opening the file!")
+ return self.tr("File type not supported!")
+
+ @Slot(QQuickTextDocument, int, result=int)
+ def currentLineNumber(self, textDocument, cursorPosition):
+ td = textDocument.textDocument()
+ tb = td.findBlock(cursorPosition)
+ return tb.blockNumber()
+
+ def setInitialDirectory(self, path=getDefaultRootDir()):
+ dir = QDir(path)
+ if dir.makeAbsolute():
+ self.setRootPath(dir.path())
+ else:
+ self.setRootPath(self.getDefaultRootDir())
+ self.setRootIndex(self.index(dir.path()))
+
+ # we only need one column in this example
+ def columnCount(self, parent):
+ return 1
+
+ @Property(QModelIndex, notify=rootIndexChanged)
+ def rootIndex(self):
+ return self.mRootIndex
+
+ def setRootIndex(self, index):
+ if (index == self.mRootIndex):
+ return
+ self.mRootIndex = index
+ self.rootIndexChanged.emit()
+
+
+@QmlElement
+class LineNumberModel(QAbstractListModel):
+
+ lineCountChanged = Signal()
+
+ def __init__(self, parent=None):
+ self.mLineCount = 0
+ super().__init__(parent=parent)
+
+ @Property(int, notify=lineCountChanged)
+ def lineCount(self):
+ return self.mLineCount
+
+ @lineCount.setter
+ def lineCount(self, n):
+ if n < 0:
+ print("lineCount must be greater then zero")
+ return
+ if self.mLineCount == n:
+ return
+
+ if self.mLineCount < n:
+ self.beginInsertRows(QModelIndex(), self.mLineCount, n - 1)
+ self.mLineCount = n
+ self.endInsertRows()
+ else:
+ self.beginRemoveRows(QModelIndex(), n, self.mLineCount - 1)
+ self.mLineCount = n
+ self.endRemoveRows()
+
+ def rowCount(self, parent):
+ return self.mLineCount
+
+ def data(self, index, role):
+ if not self.checkIndex(index) or role != Qt.ItemDataRole.DisplayRole:
+ return
+ return index.row()
diff --git a/examples/quickcontrols/filesystemexplorer/filesystemexplorer.py b/examples/quickcontrols/filesystemexplorer/filesystemexplorer.py
deleted file mode 100644
index 90579b360..000000000
--- a/examples/quickcontrols/filesystemexplorer/filesystemexplorer.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# 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 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/examples/quickcontrols/filesystemexplorer/filesystemexplorer.pyproject b/examples/quickcontrols/filesystemexplorer/filesystemexplorer.pyproject
index 1e1aa2ad8..8053cfab0 100644
--- a/examples/quickcontrols/filesystemexplorer/filesystemexplorer.pyproject
+++ b/examples/quickcontrols/filesystemexplorer/filesystemexplorer.pyproject
@@ -1,19 +1,21 @@
{
"files": [
- "filesystemexplorer.py",
+ "main.py",
+ "editormodels.py",
"FileSystemModule/qmldir",
"FileSystemModule/app.qrc",
"FileSystemModule/qmldir",
"FileSystemModule/Main.qml",
"FileSystemModule/qml/About.qml",
"FileSystemModule/qml/Colors.qml",
+ "FileSystemModule/qml/Editor.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/app_icon.svg",
"FileSystemModule/icons/folder_closed.svg",
"FileSystemModule/icons/folder_open.svg",
"FileSystemModule/icons/generic_file.svg",
diff --git a/examples/quickcontrols/filesystemexplorer/main.py b/examples/quickcontrols/filesystemexplorer/main.py
new file mode 100644
index 000000000..8fad951cb
--- /dev/null
+++ b/examples/quickcontrols/filesystemexplorer/main.py
@@ -0,0 +1,48 @@
+# Copyright (C) 2024 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 editormodels import FileSystemModel # noqa: F401
+from PySide6.QtGui import QGuiApplication, QIcon
+from PySide6.QtQml import QQmlApplicationEngine
+from PySide6.QtCore import QCommandLineParser, qVersion
+
+import sys
+
+if __name__ == '__main__':
+ app = QGuiApplication(sys.argv)
+ app.setOrganizationName("QtProject")
+ app.setApplicationName("File System Explorer")
+ app.setApplicationVersion(qVersion())
+ app.setWindowIcon(QIcon(sys.path[0] + "/FileSystemModule/icons/app_icon.svg"))
+
+ parser = QCommandLineParser()
+ parser.setApplicationDescription("Qt Filesystemexplorer Example")
+ parser.addHelpOption()
+ parser.addVersionOption()
+ parser.addPositionalArgument("", "Initial directory", "[path]")
+ parser.process(app)
+ args = parser.positionalArguments()
+
+ 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)
+
+ if (len(args) == 1):
+ fsm = engine.singletonInstance("FileSystemModule", "FileSystemModel")
+ fsm.setInitialDirectory(args[0])
+
+ sys.exit(app.exec())
diff --git a/examples/quickcontrols/gallery/doc/gallery.rst b/examples/quickcontrols/gallery/doc/gallery.rst
index 29cd49f14..acd5096f6 100644
--- a/examples/quickcontrols/gallery/doc/gallery.rst
+++ b/examples/quickcontrols/gallery/doc/gallery.rst
@@ -1,6 +1,8 @@
Qt Quick Controls 2 - Gallery
=============================
+.. tags:: Android
+
The gallery example is a simple application with a drawer menu that contains
all the Qt Quick Controls 2. Each menu item opens a page that shows the
graphical appearance of a control, allows you to interact with the control, and
diff --git a/examples/quickcontrols/gallery/gallery.py b/examples/quickcontrols/gallery/gallery.py
index 1cdc30bab..6c2a3612e 100644
--- a/examples/quickcontrols/gallery/gallery.py
+++ b/examples/quickcontrols/gallery/gallery.py
@@ -17,7 +17,7 @@ from PySide6.QtCore import QSettings, QUrl
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtQuickControls2 import QQuickStyle
-import rc_gallery
+import rc_gallery # noqa: F401
if __name__ == "__main__":
QGuiApplication.setApplicationName("Gallery")