summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@digia.com>2013-12-16 16:19:20 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-11 13:29:28 +0100
commit77a6b6448200c263a862bc34546106a6b0e698a6 (patch)
treecb3c6da821934dded9810a55db63e0c146a17a64
parenta5da0d56dbad39259e20b17de340c3dd757e74ae (diff)
downloadqtquickcontrols-77a6b6448200c263a862bc34546106a6b0e698a6.tar.gz
FileDialog: new features in DefaultFileDialog.qml
Use a ComboBox for the filters. Add a sidebar showing shortcuts for the common paths and drives that the user will most likely need, and an editable list of favorite paths. [ChangeLog][QtQuickDialogs][FileDialog] The FileDialog fallback QML implementation now uses QtQuick.Controls, and has added features including a Combobox for file extension filters, and a sidebar with common paths, drives/volumes and favorite paths. Change-Id: I228ebdadcf338917db81a2b3d03d3c0b09584e7d Reviewed-by: Liang Qi <liang.qi@digia.com>
-rw-r--r--src/dialogs/DefaultFileDialog.qml556
-rw-r--r--src/dialogs/dialogs.pro2
-rw-r--r--src/dialogs/qquickabstractfiledialog.cpp18
-rw-r--r--src/dialogs/qquickabstractfiledialog_p.h2
-rw-r--r--src/dialogs/qquickfiledialog.cpp41
-rw-r--r--src/dialogs/qquickfiledialog_p.h7
6 files changed, 337 insertions, 289 deletions
diff --git a/src/dialogs/DefaultFileDialog.qml b/src/dialogs/DefaultFileDialog.qml
index 06e68059..4521859d 100644
--- a/src/dialogs/DefaultFileDialog.qml
+++ b/src/dialogs/DefaultFileDialog.qml
@@ -40,18 +40,20 @@
import QtQuick 2.1
import QtQuick.Controls 1.1
-import QtQuick.Dialogs 1.0
+import QtQuick.Controls.Private 1.0 as ControlsPrivate
+import QtQuick.Dialogs 1.1
+import QtQuick.Dialogs.Private 1.1
+import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
-import Qt.labs.folderlistmodel 2.0
-import "qml"
+import Qt.labs.folderlistmodel 2.1
+import Qt.labs.settings 1.0
AbstractFileDialog {
id: root
onVisibleChanged: {
if (visible) {
- __selectedIndices = []
- __lastClickedIdx = -1
- currentPathField.visible = false
+ view.needsWidthAdjustment = true
+ view.selection.clear()
}
}
onFolderChanged: {
@@ -62,58 +64,44 @@ AbstractFileDialog {
view.model.folder = folder
}
- property real __textX: titleBar.height
- property SystemPalette __palette
- property var __selectedIndices: []
- property int __lastClickedIdx: -1
+ Component.onCompleted: {
+ view.model.nameFilters = root.selectedNameFilterExtensions
+ filterField.currentIndex = root.selectedNameFilterIndex
+ root.favoriteFolders = settings.favoriteFolders
+ }
- function __dirDown(path) {
- view.model.folder = "file://" + path
- __lastClickedIdx = -1
- __selectedIndices = []
+ Component.onDestruction: {
+ settings.favoriteFolders = root.favoriteFolders
}
- function __dirUp() {
- if (view.model.parentFolder == "")
- view.model.folder = "file:///"
- else
- view.model.folder = view.model.parentFolder
- __lastClickedIdx = -1
- __selectedIndices = []
+
+ property Settings settings: Settings {
+ category: "QQControlsFileDialog"
+ property alias width: root.width
+ property alias height: root.height
+ property alias sidebarWidth: sidebar.width
+ property alias sidebarSplit: shortcuts.height
+ property variant favoriteFolders: []
}
- function __up(extend) {
- if (view.currentIndex > 0)
- --view.currentIndex
- else
- view.currentIndex = 0
- if (extend) {
- if (__selectedIndices.indexOf(view.currentIndex) < 0) {
- var selCopy = __selectedIndices
- selCopy.push(view.currentIndex)
- __selectedIndices = selCopy
- }
- } else
- __selectedIndices = [view.currentIndex]
+
+ property bool showFocusHighlight: false
+ property SystemPalette palette: SystemPalette { }
+ property var favoriteFolders: []
+
+ function dirDown(path) {
+ view.model.folder = "file://" + path
+ view.selection.clear()
}
- function __down(extend) {
- if (view.currentIndex < view.model.count - 1)
- ++view.currentIndex
- else
- view.currentIndex = view.model.count - 1
- if (extend) {
- if (__selectedIndices.indexOf(view.currentIndex) < 0) {
- var selCopy = __selectedIndices
- selCopy.push(view.currentIndex)
- __selectedIndices = selCopy
- }
- } else
- __selectedIndices = [view.currentIndex]
+ function dirUp() {
+ view.model.folder = view.model.parentFolder
+ view.selection.clear()
}
- function __acceptSelection() {
+ function acceptSelection() {
+ // transfer the view's selections to QQuickFileDialog
clearSelection()
- if (selectFolder && __selectedIndices.length == 0)
+ if (selectFolder && view.selection.count === 0)
addSelection(folder)
- else if (__selectedIndices.length > 0) {
- __selectedIndices.map(function(idx) {
+ else {
+ view.selection.forEach(function(idx) {
if (view.model.isFolder(idx)) {
if (selectFolder)
addSelection(view.model.get(idx, "fileURL"))
@@ -122,265 +110,297 @@ AbstractFileDialog {
addSelection(view.model.get(idx, "fileURL"))
}
})
- } else {
- addSelection(pathToUrl(currentPathField.text))
}
accept()
}
+ property Action dirUpAction: Action {
+ text: "&Up"
+ shortcut: "Ctrl+U"
+ iconSource: "images/up.png"
+ onTriggered: if (view.model.parentFolder != "") dirUp()
+ tooltip: "Go up to the folder containing this one"
+ }
+
Rectangle {
- id: content
property int maxSize: Math.min(Screen.desktopAvailableWidth, Screen.desktopAvailableHeight)
- // TODO: QTBUG-29817 geometry from AbstractFileDialog
- implicitWidth: Math.min(maxSize, Screen.pixelDensity * 100)
+ implicitWidth: Math.min(maxSize, Math.max(Screen.pixelDensity * 100, splitter.implicitWidth))
implicitHeight: Math.min(maxSize, Screen.pixelDensity * 80)
- color: __palette.window
- focus: root.visible && !currentPathField.visible
- property real spacing: 6
- property real outerSpacing: 12
- SystemPalette { id: __palette }
+ id: window
+ color: root.palette.window
- Component {
- id: folderDelegate
- Rectangle {
- id: wrapper
- function launch() {
- if (view.model.isFolder(index)) {
- __dirDown(filePath)
- } else {
- root.__acceptSelection()
- }
- }
- width: content.width
- height: nameText.implicitHeight * 1.5
- color: "transparent"
- Rectangle {
- id: itemHighlight
- visible: root.__selectedIndices.indexOf(index) >= 0
- anchors.fill: parent
- color: __palette.highlight
- }
- Image {
- id: icon
- source: "images/folder.png"
- height: wrapper.height - y * 2; width: height
- x: (root.__textX - width) / 2
- y: 2
- visible: view.model.isFolder(index)
- }
- Text {
- id: nameText
- anchors.fill: parent; verticalAlignment: Text.AlignVCenter
- text: fileName
- anchors.leftMargin: root.__textX
- color: itemHighlight.visible ? __palette.highlightedText : __palette.windowText
- elide: Text.ElideRight
- }
- MouseArea {
- id: mouseRegion
- anchors.fill: parent
- onDoubleClicked: {
- __selectedIndices = [index]
- root.__lastClickedIdx = index
- launch()
+ SplitView {
+ id: splitter
+ x: 0
+ width: parent.width
+ anchors.top: titleBar.bottom
+ anchors.bottom: bottomBar.top
+
+ Column {
+ id: sidebar
+ Component.onCompleted: if (width < 1) width = sidebarSplitter.maxShortcutWidth
+ height: parent.height
+ width: 0 // initial width only; settings and onCompleted will override it
+ SplitView {
+ id: sidebarSplitter
+ orientation: Qt.Vertical
+ property real rowHeight: 10
+ property real maxShortcutWidth: 50
+ width: parent.width
+ height: parent.height - favoritesButtons.height
+
+ ScrollView {
+ id: shortcuts
+ Component.onCompleted: {
+ if (height < 1)
+ height = shortcutsView.model.count * sidebarSplitter.rowHeight
+ Layout.minimumHeight = sidebarSplitter.rowHeight * 2.5
+ }
+ height: 0 // initial width only; settings and onCompleted will override it
+ ListView {
+ id: shortcutsView
+ model: root.shortcuts
+ anchors.bottomMargin: ControlsPrivate.Settings.hasTouchScreen ? Screen.pixelDensity * 3.5 : anchors.margins
+ implicitHeight: model.count * sidebarSplitter.rowHeight
+ delegate: Item {
+ id: shortcutItem
+ width: sidebarSplitter.width
+ height: shortcutLabel.implicitHeight * 1.5
+ Text {
+ id: shortcutLabel
+ text: shortcutsView.model[index]["name"]
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ right: parent.right
+ margins: 4
+ }
+ elide: Text.ElideLeft
+ renderType: Text.NativeRendering
+ Component.onCompleted: {
+ sidebarSplitter.rowHeight = parent.height
+ if (implicitWidth * 1.2 > sidebarSplitter.maxShortcutWidth)
+ sidebarSplitter.maxShortcutWidth = implicitWidth * 1.2
+ }
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: root.folder = shortcutsView.model[index]["url"]
+ }
+ }
+ }
}
- onClicked: {
- view.currentIndex = index
- if (mouse.modifiers & Qt.ControlModifier && root.selectMultiple) {
- // modifying the contents of __selectedIndices doesn't notify,
- // so we have to re-assign the variable
- var selCopy = __selectedIndices
- var existingIdx = selCopy.indexOf(index)
- if (existingIdx >= 0)
- selCopy.splice(existingIdx, 1)
- else
- selCopy.push(index)
- __selectedIndices = selCopy
- } else if (mouse.modifiers & Qt.ShiftModifier && root.selectMultiple) {
- if (root.__lastClickedIdx >= 0) {
- var sel = []
- if (index > __lastClickedIdx) {
- for (var i = root.__lastClickedIdx; i <= index; i++)
- sel.push(i)
- } else {
- for (var i = root.__lastClickedIdx; i >= index; i--)
- sel.push(i)
+
+ ScrollView {
+ Layout.minimumHeight: sidebarSplitter.rowHeight * 2.5
+ ListView {
+ id: favorites
+ model: root.favoriteFolders
+ anchors.topMargin: ControlsPrivate.Settings.hasTouchScreen ? Screen.pixelDensity * 3.5 : anchors.margins
+ delegate: Item {
+ width: favorites.width
+ height: folderLabel.implicitHeight * 1.5
+ Text {
+ id: folderLabel
+ text: root.favoriteFolders[index]
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ right: parent.right
+ margins: 4
+ }
+ elide: Text.ElideLeft
+ renderType: Text.NativeRendering
+ }
+ Menu {
+ id: favoriteCtxMenu
+ title: root.favoriteFolders[index]
+ MenuItem {
+ text: "Remove favorite"
+ onTriggered: {
+ root.favoriteFolders.splice(index, 1)
+ favorites.model = root.favoriteFolders
+ }
+ }
+ }
+ MouseArea {
+ id: favoriteArea
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ hoverEnabled: true
+ onClicked: {
+ if (mouse.button == Qt.LeftButton)
+ view.model.folder = root.favoriteFolders[index]
+ else if (mouse.button == Qt.RightButton)
+ favoriteCtxMenu.popup()
+ }
+ onExited: ControlsPrivate.Tooltip.hideText()
+ onCanceled: ControlsPrivate.Tooltip.hideText()
+ Timer {
+ interval: 1000
+ running: favoriteArea.containsMouse && !favoriteArea.pressed && folderLabel.truncated
+ onTriggered: ControlsPrivate.Tooltip.showText(favoriteArea,
+ Qt.point(favoriteArea.mouseX, favoriteArea.mouseY), urlToPath(root.favoriteFolders[index]))
+ }
}
- __selectedIndices = sel
}
- } else {
- __selectedIndices = [index]
- root.__lastClickedIdx = index
}
}
}
- }
- }
- Keys.onPressed: {
- event.accepted = true
- switch (event.key) {
- case Qt.Key_Up:
- root.__up(event.modifiers & Qt.ShiftModifier && root.selectMultiple)
- break
- case Qt.Key_Down:
- root.__down(event.modifiers & Qt.ShiftModifier && root.selectMultiple)
- break
- case Qt.Key_Left:
- root.__dirUp()
- break
- case Qt.Key_Return:
- case Qt.Key_Select:
- case Qt.Key_Right:
- if (view.currentItem)
- view.currentItem.launch()
- else
- root.__acceptSelection()
- break
- case Qt.Key_Back:
- case Qt.Key_Escape:
- reject()
- break
- case Qt.Key_C:
- if (event.modifiers & Qt.ControlModifier)
- currentPathField.copyAll()
- break
- case Qt.Key_V:
- if (event.modifiers & Qt.ControlModifier) {
- currentPathField.visible = true
- currentPathField.paste()
+ Row {
+ id: favoritesButtons
+ height: plusButton.height
+ Button {
+ id: plusButton
+ text: "+"
+ width: height
+ onClicked: {
+ root.favoriteFolders.push(view.model.folder)
+ favorites.model = root.favoriteFolders
+ }
+ }
}
- break
- default:
- // do nothing
- event.accepted = false
- break
}
- }
- ListView {
- id: view
- anchors.top: titleBar.bottom
- anchors.bottom: bottomBar.top
- clip: true
- x: 0
- width: parent.width
- model: FolderListModel {
- onFolderChanged: {
- root.folder = folder
- currentPathField.text = root.urlToPath(view.model.folder)
+ TableView {
+ id: view
+ sortIndicatorVisible: true
+ Layout.fillWidth: true
+ Layout.minimumWidth: 40
+ property bool needsWidthAdjustment: true
+ selectionMode: root.selectMultiple ?
+ (ControlsPrivate.Settings.hasTouchScreen ? SelectionMode.MultiSelection : SelectionMode.ExtendedSelection) :
+ SelectionMode.SingleSelection
+ onRowCountChanged: if (needsWidthAdjustment && rowCount > 0) {
+ resizeColumnsToContents()
+ needsWidthAdjustment = false
+ }
+ model: FolderListModel {
+ showFiles: !root.selectFolder
+ nameFilters: root.selectedNameFilterExtensions
+ onFolderChanged: root.folder = folder
+ sortField: (view.sortIndicatorColumn === 0 ? FolderListModel.Name :
+ (view.sortIndicatorColumn === 1 ? FolderListModel.Type :
+ (view.sortIndicatorColumn === 2 ? FolderListModel.Size : FolderListModel.LastModified)))
+ sortReversed: view.sortIndicatorOrder === Qt.DescendingOrder
}
- }
- delegate: folderDelegate
- highlight: Rectangle {
- color: "transparent"
- border.color: Qt.darker(__palette.window, 1.3)
- }
- highlightMoveDuration: 0
- highlightMoveVelocity: -1
- }
-
- MouseArea {
- anchors.fill: view
- enabled: currentPathField.visible
- onClicked: currentPathField.visible = false
- }
-
-
- Item {
- id: titleBar
- width: parent.width
- height: currentPathField.height * 1.5
- Rectangle {
- anchors.fill: parent
- color: Qt.darker(__palette.window, 1.1)
- border.color: Qt.darker(__palette.window, 1.3)
- }
- Rectangle {
- id: upButton
- width: root.__textX
- height: titleBar.height
- color: "transparent"
- Image {
- id: upButtonImage
- anchors.centerIn: parent; source: "images/up.png"
+ onActivated: {
+ if (view.model.isFolder(row)) {
+ dirDown(view.model.get(row, "filePath"))
+ } else {
+ root.acceptSelection()
+ }
}
- MouseArea { id: upRegion; anchors.centerIn: parent
- width: 56
- height: parent.height
- onClicked: if (view.model.parentFolder !== "") __dirUp()
+
+ TableViewColumn {
+ id: fileNameColumn
+ role: "fileName"
+ title: "Filename"
+ delegate: Item {
+ implicitWidth: pathText.implicitWidth + pathText.anchors.leftMargin + pathText.anchors.rightMargin
+ Image {
+ id: fileIcon
+ width: height
+ x: 4
+ height: parent.height - 2
+ source: "images/folder.png"
+ property var isDir: view.model.get(styleData.row, "fileIsDir")
+ visible: isDir !== undefined && isDir
+ }
+ Text {
+ id: pathText
+ text: styleData.value
+ anchors {
+ left: parent.left
+ right: parent.right
+ leftMargin: fileIcon.width + 8
+ rightMargin: 4
+ verticalCenter: parent.verticalCenter
+ }
+ color: styleData.textColor
+ elide: Text.ElideRight
+ renderType: Text.NativeRendering
+ }
+ }
}
- states: [
- State {
- name: "pressed"
- when: upRegion.pressed
- PropertyChanges { target: upButton; color: __palette.highlight }
+ TableViewColumn {
+ role: "fileSuffix"
+ title: "Type"
+ // TODO should not need to create a whole new component just to customize the text value
+ // something like textFormat: function(text) { return view.model.get(styleData.row, "fileIsDir") ? "folder" : text }
+ delegate: Item {
+ implicitWidth: sizeText.implicitWidth + sizeText.anchors.leftMargin + sizeText.anchors.rightMargin
+ Text {
+ id: sizeText
+ text: view.model.get(styleData.row, "fileIsDir") ? "folder" : styleData.value
+ anchors {
+ left: parent.left
+ right: parent.right
+ leftMargin: 4
+ rightMargin: 4
+ verticalCenter: parent.verticalCenter
+ }
+ color: styleData.textColor
+ elide: Text.ElideRight
+ renderType: Text.NativeRendering
+ }
}
- ]
- }
- Text {
- id: currentPathText
- anchors.left: parent.left; anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: __textX; anchors.rightMargin: content.spacing
- text: root.urlToPath(view.model.folder)
- color: __palette.text
- elide: Text.ElideLeft; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignVCenter
- MouseArea {
- anchors.fill: parent
- onClicked: currentPathField.visible = true
}
+ TableViewColumn {
+ role: "fileSize"
+ title: "Size"
+ horizontalAlignment: Text.AlignRight
+ }
+ TableViewColumn { role: "fileModified" ; title: "Modified" }
+ TableViewColumn { role: "fileAccessed" ; title: "Accessed" }
}
- TextField {
- id: currentPathField
- anchors.left: parent.left; anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: __textX; anchors.rightMargin: content.spacing
- visible: false
- focus: visible
- onAccepted: {
- root.clearSelection()
- if (root.addSelection(root.pathToUrl(text)))
- root.accept()
- else
- view.model.folder = root.pathFolder(text)
+ }
+
+ ToolBar {
+ id: titleBar
+ RowLayout {
+ width: parent.width
+ ToolButton {
+ iconSource: "images/up.png"
+ action: dirUpAction
}
- Keys.onPressed: {
- event.accepted = true
- switch (event.key) {
- case Qt.Key_Down:
- currentPathField.visible = false
- break
- case Qt.Key_Back:
- case Qt.Key_Escape:
- reject()
- break
+ TextField {
+ id: currentPathField
+ text: root.urlToPath(view.model.folder)
+ Layout.fillWidth: true
+ onAccepted: {
+ root.clearSelection()
+ if (root.addSelection(root.pathToUrl(text)))
+ root.accept()
+ else
+ view.model.folder = root.pathFolder(text)
}
}
}
}
- Rectangle {
+ Item {
id: bottomBar
width: parent.width
height: buttonRow.height + buttonRow.spacing * 2
anchors.bottom: parent.bottom
- color: Qt.darker(__palette.window, 1.1)
- border.color: Qt.darker(__palette.window, 1.3)
Row {
id: buttonRow
anchors.right: parent.right
anchors.rightMargin: spacing
anchors.verticalCenter: parent.verticalCenter
- spacing: content.spacing
- TextField {
+ spacing: 4
+ ComboBox {
id: filterField
- text: root.selectedNameFilter
+ model: root.nameFilters
visible: !selectFolder
width: bottomBar.width - cancelButton.width - okButton.width - parent.spacing * 5
anchors.verticalCenter: parent.verticalCenter
- onAccepted: {
- root.selectNameFilter(text)
- view.model.nameFilters = text
+ onCurrentTextChanged: {
+ root.selectNameFilter(currentText)
+ view.model.nameFilters = root.selectedNameFilterExtensions
}
}
Button {
@@ -393,9 +413,9 @@ AbstractFileDialog {
text: "OK"
onClicked: {
if (view.model.isFolder(view.currentIndex) && !selectFolder)
- __dirDown(view.model.get(view.currentIndex, "filePath"))
+ dirDown(view.model.get(view.currentIndex, "filePath"))
else
- root.__acceptSelection()
+ root.acceptSelection()
}
}
}
diff --git a/src/dialogs/dialogs.pro b/src/dialogs/dialogs.pro
index f263c003..dee9fe36 100644
--- a/src/dialogs/dialogs.pro
+++ b/src/dialogs/dialogs.pro
@@ -63,7 +63,7 @@ DIALOGS_QML_FILES += \
images/folder.png \
images/up.png
-QT += quick-private gui gui-private core core-private qml
+QT += quick-private gui gui-private core core-private qml qml-private
# Create the resource file
GENERATED_RESOURCE_FILE = $$OUT_PWD/dialogs.qrc
diff --git a/src/dialogs/qquickabstractfiledialog.cpp b/src/dialogs/qquickabstractfiledialog.cpp
index 50be9f2c..e193ca37 100644
--- a/src/dialogs/qquickabstractfiledialog.cpp
+++ b/src/dialogs/qquickabstractfiledialog.cpp
@@ -79,24 +79,6 @@ QString QQuickAbstractFileDialog::title() const
return m_options->windowTitle();
}
-QStringList QQuickAbstractFileDialog::shortcuts() const
-{
- QStringList ret;
- ret << QStandardPaths::standardLocations(QStandardPaths::DesktopLocation);
- ret << QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
- ret << QStandardPaths::standardLocations(QStandardPaths::MusicLocation);
- ret << QStandardPaths::standardLocations(QStandardPaths::MoviesLocation);
- ret << QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
- ret << QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
- ret << QStandardPaths::writableLocation(QStandardPaths::TempLocation);
- ret << QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
-
- QFileInfoList drives = QDir::drives();
- foreach (QFileInfo fi, drives)
- ret << fi.absoluteFilePath();
- return ret;
-}
-
void QQuickAbstractFileDialog::setTitle(const QString &t)
{
if (m_options->windowTitle() == t) return;
diff --git a/src/dialogs/qquickabstractfiledialog_p.h b/src/dialogs/qquickabstractfiledialog_p.h
index d24e557d..0860ce36 100644
--- a/src/dialogs/qquickabstractfiledialog_p.h
+++ b/src/dialogs/qquickabstractfiledialog_p.h
@@ -67,7 +67,6 @@ class QQuickAbstractFileDialog : public QQuickAbstractDialog
Q_PROPERTY(bool selectExisting READ selectExisting WRITE setSelectExisting NOTIFY fileModeChanged)
Q_PROPERTY(bool selectMultiple READ selectMultiple WRITE setSelectMultiple NOTIFY fileModeChanged)
Q_PROPERTY(bool selectFolder READ selectFolder WRITE setSelectFolder NOTIFY fileModeChanged)
- Q_PROPERTY(QStringList shortcuts READ shortcuts CONSTANT)
Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged)
Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
Q_PROPERTY(QString selectedNameFilter READ selectedNameFilter WRITE selectNameFilter NOTIFY filterSelected)
@@ -84,7 +83,6 @@ public:
bool selectExisting() const { return m_selectExisting; }
bool selectMultiple() const { return m_selectMultiple; }
bool selectFolder() const { return m_selectFolder; }
- QStringList shortcuts() const;
QUrl folder() const;
QStringList nameFilters() const { return m_options->nameFilters(); }
QString selectedNameFilter() const;
diff --git a/src/dialogs/qquickfiledialog.cpp b/src/dialogs/qquickfiledialog.cpp
index f408713e..3891308d 100644
--- a/src/dialogs/qquickfiledialog.cpp
+++ b/src/dialogs/qquickfiledialog.cpp
@@ -42,9 +42,12 @@
#include "qquickfiledialog_p.h"
#include <QQuickItem>
#include <private/qguiapplication_p.h>
+#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
+using namespace QV4;
+
/*!
\qmltype AbstractFileDialog
\instantiates QQuickFileDialog
@@ -108,6 +111,44 @@ QList<QUrl> QQuickFileDialog::fileUrls() const
return m_selections;
}
+
+void QQuickFileDialog::addShortcut(int &i, const QString &name, const QString &path)
+{
+ QJSEngine *engine = qmlEngine(this);
+ QJSValue o = engine->newObject();
+ o.setProperty("name", name);
+ o.setProperty("url", QUrl::fromLocalFile(path).toString());
+ m_shortcuts.setProperty(i++, o);
+}
+
+void QQuickFileDialog::addIfReadable(int &i, const QString &name, QStandardPaths::StandardLocation loc)
+{
+ QStringList paths = QStandardPaths::standardLocations(loc);
+ if (!paths.isEmpty() && QDir(paths.first()).isReadable())
+ addShortcut(i, name, paths.first());
+}
+
+QJSValue QQuickFileDialog::shortcuts()
+{
+ if (m_shortcuts.isUndefined()) {
+ QJSEngine *engine = qmlEngine(this);
+ m_shortcuts = engine->newArray();
+ int i = 0;
+
+ addIfReadable(i, "Desktop", QStandardPaths::DesktopLocation);
+ addIfReadable(i, "Documents", QStandardPaths::DocumentsLocation);
+ addIfReadable(i, "Music", QStandardPaths::MusicLocation);
+ addIfReadable(i, "Movies", QStandardPaths::MoviesLocation);
+ addIfReadable(i, "Pictures", QStandardPaths::PicturesLocation);
+ addIfReadable(i, "Home", QStandardPaths::HomeLocation);
+
+ QFileInfoList drives = QDir::drives();
+ foreach (QFileInfo fi, drives)
+ addShortcut(i, fi.absoluteFilePath(), fi.absoluteFilePath());
+ }
+ return m_shortcuts;
+}
+
/*!
\qmlproperty bool AbstractFileDialog::visible
diff --git a/src/dialogs/qquickfiledialog_p.h b/src/dialogs/qquickfiledialog_p.h
index 880fd137..19d8cac0 100644
--- a/src/dialogs/qquickfiledialog_p.h
+++ b/src/dialogs/qquickfiledialog_p.h
@@ -61,6 +61,7 @@ class QQuickFileDialog : public QQuickAbstractFileDialog
{
Q_OBJECT
Q_PROPERTY(QObject* implementation READ qmlImplementation WRITE setQmlImplementation DESIGNABLE false)
+ Q_PROPERTY(QJSValue shortcuts READ shortcuts CONSTANT)
Q_CLASSINFO("DefaultProperty", "implementation") // AbstractFileDialog in QML can have only one child
public:
@@ -68,6 +69,8 @@ public:
~QQuickFileDialog();
virtual QList<QUrl> fileUrls() const;
+ QJSValue shortcuts();
+
Q_SIGNALS:
public Q_SLOTS:
@@ -80,10 +83,14 @@ protected:
Q_INVOKABLE QUrl pathToUrl(const QString &path) { return QUrl::fromLocalFile(path); }
Q_INVOKABLE QUrl pathFolder(const QString &path);
+ void addShortcut(int &i, const QString &name, const QString &path);
+ void addIfReadable(int &i, const QString &name, QStandardPaths::StandardLocation loc);
+
private:
QList<QUrl> m_selections;
Q_DISABLE_COPY(QQuickFileDialog)
+ QJSValue m_shortcuts;
};
QT_END_NAMESPACE