/* * Copyright (C) 2014-2018 CZ.NIC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations including * the two. */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import Qt.labs.folderlistmodel 2.1 import cz.nic.mobileDatovka 1.0 import cz.nic.mobileDatovka.qmlInteraction 1.0 Dialog { id: root focus: true modal: true title: qsTr("Select path") //standardButtons: (selectedFileIndex != -1) ? (Dialog.Ok | Dialog.Cancel) : Dialog.Cancel footer: DialogButtonBox { AccessibleButton { text: qsTr("Cancel") DialogButtonBox.buttonRole: DialogButtonBox.RejectRole } AccessibleButton { text: qsTr("OK") enabled: (onlyDir || selectedFileIndex != -1) visible: (onlyDir || selectedFileIndex != -1) DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole } } /* Place the dialogue in the centre. */ x: 2 * defaultMargin y: 2 * defaultMargin height: parent.height - 4 * defaultMargin width: parent.width - 4 * defaultMargin /* This property must be set by caller. */ property bool multiSelect: false property int selectedFileIndex: -1 property bool onlyDir: false signal finished(variant pathListModel) function raise(title, filters, showFiles) { root.title = title folderModel.folder = folderModel.folder folderModel.showFiles = showFiles onlyDir = !showFiles if (filters !== "") { folderModel.nameFilters = [filters] } selectedFileIndex = -1 // clear add path list model pathListModel.clear() // deselect all item in the file idalog for (fileList.currentIndex = 0; fileList.currentIndex < fileList.count; ++fileList.currentIndex) { fileList.currentItem.color = datovkaPalette.window } if (onlyDir) { var path = stripUrlPrefix(folderModel.folder) pathListModel.clear() pathListModel.append({path: path}) } root.open() } function stripUrlPrefix(url) { return url.toString().replace(/^(file:\/{2})/, "") } function standardLocationUrl(location) { return "file://" + interactionFilesystem.locate(location) } // retrun valid index if item is selected or invalid index function isSelected(pathListModel, fileIndex) { var path = stripUrlPrefix(folderModel.folder) + "/" + folderModel.get(fileIndex, "fileName") var listLength = pathListModel.count for (var j = 0; j < listLength; ++j) { if (pathListModel.get(j).path === path) { return j } } return -1 } InteractionFilesystem { id: interactionFilesystem } ListModel { id: pathListModel } contentItem: ColumnLayout { spacing: formItemVerticalSpacing AccessibleComboBox { anchors { left: parent.left; right: parent.right; } accessibleDescription: qsTr("Select location type") model: ListModel { ListElement { label: qsTr("Desktop"); key: "desktop" } ListElement { label: qsTr("Documents"); key: "document" } ListElement { label: qsTr("Downloads"); key: "download" } ListElement { label: qsTr("Pictures"); key: "picture" } ListElement { label: qsTr("Temp"); key: "temp" } } onCurrentIndexChanged: { var location = InteractionFilesystem.DESKTOP_LOCATION if (currentKey() === "document") { location = InteractionFilesystem.DOCUMENTS_LOCATION } else if (currentKey() === "download") { location = InteractionFilesystem.DOWNLOAD_LOCATION } else if (currentKey() === "picture") { location = InteractionFilesystem.PICTURE_LOCATION } else if (currentKey() === "temp") { location = InteractionFilesystem.TEMP_LOCATION } folderModel.folder = standardLocationUrl(location) } } RowLayout { anchors { left: parent.left; right: parent.right; } spacing: formItemVerticalSpacing AccessibleButton { id: upButton text: "<" accessibleName: qsTr("Up") /* Needs to be specified as "<" is not read. */ onClicked: { /* Navigate to parent folder. */ if (folderModel.parentFolder !== "") { folderModel.folder = folderModel.parentFolder } } } AccessibleTextField { id: pathField Layout.fillWidth: true text: stripUrlPrefix(folderModel.folder) onEditingFinished: { /* Navigate to supplied location if location exists. */ var path = interactionFilesystem.absoluteDirPath(text) if (path !== "") { folderModel.folder = "file://" + path } else { path = interactionFilesystem.absolutePath(text) if (path !== "") { folderModel.folder = "file://" + path } else { /* Restore original location. */ text = stripUrlPrefix(folderModel.folder) } } } } } // RowLayout ScrollableListView { id: fileList delegateHeight: imgHeightHeader /* Fill remaining space with the list content. */ Layout.fillHeight: true Layout.fillWidth: true FolderListModel { id: folderModel showDirsFirst: true nameFilters: ["*.*"] folder: standardLocationUrl(InteractionFilesystem.DESKTOP_LOCATION) onFolderChanged: { selectedFileIndex = -1 pathField.text = stripUrlPrefix(folder) } } // FolderListModel Component { id: fileDelegate Rectangle { id: fileRectangle color: if (multiSelect) { // if files are in the pathList, select them (isSelected(pathListModel, index) >= 0) ? datovkaPalette.highlight : datovkaPalette.window } else { // only one file can be selected (index === selectedFileIndex) ? datovkaPalette.highlight : datovkaPalette.window } width: fileList.width height: fileList.delegateHeight RowLayout { anchors.fill: parent Text { anchors.left: parent.left Layout.fillWidth: true elide: Text.ElideRight /* Add '>' to directory names. */ text: fileName } Text { anchors.right: parent.right /* Add '>' to directory names. */ text: fileIsDir ? " >" : "" } } MouseArea { function accessibleDescriptionText() { var aText = ""; if (fileIsDir) { aText += qsTr("Open directory."); } else { if (isSelected(pathListModel, index) >= 0) { aText += qsTr("File is selected.") } else { aText += qsTr("File is not selected.") } } return aText; } function handleClick() { var path if (fileIsDir) { /* Navigate to selected directory. */ folderModel.folder = fileURL if (onlyDir) { pathListModel.clear() path = stripUrlPrefix(folderModel.folder) pathListModel.append({path: path}) } } else { /* Select file. */ selectedFileIndex = index path = stripUrlPrefix(folderModel.folder) + "/" + folderModel.get(selectedFileIndex, "fileName") if (!multiSelect) { // only one file can be selected and append to list pathListModel.clear() pathListModel.append({path: path}) } else { // file can be append to list or removed and deselected var idx = isSelected(pathListModel, index); if (idx >= 0) { fileRectangle.color = datovkaPalette.window pathListModel.remove(idx) } else { fileRectangle.color = datovkaPalette.highlight pathListModel.append({path: path}) } } } } anchors.fill: parent Accessible.role: Accessible.Button Accessible.description: accessibleDescriptionText() Accessible.name: fileName Accessible.onScrollDownAction: fileList.scrollDown() Accessible.onScrollUpAction: fileList.scrollUp() Accessible.onPressAction: { handleClick() } onClicked: { handleClick() } } } } // Component model: folderModel delegate: fileDelegate } // ListView } // ColumnLayout onAccepted: { selectedFileIndex = -1 finished(pathListModel) } onRejected: { selectedFileIndex = -1 pathListModel.clear() } }