Warning, /multimedia/kid3/src/qml/app/Main.qml is written in an unsupported language. File is not indexed.

0001 /**
0002  * \file Main.qml
0003  * Main entry point for QML application.
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.Controls 2.4
0026 import QtQuick.Controls.Material 2.4
0027 import QtQml 2.11
0028 import Kid3 1.1 as Kid3
0029 
0030 ApplicationWindow {
0031   id: root
0032   visible: true
0033   visibility: Qt.platform.os === "android" ? "FullScreen" : "Windowed"
0034   objectName: "mainView"
0035   title: "Kid3"
0036   width: constants.gu(100)
0037   height: constants.gu(100)
0038 
0039   FontLoader {
0040     id: materialFont
0041     source: "../icons/kid3material.ttf"
0042   }
0043 
0044   UiConstants {
0045     id: constants
0046   }
0047 
0048   Kid3.FrameEditorObject {
0049     id: frameEditor
0050   }
0051 
0052   Kid3.ScriptUtils {
0053     id: script
0054   }
0055 
0056   Kid3.ConfigObjects {
0057     id: configs
0058   }
0059 
0060   FrameSelectDialog {
0061     id: frameSelectDialog
0062     parent: Overlay.overlay
0063 
0064     onFrameSelected: frameEditor.onFrameSelectionFinished(name)
0065 
0066     Connections {
0067       target: frameEditor
0068       onFrameSelectionRequested: frameSelectDialog.openFrameNames(frameNames)
0069     }
0070   }
0071 
0072   FrameEditDialog {
0073     id: frameEditDialog
0074     parent: Overlay.overlay
0075     onFrameEdited: frameEditor.onFrameEditFinished(frame)
0076 
0077     Connections {
0078       target: frameEditor
0079       onFrameEditRequested: frameEditDialog.openFrame(frame)
0080     }
0081   }
0082 
0083   MessageDialog {
0084     property bool doNotRevert: false
0085 
0086     signal completed(bool ok)
0087 
0088     id: saveModifiedDialog
0089     x: (parent.width - width) / 2
0090     y: parent.height / 6
0091     parent: Overlay.overlay
0092     title: qsTr("Warning")
0093     text: qsTr("The current folder has been modified.\nDo you want to save it?")
0094     onYes: {
0095       saveDirectory(function() {
0096         completed(true)
0097       })
0098     }
0099     onNo: {
0100       if (!doNotRevert) {
0101         app.deselectAllFiles()
0102         app.revertFileModifications()
0103       }
0104       completed(true)
0105     }
0106     onCancel: completed(false)
0107 
0108     // Open dialog if any file modified.
0109     // completed(ok) is signalled with false if canceled.
0110     function openIfModified() {
0111       if (app.modified && app.dirName) {
0112         open()
0113       } else {
0114         completed(true)
0115       }
0116     }
0117   }
0118 
0119   MessageDialog {
0120     property var errorMsgs: []
0121 
0122     signal completed()
0123 
0124     id: writeErrorDialog
0125     x: (parent.width - width) / 2
0126     y: parent.height / 6
0127     parent: Overlay.overlay
0128     title: qsTr("File Error")
0129     text: qsTr("Error while writing file:\n") + errorMsgs.join("\n")
0130     standardButtons: Dialog.Close
0131     onClosed: {
0132       completed()
0133     }
0134   }
0135 
0136   MessageDialog {
0137     property string externalFilesDir
0138 
0139     signal completed()
0140 
0141     id: sdCardErrorDialog
0142     x: (parent.width - width) / 2
0143     y: parent.height / 6
0144     parent: Overlay.overlay
0145     title: qsTr("File Error")
0146     text: qsTr("SD card is only writable in %1").arg(externalFilesDir)
0147     standardButtons: Dialog.Close
0148     onClosed: {
0149       completed()
0150     }
0151   }
0152 
0153   MessageDialog {
0154     property var errorMsgs: []
0155 
0156     signal completed(bool ok)
0157 
0158     id: changePermissionsDialog
0159     x: (parent.width - width) / 2
0160     y: parent.height / 6
0161     parent: Overlay.overlay
0162     title: qsTr("File Error")
0163     text: qsTr("Error while writing file. Do you want to change the permissions?")
0164           + "\n" + errorMsgs.join("\n")
0165     standardButtons: Dialog.Yes | Dialog.No
0166     onYes: {
0167       completed(true)
0168     }
0169     onNo: {
0170       completed(false)
0171     }
0172   }
0173 
0174   Shortcut {
0175     sequences: ["Esc", "Back"]
0176     enabled: pageStack.depth > 1
0177     onActivated: {
0178       pageStack.pop()
0179     }
0180   }
0181 
0182   StackView {
0183     id: pageStack
0184     initialItem: mainPage
0185     anchors.fill: parent
0186 
0187     MainPage {
0188       id: mainPage
0189       visible: false
0190       parent: Overlay.overlay
0191       onConfirmedOpenRequested: confirmedOpenDirectory(path)
0192       onSaveRequested: saveDirectory(onCompleted)
0193     }
0194   }
0195 
0196   Text {
0197     visible: false
0198     Component.onCompleted: {
0199       // Linux Desktop: pixelSize 12 => gu = 8
0200       // Android Emulator Galaxy Nexus: 32 => gu = 21
0201       constants.gridUnit = Math.max(8 * font.pixelSize / 12, 8)
0202       constants.titlePixelSize = 18 * font.pixelSize / 12
0203       constants.imageScaleFactor = Math.max(font.pixelSize / 12.0, 1.0)
0204     }
0205   }
0206 
0207   Component.onCompleted: {
0208     app.frameEditor = frameEditor
0209     app.readConfig()
0210     var path = configs.fileConfig().lastOpenedFile
0211     if (!path || !script.fileExists(path)) {
0212       path = script.musicPath()
0213     }
0214     app.openDirectory(path)
0215     if (mainPage.Material) {
0216       constants.highlightColor = mainPage.Material.primary
0217       constants.highlightedTextColor = mainPage.Material.foreground
0218       constants.textColor = mainPage.Material.foreground
0219       constants.baseColor = mainPage.Material.background
0220     }
0221   }
0222 
0223   Component.onDestruction: {
0224     app.frameEditor = null
0225   }
0226 
0227   Connections {
0228     target: app
0229 
0230     onConfirmedOpenDirectoryRequested: confirmedOpenDirectory(paths)
0231     onFileSelectionUpdateRequested: mainPage.updateCurrentSelection()
0232     onSelectedFilesUpdated: app.tagsToFrameModels()
0233     onSelectedFilesChanged: app.tagsToFrameModels()
0234   }
0235   Connections {
0236     target: app.downloadClient
0237     onDownloadFinished: app.imageDownloaded(data, contentType, url)
0238   }
0239 
0240   DropArea {
0241     anchors.fill: parent
0242     onDropped: {
0243       if (drop.hasUrls) {
0244         app.openDropUrls(drop.urls)
0245       }
0246     }
0247   }
0248 
0249   function saveDirectory(onCompleted) {
0250     var errorFiles = app.saveDirectory()
0251     var numErrorFiles = errorFiles.length
0252     if (numErrorFiles > 0) {
0253       var errorMsgs = [], notWritableFiles = []
0254       for (var i = 0; i < numErrorFiles; i++) {
0255         var errorFile = errorFiles[i]
0256         var slashPos = errorFile.lastIndexOf("/")
0257         var fileName = slashPos !== -1 ? errorFile.substr(slashPos + 1)
0258                                        : errorFile
0259         if (!script.fileIsWritable(errorFile)) {
0260           errorMsgs.push(qsTr("%1 is not writable").arg(fileName))
0261           notWritableFiles.push(errorFile)
0262         } else {
0263           errorMsgs.push(fileName)
0264         }
0265       }
0266       if (notWritableFiles.length === 0) {
0267         function resultReceived() {
0268           writeErrorDialog.completed.disconnect(resultReceived)
0269           if (onCompleted) {
0270             onCompleted();
0271           }
0272         }
0273         writeErrorDialog.errorMsgs = errorMsgs
0274         writeErrorDialog.completed.connect(resultReceived)
0275         writeErrorDialog.open()
0276       } else if (Qt.platform.os === "android" &&
0277                  notWritableFiles[0].substr(0, 19) !== "/storage/emulated/0" &&
0278                  notWritableFiles[0].substr(0, 9) === "/storage/" &&
0279                  notWritableFiles[0].indexOf(
0280                    "Android/data/net.sourceforge.kid3/") === -1) {
0281         var externalFilesDir = notWritableFiles[0].substr(
0282               0, notWritableFiles[0].indexOf("/", 9) + 1) +
0283             "Android/data/net.sourceforge.kid3/"
0284         if (!script.fileExists(externalFilesDir)) {
0285           script.makeDir(externalFilesDir)
0286         }
0287         function resultReceived() {
0288           sdCardErrorDialog.completed.disconnect(resultReceived)
0289           if (onCompleted) {
0290             onCompleted();
0291           }
0292         }
0293         sdCardErrorDialog.externalFilesDir = externalFilesDir
0294         sdCardErrorDialog.completed.connect(resultReceived)
0295         sdCardErrorDialog.open()
0296       } else {
0297         function resultReceived(ok) {
0298           changePermissionsDialog.completed.disconnect(resultReceived)
0299           if (ok) {
0300             for (var i = 0; i < notWritableFiles.length; i++) {
0301               var errorFile = notWritableFiles[i]
0302               var perms = script.getFilePermissions(errorFile)
0303               script.setFilePermissions(errorFile, perms | 0x0200)
0304             }
0305             // Try again
0306             app.saveDirectory()
0307           }
0308           if (onCompleted) {
0309             onCompleted();
0310           }
0311         }
0312         changePermissionsDialog.errorMsgs = errorMsgs
0313         changePermissionsDialog.completed.connect(resultReceived)
0314         changePermissionsDialog.open()
0315       }
0316     } else {
0317       if (onCompleted) {
0318         onCompleted();
0319       }
0320     }
0321   }
0322 
0323   function confirmedOpenDirectory(path) {
0324     function openIfCompleted(ok) {
0325       saveModifiedDialog.completed.disconnect(openIfCompleted)
0326       if (ok) {
0327         app.openDirectory(path)
0328       }
0329     }
0330 
0331     mainPage.updateCurrentSelection()
0332     saveModifiedDialog.doNotRevert = false
0333     saveModifiedDialog.completed.connect(openIfCompleted)
0334     saveModifiedDialog.openIfModified()
0335   }
0336 
0337   function confirmedQuit() {
0338     mainPage.updateCurrentSelection()
0339     saveModifiedDialog.doNotRevert = true
0340     saveModifiedDialog.completed.connect(quitIfCompleted)
0341     saveModifiedDialog.openIfModified()
0342   }
0343 
0344   function quitIfCompleted(ok) {
0345     saveModifiedDialog.completed.disconnect(quitIfCompleted)
0346     if (ok) {
0347       var currentFile = mainPage.currentFilePath()
0348       if (currentFile) {
0349         configs.fileConfig().lastOpenedFile = currentFile
0350       }
0351       app.saveConfig()
0352       Qt.quit()
0353     }
0354   }
0355 
0356   onClosing: {
0357     confirmedQuit()
0358     if (app.modified) {
0359       close.accepted = false
0360     }
0361   }
0362 }