Warning, /multimedia/kid3/src/qml/app/FileSelectDialog.qml is written in an unsupported language. File is not indexed.
0001 /**
0002 * \file FileSelectDialog.qml
0003 * File select dialog.
0004 *
0005 * \b Project: Kid3
0006 * \author Urs Fleisch
0007 * \date 16 Feb 2015
0008 *
0009 * Copyright (C) 2015-2018 Urs Fleisch
0010 *
0011 * This program is free software; you can redistribute it and/or modify
0012 * it under the terms of the GNU Lesser General Public License as published by
0013 * the Free Software Foundation; version 3.
0014 *
0015 * This program is distributed in the hope that it will be useful,
0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0018 * GNU Lesser General Public License for more details.
0019 *
0020 * You should have received a copy of the GNU Lesser General Public License
0021 * along with this program. If not, see <http://www.gnu.org/licenses/>.
0022 */
0023
0024 import QtQuick 2.11
0025 import QtQuick.Layouts 1.11
0026 import QtQuick.Controls 2.4
0027 import Qt.labs.folderlistmodel 2.1
0028
0029 Dialog {
0030 id: page
0031
0032 signal finished(string path)
0033 signal fileSelected(string fileName)
0034 property bool showDotAndDotDot: true
0035 property bool showHidden: true
0036 property bool showDirsFirst: true
0037 property bool saveMode: false
0038 property string currentFile: ""
0039 property string folder: ""
0040 property var nameFilters: ["*.*"]
0041
0042 title: qsTr("Open")
0043 modal: true
0044 x: (parent.width - width) / 2
0045 y: (parent.height - height) / 2
0046 width: Math.min(parent.width, constants.gu(65))
0047 height: Math.min(parent.height, constants.gu(80))
0048 standardButtons: Dialog.Ok | Dialog.Cancel
0049 onAccepted: page.finished(getCurrentFilePath())
0050 onRejected: page.finished(null)
0051
0052 function getCurrentFilePath() {
0053 return folderField.text + "/" + currentFileField.text
0054 }
0055
0056 function simplifyPath(path) {
0057 if (typeof path === "object") {
0058 path = path.toString()
0059 }
0060 if (path.substr(0,7) === "file://") {
0061 path = path.substr(7)
0062 }
0063 return path
0064 }
0065
0066 function setFolder(path) {
0067 path = simplifyPath(path)
0068 for (;;) {
0069 if (script.classifyFile(path) === "/") {
0070 break;
0071 }
0072 var slashPos = path.lastIndexOf("/")
0073 if (slashPos === -1) {
0074 path = "/";
0075 break;
0076 } else {
0077 path = path.substring(0, slashPos)
0078 }
0079 }
0080 folderListModel.folder = "file://" + path
0081 }
0082
0083 function setCurrentFile(name) {
0084 var idx = folderListModel.indexOf(folderListModel.folder + "/" + name)
0085 if (idx >= 0) {
0086 fileListView.currentIndex = idx
0087 }
0088 }
0089
0090 ColumnLayout {
0091 anchors.fill: parent
0092 GridLayout {
0093 id: pathLayout
0094 Layout.maximumWidth: parent.width
0095 columns: 3
0096 Label {
0097 id: folderLabel
0098 text: qsTr("Folder")
0099 }
0100 TextField {
0101 id: folderField
0102 Layout.fillWidth: true
0103 selectByMouse: true
0104 onEditingFinished: {
0105 setFolder(text)
0106 }
0107 }
0108 IconButton {
0109 id: menuButton
0110 iconName: "navigation-menu"
0111 color: folderLabel.color
0112 onClicked: menu.open()
0113 Menu {
0114 id: menu
0115
0116 // https://stackoverflow.com/questions/49599322/qt-getting-cleaner-storage-volumes-info-on-android
0117 function getMountedVolumes() {
0118 var vols = script.mountedVolumes()
0119 var result = []
0120 var i
0121 switch (Qt.platform.os) {
0122 case "android":
0123 var sd = /\/storage\/[0-9A-F]{4}-[0-9A-F]{4}/, sdc = 1
0124 var usb = /\/mnt\/media_rw\/[0-9A-F]{4}-[0-9A-F]{4}/, usbc = 1
0125 result.push({name: "Internal Storage",
0126 rootPath: "/storage/emulated/0",
0127 isValid: true,
0128 isReady: true})
0129 for (i = 0; i < vols.length; ++i) {
0130 if (sd.test(vols[i].rootPath)) {
0131 vols[i].name = "SD Card " + sdc++
0132 result.push(vols[i])
0133 } else if (usb.test(vols[i].rootPath)) {
0134 vols[i].name = "USB drive " + usbc++
0135 result.push(vols[i])
0136 }
0137 }
0138 return result
0139 case "linux":
0140 for (i = 0; i < vols.length; ++i) {
0141 var path = vols[i].rootPath
0142 if (path.indexOf("/media/") !== -1 ||
0143 (path.substr(0, 4) !== "/run" &&
0144 path.substr(0, 5) !== "/snap")) {
0145 result.push(vols[i])
0146 }
0147 }
0148 return result
0149 }
0150 return vols
0151 }
0152
0153 function addEntry(text, path) {
0154 // This will cause a warning, is there a workaround?
0155 // Created graphical object was not placed in the graphics scene.
0156 menu.addItem(menuItem.createObject(menu, {text: text, path: path}))
0157 }
0158
0159 function setupEntries() {
0160 while (menu.itemAt(0)) {
0161 menu.removeItem(menu.itemAt(0))
0162 }
0163 menu.addEntry("Music", script.musicPath())
0164 var vols = getMountedVolumes();
0165 for (var i = 0; i < vols.length; ++i) {
0166 var vol = vols[i]
0167 if (vol.isValid && vol.isReady && !vol.isReadOnly) {
0168 menu.addEntry(vol.name || vol.displayName || vol.path,
0169 vol.rootPath)
0170 }
0171 }
0172 }
0173
0174 Component {
0175 id: menuItem
0176 MenuItem {
0177 property string path
0178 onTriggered: {
0179 folderField.text = path
0180 setFolder(path)
0181 if (!page.saveMode) {
0182 currentFileField.text = ""
0183 }
0184 }
0185 }
0186 }
0187 }
0188 }
0189 Label {
0190 text: qsTr("File")
0191 }
0192 TextField {
0193 id: currentFileField
0194 Layout.fillWidth: true
0195 Layout.columnSpan: 2
0196 selectByMouse: true
0197 onEditingFinished: {
0198 setCurrentFile(text)
0199 }
0200 }
0201 }
0202 ListView {
0203 id: fileListView
0204 Layout.maximumWidth: parent.width
0205 Layout.fillWidth: true
0206 Layout.fillHeight: true
0207
0208 clip: true
0209
0210 model: FolderListModel {
0211 id: folderListModel
0212 showDotAndDotDot: page.showDotAndDotDot
0213 showHidden: page.showHidden
0214 showDirsFirst: page.showDirsFirst
0215 showOnlyReadable: true
0216 folder: page.folder
0217 nameFilters: page.nameFilters
0218 }
0219
0220 delegate: Standard {
0221 id: fileDelegate
0222 progression: fileIsDir
0223 onClicked: {
0224 if (!fileIsDir) {
0225 ListView.view.currentIndex = index
0226 currentFileField.text = fileName
0227 return;
0228 }
0229 if (!page.saveMode) {
0230 currentFileField.text = ""
0231 }
0232 ListView.view.currentIndex = -1
0233 var currentPath = simplifyPath(folderField.text)
0234 if (currentPath === "") {
0235 currentPath = "/"
0236 }
0237 var selectedDirName = fileName
0238 if (selectedDirName === "..") {
0239 if (currentPath !== "/") {
0240 folderField.text = simplifyPath(folderListModel.parentFolder)
0241 folderListModel.folder = folderListModel.parentFolder
0242 }
0243 } else if (selectedDirName === ".") {
0244 folderField.text = simplifyPath(folderListModel.folder)
0245 } else {
0246 if (currentPath === "/") {
0247 folderListModel.folder = "file:///" + selectedDirName
0248 } else {
0249 folderListModel.folder += "/" + selectedDirName
0250 }
0251 if (currentPath[currentPath.length - 1] !== "/") {
0252 currentPath += "/"
0253 }
0254 currentPath += selectedDirName
0255 folderField.text = currentPath
0256 }
0257 }
0258 highlighted: ListView.isCurrentItem
0259 background: Rectangle {
0260 color: highlighted ? constants.highlightColor : "transparent"
0261 }
0262
0263 Row {
0264 anchors.fill: parent
0265
0266 Label {
0267 id: fileText
0268 anchors.verticalCenter: parent.verticalCenter
0269 text: fileName
0270 color: fileDelegate.highlighted
0271 ? constants.highlightedTextColor : constants.textColor
0272 }
0273 }
0274 }
0275 }
0276 }
0277 onOpened: {
0278 folderField.text = page.folder
0279 currentFileField.text = page.currentFile
0280 setFolder(page.folder)
0281 setCurrentFile(page.currentFile)
0282 menu.setupEntries()
0283 }
0284 }