diff --git a/src/controls/ColorsBar.qml b/src/controls/ColorsBar.qml index 73700d8..8cd29f3 100644 --- a/src/controls/ColorsBar.qml +++ b/src/controls/ColorsBar.qml @@ -1,141 +1,138 @@ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami Row { signal colorPicked(string color) anchors.verticalCenter: parent.verticalCenter spacing: Maui.Style.space.medium property string currentColor property int size : Maui.Style.iconSizes.medium Rectangle { color:"#f21b51" anchors.verticalCenter: parent.verticalCenter height: size width: height radius: Maui.Style.radiusV border.color: Qt.darker(color, 1.7) MouseArea { anchors.fill: parent onClicked: { currentColor = parent.color colorPicked("folder-red") } } } Rectangle { color:"#f9a32b" anchors.verticalCenter: parent.verticalCenter height: size width: height radius: Maui.Style.radiusV border.color: Qt.darker(color, 1.7) MouseArea { anchors.fill: parent onClicked: { currentColor = parent.color colorPicked("folder-orange") } } } Rectangle { color:"#3eb881" anchors.verticalCenter: parent.verticalCenter height: size width: height radius: Maui.Style.radiusV border.color: Qt.darker(color, 1.7) MouseArea { anchors.fill: parent onClicked: { currentColor = parent.color colorPicked("folder-green") } } } Rectangle { color:"#b2b9bd" anchors.verticalCenter: parent.verticalCenter height: size width: height radius: Maui.Style.radiusV border.color: Qt.darker(color, 1.7) MouseArea { anchors.fill: parent onClicked: { currentColor = parent.color colorPicked("folder-grey") } - } - + } } - - Rectangle { color:"#474747" anchors.verticalCenter: parent.verticalCenter height: size width: height radius: Maui.Style.radiusV border.color: Qt.darker(color, 1.7) MouseArea { anchors.fill: parent onClicked: { currentColor = parent.color colorPicked("folder-black") } } } Kirigami.Icon { anchors.verticalCenter: parent.verticalCenter height: size width: height source: "edit-clear" color: Kirigami.Theme.textColor MouseArea { anchors.fill: parent onClicked: { currentColor = parent.color colorPicked("folder") } } } } diff --git a/src/controls/FileBrowser.qml b/src/controls/FileBrowser.qml index 9d40556..62179df 100644 --- a/src/controls/FileBrowser.qml +++ b/src/controls/FileBrowser.qml @@ -1,1120 +1,1118 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import QtQml.Models 2.3 import QtQml 2.1 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Maui.Page { id: control property url currentPath onCurrentPathChanged: control.browserView.path = control.currentPath property int viewType : Maui.FMList.LIST_VIEW onViewTypeChanged: browserView.viewType = control.viewType property int currentPathType : control.currentFMList.pathType property int thumbnailsSize : Maui.Style.iconSizes.large * 1.7 property bool showThumbnails: true - property var copyItems : [] - property var cutItems : [] + property var clipboardItems : [] property var indexHistory : [] property bool isCopy : false property bool isCut : false property bool selectionMode : false property bool singleSelection: false property bool group : false property bool showEmblems: true //group properties from the browser since the browser views are loaded async and //their properties can not be accesed inmediately property BrowserSettings settings : BrowserSettings {} property alias selectionBar : selectionBarLoader.item property alias browserView : _browserList.currentItem property Maui.FMList currentFMList : browserView.currentFMList property alias previewer : previewer property alias menu : browserMenu.contentData property alias itemMenu: itemMenu property alias dialog : dialogLoader.item signal itemClicked(int index) signal itemDoubleClicked(int index) signal itemRightClicked(int index) signal itemLeftEmblemClicked(int index) signal itemRightEmblemClicked(int index) signal rightClicked() signal newBookmark(var paths) Kirigami.Theme.colorSet: Kirigami.Theme.View Kirigami.Theme.inherit: false onGoBackTriggered: control.goBack() onGoForwardTriggered: control.goNext() focus: true footBar.visible: false footBar.leftContent: Label { Layout.fillWidth: true text: control.currentFMList.count + " " + qsTr("items") } footBar.rightContent: [ ToolButton { icon.name: "zoom-in" onClicked: zoomIn() }, ToolButton { icon.name: "zoom-out" onClicked: zoomOut() } ] headBar.visible: currentPathType !== Maui.FMList.APPS_PATH headBar.position: Kirigami.Settings.isMobile ? ToolBar.Footer : ToolBar.Header property list t_actions: [ Action { id: _previewAction icon.name: "image-preview" text: qsTr("Previews") checkable: true checked: control.showThumbnails onTriggered: control.showThumbnails = !control.showThumbnails }, Action { id: _hiddenAction icon.name: "visibility" text: qsTr("Hidden files") checkable: true checked: control.currentFMList.hidden onTriggered: control.currentFMList.hidden = !control.currentFMList.hidden }, Action { id: _bookmarkAction icon.name: "bookmark-new" text: qsTr("Bookmark") onTriggered: newBookmark([currentPath]) }, Action { id: _newFolderAction icon.name: "folder-add" text: qsTr("New folder") onTriggered: { dialogLoader.sourceComponent= newFolderDialogComponent dialog.open() } }, Action { id: _newDocumentAction icon.name: "document-new" text: qsTr("New file") onTriggered: { dialogLoader.sourceComponent= newFileDialogComponent dialog.open() } }, Action { id: _pasteAction - text: qsTr("Paste ")+"["+browserMenu.pasteFiles+"]" + text: qsTr("Paste ")+"["+control.clipboardItems.length+"]" icon.name: "edit-paste" - enabled: browserMenu.pasteFiles > 0 + enabled: control.clipboardItems.length > 0 onTriggered: paste() }, Action { id: _selectAllAction text: qsTr("Select all") icon.name: "edit-select-all" onTriggered: selectAll() }, Action { text: qsTr("Status bar") icon.name: "settings-configure" checkable: true checked: control.footBar.visible onTriggered: control.footBar.visible = !control.footBar.visible } ] Loader { id: dialogLoader } Component { id: removeDialogComponent Maui.Dialog { property var items: [] title: qsTr(String("Removing %1 files").arg(items.length.toString())) message: isAndroid ? qsTr("This action will completely remove your files from your system. This action can not be undone.") : qsTr("You can move the file to the Trash or Delete it completely from your system. Which one you preffer?") rejectButton.text: qsTr("Delete") acceptButton.text: qsTr("Trash") acceptButton.visible: !Kirigami.Settings.isMobile page.padding: Maui.Style.space.huge onRejected: { if(control.selectionBar && control.selectionBar.visible) { control.selectionBar.clear() control.selectionBar.animate(Maui.Style.dangerColor) } control.remove(items) close() } onAccepted: { if(control.selectionBar && control.selectionBar.visible) { control.selectionBar.clear() control.selectionBar.animate(Maui.Style.dangerColor) } control.trash(items) close() } } } Component { id: newFolderDialogComponent Maui.NewDialog { title: qsTr("New folder") message: qsTr("Create a new folder with a custom name") acceptButton.text: qsTr("Create") onFinished: control.currentFMList.createDir(text) rejectButton.visible: false textEntry.placeholderText: qsTr("Folder name...") } } Component { id: newFileDialogComponent Maui.NewDialog { title: qsTr("New file") message: qsTr("Create a new file with a custom name and extension") acceptButton.text: qsTr("Create") onFinished: Maui.FM.createFile(control.currentPath, text) rejectButton.visible: false textEntry.placeholderText: qsTr("File name...") } } Component { id: renameDialogComponent Maui.NewDialog { title: qsTr("Rename file") message: qsTr("Rename a file or folder to a new custom name") textEntry.text: itemMenu.item.label textEntry.placeholderText: qsTr("New name...") onFinished: Maui.FM.rename(itemMenu.item.path, textEntry.text) onRejected: close() acceptText: qsTr("Rename") rejectText: qsTr("Cancel") } } Component { id: shareDialogComponent Maui.ShareDialog {} } Component { id: tagsDialogComponent Maui.TagsDialog { onTagsReady: { composerList.updateToUrls(tags) if(previewer.visible) previewer.tagBar.list.refresh() } } } BrowserMenu { id: browserMenu - z : control.z +1 } Maui.FilePreviewer { id: previewer onShareButtonClicked: control.shareFiles([url]) } FileMenu { id: itemMenu width: Maui.Style.unit *200 onBookmarkClicked: control.newBookmark([item.path]) onCopyClicked: { if(item) control.copy([item]) } onCutClicked: { if(item) control.cut([item]) } onTagsClicked: { if(item) { dialogLoader.sourceComponent = tagsDialogComponent dialog.composerList.urls = [item.path] dialog.open() } } onRenameClicked: { dialogLoader.sourceComponent = renameDialogComponent dialog.open() } onRemoveClicked: { dialogLoader.sourceComponent= removeDialogComponent dialog.items = [item] dialog.open() } onShareClicked: control.shareFiles([item.path]) } Connections { target: browserView.currentView onItemClicked: { console.log("item clicked connections:", index) browserView.currentView.currentIndex = index indexHistory.push(index) control.itemClicked(index) } onItemDoubleClicked: { browserView.currentView.currentIndex = index indexHistory.push(index) control.itemDoubleClicked(index) } onItemRightClicked: { if(currentFMList.pathType !== Maui.FMList.TRASH_PATH && currentFMList.pathType !== Maui.FMList.REMOTE_PATH ) itemMenu.show(index) control.itemRightClicked(index) } onLeftEmblemClicked: { const item = control.currentFMList.get(index) if(control.selectionBar && control.selectionBar.contains(item.path)) { control.selectionBar.removeAtPath(item.path) }else { control.addToSelection(item) } control.itemLeftEmblemClicked(index) } onRightEmblemClicked: { isAndroid ? Maui.Android.shareDialog([control.currentFMList.get(index).path]) : shareDialog.show([control.currentFMList.get(index).path]) control.itemRightEmblemClicked(index) } onAreaClicked: { if(!Kirigami.Settings.isMobile && mouse.button === Qt.RightButton) browserMenu.show() else return control.rightClicked() } onAreaRightClicked: browserMenu.show() } headBar.rightContent:[ Kirigami.ActionToolBar { position: ToolBar.Header Layout.fillWidth: true hiddenActions: t_actions display: ToolButton.IconOnly actions: [ Action { icon.name: "view-list-icons" onTriggered: control.viewType = Maui.FMList.ICON_VIEW checkable: false checked: browserView.viewType === Maui.FMList.ICON_VIEW icon.width: Maui.Style.iconSizes.medium text: qsTr("Grid view") // autoExclusive: true }, Action { icon.name: "view-list-details" onTriggered: control.viewType = Maui.FMList.LIST_VIEW icon.width: Maui.Style.iconSizes.medium checked: browserView.viewType === Maui.FMList.LIST_VIEW text: qsTr("List view") // autoExclusive: true }, Action { icon.name: "view-file-columns" onTriggered: control.viewType = Maui.FMList.MILLERS_VIEW icon.width: Maui.Style.iconSizes.medium checked: browserView.viewType === Maui.FMList.MILLERS_VIEW text: qsTr("Column view") // autoExclusive: true }, Kirigami.Action { icon.name: "view-sort" text: qsTr("Sort") Kirigami.Action { text: qsTr("Folders first") checked: control.currentFMList.foldersFirst checkable: true onTriggered: control.currentFMList.foldersFirst = !control.currentFMList.foldersFirst } Kirigami.Action { text: qsTr("Type") checked: control.currentFMList.sortBy === Maui.FMList.MIME checkable: true onTriggered: control.currentFMList.sortBy = Maui.FMList.MIME } Kirigami.Action { text: qsTr("Date") checked: control.currentFMList.sortBy === Maui.FMList.DATE checkable: true onTriggered: control.currentFMList.sortBy = Maui.FMList.DATE } Kirigami.Action { text: qsTr("Modified") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.MODIFIED onTriggered: control.currentFMList.sortBy = Maui.FMList.MODIFIED } Kirigami.Action { text: qsTr("Size") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.SIZE onTriggered: control.currentFMList.sortBy = Maui.FMList.SIZE } Kirigami.Action { text: qsTr("Name") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.LABEL onTriggered: control.currentFMList.sortBy = Maui.FMList.LABEL } Kirigami.Action { id: groupAction text: qsTr("Group") checkable: true checked: control.group onTriggered: { control.group = !control.group if(control.group) groupBy() else browserView.currentView.section.property = "" } } }, Kirigami.Action { text: qsTr("Select mode") icon.name: "item-select" checkable: true checked: control.selectionMode onTriggered: control.selectionMode = !control.selectionMode } ] } ] headBar.leftContent: [ ToolButton { icon.name: "go-previous" onClicked: control.goBack() }, // ToolButton // { // id: goUpButton // visible: true // icon.name: "go-up" // onClicked: control.goUp() // }, ToolButton { icon.name: "go-next" onClicked: control.goNext() } ] Component { id: selectionBarComponent Maui.SelectionBar { anchors.fill: parent onIconClicked: _selectionBarmenu.popup() onExitClicked: clean() onItemClicked: removeAtIndex(index) Menu { id: _selectionBarmenu MenuItem { text: qsTr("Copy") onTriggered: if(control.selectionBar) { control.selectionBar.animate("#6fff80") control.copy(selectedItems) - console.log(selectedItems) _selectionBarmenu.close() } } MenuItem { text: qsTr("Cut") onTriggered: if(control.selectionBar) { control.selectionBar.animate("#fff44f") control.cut(selectedItems) _selectionBarmenu.close() } } MenuItem { text: qsTr("Share") onTriggered: { control.shareFiles(selectedPaths) _selectionBarmenu.close() } } MenuItem { text: qsTr("Tags") onTriggered: if(control.selectionBar) { dialogLoader.sourceComponent = tagsDialogComponent dialog.composerList.urls = selectedPaths dialog.open() _selectionBarmenu.close() } } MenuSeparator{} MenuItem { text: qsTr("Remove") Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor onTriggered: { dialogLoader.sourceComponent= removeDialogComponent dialog.items = selectedItems dialog.open() _selectionBarmenu.close() } } } } } ObjectModel { id: tabsObjectModel } ColumnLayout { anchors.fill: parent spacing: 0 TabBar { id: tabsBar visible: _browserList.count > 1 Layout.fillWidth: true Layout.preferredHeight: visible ? Maui.Style.rowHeight : 0 Kirigami.Theme.colorSet: Kirigami.Theme.View Kirigami.Theme.inherit: false currentIndex : _browserList.currentIndex clip: true ListModel { id: tabsListModel } background: null Repeater { id: _repeater model: tabsListModel TabButton { id: _tabButton readonly property int minTabWidth: 150 * Maui.Style.unit implicitWidth: control.width / _repeater.count implicitHeight: Maui.Style.rowHeight checked: index === _browserList.currentIndex onClicked: { _browserList.currentIndex = index control.currentPath = tabsObjectModel.get(index).path } background: Rectangle { color: "transparent" Kirigami.Separator { z: tabsBar.z + 1 width: Maui.Style.unit anchors { bottom: parent.bottom top: parent.top right: parent.right } } Kirigami.Separator { color: Kirigami.Theme.highlightColor z: tabsBar.z + 1 height: Maui.Style.unit * 2 visible: checked anchors { bottom: parent.bottom left: parent.left right: parent.right } } } contentItem: RowLayout { spacing: 0 Label { text: tabsObjectModel.get(index).currentFMList.pathName font.pointSize: Maui.Style.fontSizes.default Layout.fillWidth: true Layout.fillHeight: true Layout.margins: Maui.Style.space.small Layout.alignment: Qt.AlignCenter verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter color: checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor wrapMode: Text.NoWrap elide: Text.ElideRight } ToolButton { Layout.preferredHeight: Maui.Style.iconSizes.medium Layout.preferredWidth: Maui.Style.iconSizes.medium icon.height: Maui.Style.iconSizes.medium icon.width: Maui.Style.iconSizes.width Layout.margins: Maui.Style.space.medium Layout.alignment: Qt.AlignRight icon.name: "dialog-close" onClicked: { const removedIndex = index tabsObjectModel.remove(removedIndex) tabsListModel.remove(removedIndex) } } } } } } Kirigami.Separator { visible: tabsBar.visible color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) Layout.fillWidth: true Layout.preferredHeight: 1 } ListView { id: _browserList Layout.margins: 0 Layout.fillWidth: true Layout.fillHeight: true clip: true focus: true // Keys.onSpacePressed: previewer.show(control.currentFMList.get(browser.currentIndex).path) orientation: ListView.Horizontal model: tabsObjectModel snapMode: ListView.SnapOneItem spacing: 0 interactive: Kirigami.Settings.isMobile && tabsObjectModel.count > 1 highlightFollowsCurrentItem: true highlightMoveDuration: 0 onMovementEnded: _browserList.currentIndex = indexAt(contentX, contentY) } Loader { id: selectionBarLoader Layout.fillWidth: true Layout.preferredHeight: control.selectionBar && control.selectionBar.visible ? control.selectionBar.barHeight: 0 Layout.leftMargin: Maui.Style.contentMargins * (Kirigami.Settings.isMobile ? 3 : 2) Layout.rightMargin: Maui.Style.contentMargins * (Kirigami.Settings.isMobile ? 3 : 2) Layout.bottomMargin: control.selectionBar && control.selectionBar.visible ? Maui.Style.contentMargins*2 : 0 } ProgressBar { id: _progressBar Layout.fillWidth: true Layout.alignment: Qt.AlignBottom Layout.preferredHeight: visible ? Maui.Style.iconSizes.medium : 0 visible: value > 0 } } Component.onCompleted: { openTab(Maui.FM.homePath()) // browserView.viewType = control.viewType control.setSettings() } onThumbnailsSizeChanged: { if(settings.trackChanges && settings.saveDirProps) Maui.FM.setDirConf(currentPath+"/.directory", "MAUIFM", "IconSize", thumbnailsSize) else Maui.FM.saveSettings("IconSize", thumbnailsSize, "SETTINGS") if(control.viewType === Maui.FMList.ICON_VIEW) browserView.currentView.adaptGrid() } function setSettings() { if(control.currentFMList !== null) { control.currentFMList.onlyDirs= control.settings.onlyDirs control.currentFMList.filters= control.settings.filters control.currentFMList.sortBy= control.settings.sortBy control.currentFMList.filterType= control.settings.filterType control.currentFMList.trackChanges= control.settings.trackChanges control.currentFMList.saveDirProps= control.settings.saveDirProps } } function openTab(path) { const component = Qt.createComponent("private/BrowserView.qml"); if (component.status === Component.Ready) { const object = component.createObject(tabsObjectModel); tabsObjectModel.append(object); } tabsListModel.append({ title: qsTr("Untitled"), path: path, }) _browserList.currentIndex = tabsObjectModel.count - 1 if(path) { setTabMetadata(path) browserView.viewType = control.viewType openFolder(path) } } function setTabMetadata(filepath) { tabsListModel.setProperty(tabsBar.currentIndex, "path", filepath) } function shareFiles(urls) { if(urls.length <= 0) return; if(isAndroid) { Maui.Android.shareDialog(urls[0]) } else { dialogLoader.sourceComponent= shareDialogComponent dialog.show(urls) } } function openItem(index) { const item = control.currentFMList.get(index) const path = item.path switch(currentPathType) { case Maui.FMList.APPS_PATH: if(item.path.endsWith("/")) { populate(path) } else { Maui.FM.runApplication(path) } break case Maui.FMList.CLOUD_PATH: if(item.mime === "inode/directory") { control.openFolder(path) } else { Maui.FM.openCloudItem(item) } break; default: if(selectionMode && !Maui.FM.isDir(item.path)) { if(control.selectionBar && control.selectionBar.contains(item.path)) { control.selectionBar.removeAtPath(item.path) }else { control.addToSelection(item) } } else { if(item.mime === "inode/directory") { control.openFolder(path) } else if(Maui.FM.isApp(path)) { control.launchApp(path) } else { if (Kirigami.Settings.isMobile) { previewer.show(path) } else { control.openFile(path) } } } } } function launchApp(path) { Maui.FM.runApplication(path, "") } function openFile(path) { Maui.FM.openUrl(path) } function openFolder(path) { populate(Maui.FM.fileDir(path))// make sure the path is a dir // file to dir } function setPath(path) { control.currentPath = path } function populate(path) { if(!path.length) return; browserView.currentView.currentIndex = -1 setPath(path) // if(currentPathType === Maui.FMList.PLACES_PATH) // { // if(trackChanges && saveDirProps) // { // var conf = Maui.FM.dirConf(path+"/.directory") // var iconsize = conf["iconsize"] || Maui.Style.iconSizes.large // thumbnailsSize = parseInt(iconsize) // }else // { // thumbnailsSize = parseInt(Maui.FM.loadSettings("IconSize", "SETTINGS", thumbnailsSize)) // } // } // // if(browserView.viewType == Maui.FMList.ICON_VIEW) // browser.adaptGrid() } function goBack() { populate(control.currentFMList.previousPath) browserView.currentView.currentIndex = indexHistory.pop() } function goNext() { openFolder(control.currentFMList.posteriorPath) } function goUp() { openFolder(control.currentFMList.parentPath) } function refresh() { const pos = browserView.currentView.contentY browserView.currentView.contentY = pos } function addToSelection(item) { - if(!selectionBar) + if(!control.selectionBar) selectionBarLoader.sourceComponent = selectionBarComponent - selectionBar.singleSelection = control.singleSelection - selectionBar.append(item) + control.selectionBar.singleSelection = control.singleSelection + control.selectionBar.append(item) } function clean() { - copyItems = [] - cutItems = [] + control.clipboardItems = [] browserMenu.pasteFiles = 0 if(control.selectionBar && control.selectionBar.visible) selectionBar.clear() } function copy(items) { - copyItems = items - isCut = false - isCopy = true + control.clipboardItems = items + control.isCut = false + control.isCopy = true } function cut(items) { - cutItems = items - isCut = true - isCopy = false + control.clipboardItems = items + control.isCut = true + control.isCopy = false } function paste() { - if(isCopy) - currentFMList.copyInto(copyItems) - else if(isCut) - { - currentFMList.cutInto(cutItems) - clean() - } + if(control.isCopy) + { + control.currentFMList.copyInto(control.clipboardItems) + } + else if(control.isCut) + { + control.currentFMList.cutInto(control.clipboardItems) + control.clean() + } } function remove(items) { for(var i in items) Maui.FM.removeFile(items[i].path) } function selectAll() //TODO for now dont select more than 100 items so things dont freeze or break { for(var i = 0; i < Math.min(control.currentFMList.count, 100); i++) addToSelection(control.currentFMList.get(i)) } function trash(items) { for(var i in items) Maui.FM.moveToTrash(items[i].path) } function bookmarkFolder(paths) { newBookmark(paths) } function zoomIn() { control.thumbnailsSize = control.thumbnailsSize + 8 } function zoomOut() { const newSize = control.thumbnailsSize - 8 if(newSize >= Maui.Style.iconSizes.small) control.thumbnailsSize = newSize } function groupBy() { var prop = "" var criteria = ViewSection.FullString switch(control.currentFMList.sortBy) { case Maui.FMList.LABEL: prop = "label" criteria = ViewSection.FirstCharacter break; case Maui.FMList.MIME: prop = "mime" break; case Maui.FMList.SIZE: prop = "size" break; case Maui.FMList.DATE: prop = "date" break; case Maui.FMList.MODIFIED: prop = "modified" break; } browserView.viewType = Maui.FMList.LIST_VIEW if(!prop) { browserView.currentView.section.property = "" return } browserView.currentView.section.property = prop browserView.currentView.section.criteria = criteria } } diff --git a/src/controls/private/BrowserMenu.qml b/src/controls/private/BrowserMenu.qml index 27dff94..2fd1992 100644 --- a/src/controls/private/BrowserMenu.qml +++ b/src/controls/private/BrowserMenu.qml @@ -1,68 +1,49 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.6 as Kirigami Menu { - property int pasteFiles : 0 - - // popup.z : 999 - - /* Maui.MenuItem - * { - * che - * ckable: true - * checked: saveDirProps - * text: qsTr("Per dir props") - * onTriggered: saveDirProps = !saveDirProps -}*/ - // property list actions: t_actions - MenuItem { action: _previewAction } MenuItem { action: _hiddenAction } MenuItem { action: _bookmarkAction } MenuItem { action: _newFolderAction } MenuItem { action: _newDocumentAction } MenuItem { action: _pasteAction } function show() { if(currentPathType === Maui.FMList.PLACES_PATH || currentPathType === Maui.FMList.TAGS_PATH || currentPathType === Maui.FMList.CLOUD_PATH) { - if(isCopy) - pasteFiles = copyItems.length - else if(isCut) - pasteFiles = cutItems.length - popup() } } } diff --git a/src/fm/fm.cpp b/src/fm/fm.cpp index 1574cfd..30e93a4 100644 --- a/src/fm/fm.cpp +++ b/src/fm/fm.cpp @@ -1,937 +1,937 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fm.h" #include "utils.h" #include "tagging.h" #include "syncing.h" #include #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #else #include "mauikde.h" #include #include #include #include #include #include #include #endif /* * FM *FM::instance = nullptr; * * FM* FM::getInstance() * { * if(!instance) * { * instance = new FM(); * qDebug() << "getInstance(): First instance\n"; * instance->init(); * return instance; * } else * { * qDebug()<< "getInstance(): previous instance\n"; * return instance; * } * }*/ #ifdef Q_OS_ANDROID FM::FM(QObject *parent) : FMDB(parent), sync(new Syncing(this)), tag(Tagging::getInstance()) #else FM::FM(QObject *parent) : FMDB(parent), sync(new Syncing(this)), tag(Tagging::getInstance()), dirLister(new KCoreDirLister(this)) #endif { #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) this->dirLister->setAutoUpdate(true); connect(dirLister, static_cast(&KCoreDirLister::completed), [&](QUrl url) { qDebug()<< "PATH CONTENT READY" << url; FMH::PATH_CONTENT res; FMH::MODEL_LIST content; for(const auto &kfile : dirLister->items()) { qDebug() << kfile.url() << kfile.name() << kfile.isDir(); content << FMH::MODEL{ {FMH::MODEL_KEY::LABEL, kfile.name()}, {FMH::MODEL_KEY::NAME, kfile.name()}, {FMH::MODEL_KEY::DATE, kfile.time(KFileItem::FileTimes::CreationTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::MODIFIED, kfile.time(KFileItem::FileTimes::ModificationTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::LAST_READ, kfile.time(KFileItem::FileTimes::AccessTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::PATH, kfile.url().toString()}, {FMH::MODEL_KEY::THUMBNAIL, kfile.localPath()}, {FMH::MODEL_KEY::SYMLINK, kfile.linkDest()}, {FMH::MODEL_KEY::IS_SYMLINK, QVariant(kfile.isLink()).toString()}, {FMH::MODEL_KEY::HIDDEN, QVariant(kfile.isHidden()).toString()}, {FMH::MODEL_KEY::IS_DIR, QVariant(kfile.isDir()).toString()}, {FMH::MODEL_KEY::IS_FILE, QVariant(kfile.isFile()).toString()}, {FMH::MODEL_KEY::WRITABLE, QVariant(kfile.isWritable()).toString()}, {FMH::MODEL_KEY::READABLE, QVariant(kfile.isReadable()).toString()}, {FMH::MODEL_KEY::EXECUTABLE, QVariant(kfile.isDesktopFile()).toString()}, {FMH::MODEL_KEY::MIME, kfile.mimetype()}, {FMH::MODEL_KEY::GROUP, kfile.group()}, {FMH::MODEL_KEY::ICON, kfile.iconName()}, {FMH::MODEL_KEY::SIZE, QString::number(kfile.size())}, {FMH::MODEL_KEY::THUMBNAIL, kfile.mostLocalUrl().toString()}, {FMH::MODEL_KEY::OWNER, kfile.user()}, {FMH::MODEL_KEY::COUNT, kfile.isLocalFile() && kfile.isDir() ? QString::number(QDir(kfile.localPath()).count() - 2) : "0"} }; } res.path = url.toString(); res.content = content; emit this->pathContentReady(res); }); connect(dirLister, static_cast(&KCoreDirLister::itemsAdded), [&]() { qDebug()<< "MORE ITEMS WERE ADDED"; emit this->pathContentChanged(dirLister->url()); }); connect(dirLister, static_cast(&KCoreDirLister::newItems), [&]() { qDebug()<< "MORE NEW ITEMS WERE ADDED"; emit this->pathContentChanged(dirLister->url()); }); connect(dirLister, static_cast(&KCoreDirLister::itemsDeleted), [&]() { qDebug()<< "ITEMS WERE DELETED"; dirLister->updateDirectory(dirLister->url()); // emit this->pathContentChanged(dirLister->url()); // changes when dleted items are not that important? }); connect(dirLister, static_cast > &items)>(&KCoreDirLister::refreshItems), [&]() { qDebug()<< "ITEMS WERE REFRESHED"; dirLister->updateDirectory(dirLister->url()); emit this->pathContentChanged(dirLister->url()); }); #endif connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QString &url) { emit this->cloudServerContentReady(list, url); }); connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QString &url, const Syncing::SIGNAL_TYPE &signalType) { switch(signalType) { case Syncing::SIGNAL_TYPE::OPEN: this->openUrl(item[FMH::MODEL_KEY::PATH]); break; case Syncing::SIGNAL_TYPE::DOWNLOAD: emit this->cloudItemReady(item, url); break; case Syncing::SIGNAL_TYPE::COPY: { QVariantMap data; for(auto key : item.keys()) data.insert(FMH::MODEL_NAME[key], item[key]); this->copy(QVariantList {data}, this->sync->getCopyTo()); break; } default: return; } }); connect(this->sync, &Syncing::error, [this](const QString &message) { emit this->warningMessage(message); }); connect(this->sync, &Syncing::progress, [this](const int &percent) { emit this->loadProgress(percent); }); connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QString &url) { emit this->newItem(dir, url); }); connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QString &url) { emit this->newItem(item, url); }); } FM::~FM() {} QVariantMap FM::toMap(const FMH::MODEL& model) { return FMH::toMap(model); } FMH::MODEL FM::toModel(const QVariantMap& map) { return FMH::toModel(map); } FMH::MODEL_LIST FM::packItems(const QStringList &items, const QString &type) { FMH::MODEL_LIST data; for(const auto &path : items) if(FMH::fileExists(path)) { auto model = FMH::getFileInfoModel(path); model.insert(FMH::MODEL_KEY::TYPE, type); data << model; } return data; } QVariantList FM::get(const QString &queryTxt) { QVariantList mapList; auto query = this->getQuery(queryTxt); if(query.exec()) { while(query.next()) { QVariantMap data; for(auto key : FMH::MODEL_NAME.keys()) if(query.record().indexOf(FMH::MODEL_NAME[key]) > -1) data[FMH::MODEL_NAME[key]] = query.value(FMH::MODEL_NAME[key]).toString(); mapList<< data; } }else qDebug()<< query.lastError()<< query.lastQuery(); return mapList; } void FM::getPathContent(const QUrl& path, const bool &hidden, const bool &onlyDirs, const QStringList& filters, const QDirIterator::IteratorFlags &iteratorFlags) { qDebug()<< "Getting async path contents"; #ifdef Q_OS_ANDROID QFutureWatcher *watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, [this, watcher = std::move(watcher)]() { emit this->pathContentReady(watcher->future().result()); watcher->deleteLater(); }); QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT { FMH::PATH_CONTENT res; res.path = path.toString(); FMH::MODEL_LIST content; if (FM::isDir(path)) { QDir::Filters dirFilter; dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); if(hidden) dirFilter = dirFilter | QDir::Hidden | QDir::System; QDirIterator it (path.toLocalFile(), filters, dirFilter, iteratorFlags); while (it.hasNext()) content << FMH::getFileInfoModel(QUrl::fromLocalFile(it.next())); } res.content = content; return res; }); watcher->setFuture(t1); #else this->dirLister->setShowingDotFiles(hidden); this->dirLister->setDirOnlyMode(onlyDirs); this->dirLister->setNameFilter(filters.join(" ")); // if(this->dirLister->url() == path) // { // this->dirLister->emitChanges(); // return; // } if(this->dirLister->openUrl(path)) qDebug()<< "GETTING PATH CONTENT" << path; #endif } void FM::getTrashContent() { #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) if(this->dirLister->openUrl(QUrl("trash://"))) qDebug()<< "TRASH CONTENT"; #endif } FMH::MODEL_LIST FM::getAppsContent(const QString& path) { FMH::MODEL_LIST res; #if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID)) QUrl __url(path); // if(__url.scheme() == FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::APPS_PATH]) return MAUIKDE::getApps(QString(path).replace("apps://", "")); #endif return res; } FMH::MODEL_LIST FM::getDefaultPaths() { return packItems(FMH::defaultPaths, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]); } FMH::MODEL_LIST FM::getAppsPath() { #ifdef Q_OS_ANDROID return FMH::MODEL_LIST(); #endif return FMH::MODEL_LIST { FMH::MODEL { {FMH::MODEL_KEY::ICON, "system-run"}, {FMH::MODEL_KEY::LABEL, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::APPS_PATH]}, {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::APPS_PATH]}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]} } }; } FMH::MODEL_LIST FM::search(const QString& query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) { FMH::MODEL_LIST content; if(!path.isLocalFile()) { qWarning() << "URL recived is not a local file. FM::search" << path; return content; } if (FM::isDir(path)) { QDir::Filters dirFilter; dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); if(hidden) dirFilter = dirFilter | QDir::Hidden | QDir::System; QDirIterator it (path.toLocalFile(), filters, dirFilter, QDirIterator::Subdirectories); while (it.hasNext()) { auto url = it.next(); auto info = it.fileInfo(); if(info.completeBaseName().contains(query, Qt::CaseInsensitive)) { content << FMH::getFileInfoModel(QUrl::fromLocalFile(url)); } } }else qWarning() << "Search path does not exists" << path; qDebug()<< content; return content; } FMH::MODEL_LIST FM::getDevices() { FMH::MODEL_LIST drives; #if defined(Q_OS_ANDROID) drives << packItems(MAUIAndroid::sdDirs(), FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::DRIVES_PATH]); return drives; #endif return drives; } FMH::MODEL_LIST FM::getTags(const int &limit) { Q_UNUSED(limit); FMH::MODEL_LIST data; if(this->tag) { for(const auto &tag : this->tag->getUrlsTags(false)) { qDebug()<< "TAG << "<< tag; const auto label = tag.toMap().value(TAG::KEYMAP[TAG::KEYS::TAG]).toString(); data << FMH::MODEL { {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::TAGS_PATH]+label}, {FMH::MODEL_KEY::ICON, "tag"}, {FMH::MODEL_KEY::LABEL, label}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::TAGS_PATH]} }; } } return data; } bool FM::getCloudServerContent(const QString &path, const QStringList &filters, const int &depth) { const auto __list = QString(path).replace("cloud://", "/").split("/"); if(__list.isEmpty() || __list.size() < 2) { qWarning()<< "Could not parse username to get cloud server content"; return false; } auto user = __list[1]; auto data = this->get(QString("select * from clouds where user = '%1'").arg(user)); if(data.isEmpty()) return false; auto map = data.first().toMap(); user = map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString(); auto server = map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString(); auto password = map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString(); this->sync->setCredentials(server, user, password); this->sync->listContent(path, filters, depth); return true; } FMH::MODEL_LIST FM::getCloudAccounts() { auto accounts = this->get("select * from clouds"); FMH::MODEL_LIST res; for(const auto &account : accounts) { auto map = account.toMap(); res << FMH::MODEL { {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, {FMH::MODEL_KEY::ICON, "folder-cloud"}, {FMH::MODEL_KEY::LABEL, map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, {FMH::MODEL_KEY::USER, map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, {FMH::MODEL_KEY::SERVER, map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString()}, {FMH::MODEL_KEY::PASSWORD, map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString()}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::CLOUD_PATH]}}; } return res; } void FM::createCloudDir(const QString &path, const QString &name) { this->sync->createDir(path, name); } void FM::openCloudItem(const QVariantMap &item) { qDebug()<< item; FMH::MODEL data; for(const auto &key : item.keys()) data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::OPEN); } void FM::getCloudItem(const QVariantMap &item) { qDebug()<< item; FMH::MODEL data; for(const auto &key : item.keys()) data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::DOWNLOAD); } QVariantList FM::getCloudAccountsList() { QVariantList res; const auto data = this->getCloudAccounts(); for(const auto &item : data) res << FM::toMap(item); return res; } bool FM::addCloudAccount(const QString &server, const QString &user, const QString &password) { const QVariantMap account = { {FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER], server}, {FMH::MODEL_NAME[FMH::MODEL_KEY::USER], user}, {FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD], password} }; if(this->insert(FMH::TABLEMAP[FMH::TABLE::CLOUDS], account)) { emit this->cloudAccountInserted(user); return true; } return false; } bool FM::removeCloudAccount(const QString &server, const QString &user) { FMH::DB account = { {FMH::MODEL_KEY::SERVER, server}, {FMH::MODEL_KEY::USER, user}, }; if(this->remove(FMH::TABLEMAP[FMH::TABLE::CLOUDS], account)) { emit this->cloudAccountRemoved(user); return true; } return false; } QString FM::resolveUserCloudCachePath(const QString &server, const QString &user) { return FMH::CloudCachePath+"opendesktop/"+user; } QString FM::resolveLocalCloudPath(const QString& path) { return QString(path).replace(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+this->sync->getUser(), ""); } FMH::MODEL_LIST FM::getTagContent(const QString &tag) { FMH::MODEL_LIST content; for(const auto &data : this->tag->getUrls(tag, false)) { const auto url = QUrl(data.toMap().value(TAG::KEYMAP[TAG::KEYS::URL]).toString()); if(FMH::fileExists(url)) { auto item = FMH::getFileInfoModel(url); content << item; } } return content; } bool FM::addTagToUrl(const QString tag, const QUrl& url) { return this->tag->tagUrl(url.toString(), tag); } QVariantMap FM::getDirInfo(const QUrl &path, const QString &type) { return FMH::getDirInfo(path, type); } QVariantMap FM::getFileInfo(const QUrl &path) { return FMH::getFileInfo(path); } bool FM::isDefaultPath(const QString &path) { return FMH::defaultPaths.contains(path); } QUrl FM::parentDir(const QUrl &path) { if(!path.isLocalFile()) { qWarning() << "URL recived is not a local file, FM::parentDir" << path; return path; } QDir dir(path.toLocalFile()); dir.cdUp(); return QUrl::fromLocalFile(dir.absolutePath()); } bool FM::isDir(const QUrl &path) { if(!path.isLocalFile()) { qWarning() << "URL recived is not a local file. FM::isDir" << path; return false; } QFileInfo file(path.toLocalFile()); return file.isDir(); } bool FM::isApp(const QString& path) { return /*QFileInfo(path).isExecutable() ||*/ path.endsWith(".desktop"); } bool FM::isCloud(const QUrl &path) { return path.scheme() == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]; } bool FM::fileExists(const QUrl &path) { return FMH::fileExists(path); } QString FM::fileDir(const QUrl& path) { QString res = path.toString(); if(path.isLocalFile()) { const QFileInfo file(path.toLocalFile()); if(file.isDir()) res = path.toString(); else res = QUrl::fromLocalFile(file.dir().absolutePath()).toString(); }else qWarning()<< "The path is not a local one. FM::fileDir"; return res; } void FM::saveSettings(const QString &key, const QVariant &value, const QString &group) { UTIL::saveSettings(key, value, group); } QVariant FM::loadSettings(const QString &key, const QString &group, const QVariant &defaultValue) { return UTIL::loadSettings(key, group, defaultValue); } QString FM::formatSize(const int &size) { QLocale locale; return locale.formattedDataSize(size); } QString FM::formatDate(const QString &dateStr, const QString &format, const QString &initFormat) { QDateTime date; if( initFormat.isEmpty() ) date = QDateTime::fromString(dateStr, Qt::TextDate); else date = QDateTime::fromString(dateStr, initFormat); return date.toString(format); } QString FM::homePath() { return FMH::HomePath; } bool FM::cut(const QVariantList &data, const QString &where) { FMH::MODEL_LIST items; for(const auto &k : data) items << FM::toModel(k.toMap()); for(const auto &item : items) { const auto path = item[FMH::MODEL_KEY::PATH]; if(this->isCloud(path)) { this->sync->setCopyTo(where); this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); }else if(FMH::fileExists(path)) { #ifdef Q_OS_ANDROID QFile file(QUrl(path).toLocalFile()); file.rename(where+"/"+QFileInfo(QUrl(path).toLocalFile()).fileName()); #else auto job = KIO::move(QUrl(path), QUrl(where+"/"+FMH::getFileInfoModel(path)[FMH::MODEL_KEY::LABEL])); job->start(); #endif } } return true; } bool FM::copy(const QVariantList &data, const QString &where) { FMH::MODEL_LIST items; for(const auto &k : data) items << FM::toModel(k.toMap()); QStringList cloudPaths; for(const auto &item : items) { const auto path = item[FMH::MODEL_KEY::PATH]; if(this->isDir(path)) { - return FM::copyPath(path, where+"/"+QFileInfo(path).fileName(), false); + FM::copyPath(path, where+"/"+QFileInfo(path).fileName(), false); }else if(this->isCloud(path)) { this->sync->setCopyTo(where); this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); }else if(FMH::fileExists(path)) { if(this->isCloud(where)) cloudPaths << path; else FM::copyPath(path, where+"/"+FMH::getFileInfoModel(path)[FMH::MODEL_KEY::LABEL], false); } } if(!cloudPaths.isEmpty()) { qDebug()<<"UPLOAD QUEUE" << cloudPaths; const auto firstPath = cloudPaths.takeLast(); this->sync->setUploadQueue(cloudPaths); if(where.split("/").last().contains(".")) { QStringList whereList = where.split("/"); whereList.removeLast(); auto whereDir = whereList.join("/"); qDebug()<< "Trying ot copy to cloud" << where << whereDir; this->sync->upload(this->resolveLocalCloudPath(whereDir), firstPath); } else this->sync->upload(this->resolveLocalCloudPath(where), firstPath); } return true; } bool FM::copyPath(QUrl sourceDir, QUrl destinationDir, bool overWriteDirectory) { #ifdef Q_OS_ANDROID QFileInfo fileInfo(sourceDir.toLocalFile()); if(fileInfo.isFile()) QFile::copy(sourceDir.toLocalFile(), destinationDir.toLocalFile()); QDir originDirectory(sourceDir.toLocalFile()); if (!originDirectory.exists()) return false; QDir destinationDirectory(destinationDir.toLocalFile()); if(destinationDirectory.exists() && !overWriteDirectory) return false; else if(destinationDirectory.exists() && overWriteDirectory) destinationDirectory.removeRecursively(); originDirectory.mkpath(destinationDir.toLocalFile()); foreach(QString directoryName, originDirectory.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { QString destinationPath = destinationDir.toLocalFile() + "/" + directoryName; originDirectory.mkpath(destinationPath); copyPath(sourceDir.toLocalFile() + "/" + directoryName, destinationPath, overWriteDirectory); } foreach (QString fileName, originDirectory.entryList(QDir::Files)) { QFile::copy(sourceDir.toLocalFile() + "/" + fileName, destinationDir.toLocalFile() + "/" + fileName); } /*! Possible race-condition mitigation? */ QDir finalDestination(destinationDir.toLocalFile()); finalDestination.refresh(); if(finalDestination.exists()) return true; return false; #else qDebug()<< "TRYING TO COPY" << sourceDir.toLocalFile() << destinationDir.toLocalFile(); auto job = KIO::copy(QUrl(sourceDir), QUrl(destinationDir)); job->start(); return true; #endif } bool FM::removeFile(const QUrl &path) { if(!path.isLocalFile()) qWarning() << "URL recived is not a local file, FM::removeFile" << path; qDebug()<< "TRYING TO REMOVE FILE: " << path; #ifdef Q_OS_ANDROID if(QFileInfo(path.toLocalFile()).isDir()) return removeDir(path); else return QFile(path.toLocalFile()).remove(); #else auto job = KIO::del(path); job->start(); return true; #endif } void FM::moveToTrash(const QUrl &path) { if(!path.isLocalFile()) qWarning() << "URL recived is not a local file, FM::moveToTrash" << path; #ifdef Q_OS_ANDROID #else auto job = KIO::trash(path); job->start(); #endif } void FM::emptyTrash() { #ifdef Q_OS_ANDROID #else auto job = KIO::emptyTrash(); job->start(); #endif } bool FM::removeDir(const QUrl &path) { bool result = true; QDir dir(path.toLocalFile()); qDebug()<< "TRYING TO REMOVE DIR" << path << path.toLocalFile(); if (dir.exists()) { Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { if (info.isDir()) { result = removeDir(QUrl::fromLocalFile(info.absoluteFilePath())); } else { result = QFile::remove(info.absoluteFilePath()); } if (!result) { return result; } } result = dir.rmdir(path.toLocalFile()); } return result; } bool FM::rename(const QUrl &path, const QString &name) { QFile file(path.toLocalFile()); const auto url = QFileInfo(path.toLocalFile()).dir().absolutePath(); return file.rename(url+"/"+name); } bool FM::createDir(const QUrl &path, const QString &name) { QFileInfo dd(path.toLocalFile()); return QDir(path.toLocalFile()).mkdir(name); } bool FM::createFile(const QUrl &path, const QString &name) { QFile file(path.toLocalFile() + "/" + name); if(file.open(QIODevice::ReadWrite)) { file.close(); return true; } return false; } bool FM::openUrl(const QString &url) { #ifdef Q_OS_ANDROID MAUIAndroid::openUrl(url); return true; #else return QDesktopServices::openUrl(QUrl::fromUserInput(url)); #endif } void FM::openLocation(const QStringList &urls) { for(auto url : urls) QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(url).dir().absolutePath())); } void FM::runApplication(const QString& exec) { #if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID)) return MAUIKDE::launchApp(exec); #endif } QVariantMap FM::dirConf(const QUrl &path) { return FMH::dirConf(path); } void FM::setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value) { FMH::setDirConf(path, group, key, value); }