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 }