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 }