diff --git a/src/controls/AboutDialog.qml b/src/controls/AboutDialog.qml index 297c4e0..43a9d31 100644 --- a/src/controls/AboutDialog.qml +++ b/src/controls/AboutDialog.qml @@ -1,236 +1,238 @@ /* * 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. */ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Dialog { id: control property var app : ({}) property string appName : Qt.application.name property string appVersion : Qt.application.version property string organizationName : Qt.application.organization property string organizationDomain : Qt.application.domain property string appDescription : "" property string appLink: "www.maui-project.org" property string appDonation: "" property string appIcon: "qrc:/assets/mauikit-logo.png" defaultButtons: false widthHint: 0.9 heightHint: 0.8 maxWidth: unit * 400 maxHeight: unit * 250 page.padding: space.small footBar.middleContent: ToolButton { icon.name: "link" onClicked: Maui.FM.openUrl(control.appLink) } footBar.rightContent: ToolButton { icon.name: "love" onClicked: Maui.FM.openUrl(control.appDonation) } footBar.leftContent: ToolButton { icon.name: "documentinfo" } RowLayout { id: layout anchors.centerIn: parent width: parent.width height: parent.height * 0.7 Item { Layout.fillHeight: true Layout.margins: space.small Layout.alignment: Qt.AlignHCenter | Qt.AlignTop Layout.minimumWidth: iconSizes.huge Layout.maximumWidth: iconSizes.huge Layout.preferredWidth: iconSizes.huge Layout.minimumHeight: iconSizes.huge clip: true Image { source: app.icon || control.appIcon width: iconSizes.huge height: width sourceSize.width: width sourceSize.height: height horizontalAlignment: Qt.AlignHCenter asynchronous: true fillMode: Image.PreserveAspectFit } } Item { id: _descriptionItem Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignLeft | Qt.AlignTop ScrollView { anchors.fill: parent contentHeight: _columnInfo.implicitHeight padding: 0 clip: true ColumnLayout { id: _columnInfo width: parent.width spacing: 0 Label { id: appTitle Layout.fillWidth: true // Layout.preferredHeight: implicitHeight Layout.alignment: Qt.AlignLeft clip: true width: parent.width height: parent.height color: Kirigami.Theme.textColor text: appName font.weight: Font.Bold font.bold: true font.pointSize: fontSizes.huge } Label { id: appVersion Layout.fillWidth: true // Layout.preferredHeight: fontSizes.default Layout.alignment: Qt.AlignLeft clip: true width: parent.width height: parent.height color: Qt.lighter(Kirigami.Theme.textColor, 1.2) text: app.version font.pointSize: fontSizes.default } Label { id: body // Layout.fillWidth: true // Layout.fillHeight: true Layout.preferredWidth:_descriptionItem.width padding: 0 // placeholderText: qsTr("App description") enabled: false text: appDescription - textFormat : TextEdit.AutoText +// textFormat : TextEdit.AutoText color: Kirigami.Theme.textColor font.pointSize: fontSizes.default wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere clip: true // background: Rectangle // { // color: "transparent" // } } + + Kirigami.Separator + { + Layout.fillWidth: true + Layout.preferredHeight: 1 + Layout.alignment: Qt.AlignLeft + Layout.margins: space.big + opacity: 0.4 + } + + Label + { + color: Kirigami.Theme.textColor + Layout.preferredWidth:_descriptionItem.width + + text: qsTr("Built with MauiKit " + app.mauikit_version + " and Kirigami." ) + font.pointSize: fontSizes.default + wrapMode: TextEdit.WrapAnywhere + + + } } } } - // Item - // { - // Layout.fillWidth: true - // Layout.row: 4 - // Layout.column: 2 - // Layout.margins: space.small - // Layout.alignment: Qt.AlignLeft | Qt.AlignTop - // Label - // { - // color: textColor - // width: parent.width - // height: parent.height - // - // text: qsTr("Built with MauiKit and Kirigami.") - // font.pointSize: fontSizes.default - // wrapMode: TextEdit.WrapAnywhere - // - // - // } - // } + // Item // { // Layout.fillWidth: true // Layout.fillHeight: true // Layout.row: 5 // Layout.column: 2 // Layout.margins: space.big // Layout.alignment: Qt.AlignLeft | Qt.AlignTop // // Label // { // color: textColor // width: parent.width // height: parent.height // // text: "MauiKit " + app.mauikit + " Qt " +app.qt // font.pointSize: fontSizes.default // wrapMode: TextEdit.WrapAnywhere // // } // } } onOpened : control.app = Maui.Handy.appInfo() } diff --git a/src/controls/ApplicationWindow.qml b/src/controls/ApplicationWindow.qml index aa7b1b2..7c63ead 100644 --- a/src/controls/ApplicationWindow.qml +++ b/src/controls/ApplicationWindow.qml @@ -1,594 +1,582 @@ /* * 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. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import QtQuick.Window 2.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Controls.Material 2.1 import "private" import SyncingModel 1.0 import SyncingList 1.0 Kirigami.AbstractApplicationWindow { id: root visible: true width: Screen.width * (isMobile ? 1 : 0.4) height: Screen.height * (isMobile ? 1 : 0.4) // contentItem.anchors.leftMargin: root.globalDrawer && (root.globalDrawer.modal === false) ? root.globalDrawer.contentItem.width * root.globalDrawer.position : 0 // contentItem.anchors.left: contentItem.parent.left // contentItem.anchors.right: contentItem.parent.right // contentItem.anchors.rightMargin: 0 property bool showAccounts : true /***************************************************/ /******************** ALIASES *********************/ /*************************************************/ property alias headBar : _headBar property alias footBar: _footBar property alias dialog: dialogLoader.item property alias leftIcon : menuBtn property alias rightIcon : searchBtn property alias mainMenu : mainMenu.contentData property alias about : aboutDialog property alias accounts: _accountsDialogLoader.item property var currentAccount: ({}) property alias notifyDialog: _notify //redefines here as here we can know a pointer to PageRow wideScreen: isWide /***************************************************/ /*********************** UI ***********************/ /*************************************************/ property bool isWide : root.width >= Kirigami.Units.gridUnit * 30 property int radiusV : unit * 4 property int iconSize : iconSizes.medium * (isMobile ? 0.95 : 1) readonly property int unit : Maui.Style.unit readonly property int rowHeight: Maui.Style.rowHeight readonly property int rowHeightAlt: Maui.Style.rowHeightAlt readonly property int toolBarHeight: Maui.Style.toolBarHeight readonly property int toolBarHeightAlt: Maui.Style.toolBarHeightAlt readonly property int contentMargins: space.medium readonly property var fontSizes: Maui.Style.fontSizes readonly property var space : Maui.Style.space readonly property var iconSizes : Maui.Style.iconSizes property string colorSchemeName : Qt.application.name /***************************************************/ /********************* COLORS *********************/ /*************************************************/ readonly property var colorScheme: ({ Default : 1, Light : 2, Dark: 3, Custom: 4 }) // property color borderColor: Qt.tint(textColor, Qt.rgba(backgroundColor.r, backgroundColor.g, // backgroundColor.b, 0.7)) // property color backgroundColor: Maui.Style.backgroundColor // property color textColor: Maui.Style.textColor // property color highlightColor: Maui.Style.highlightColor // property color highlightedTextColor: Maui.Style.highlightedTextColor // property color buttonBackgroundColor: Maui.Style.buttonBackgroundColor // property color viewBackgroundColor: Maui.Style.viewBackgroundColor // property color altColor: Maui.Style.altColor // property color altColorText: Maui.Style.altColorText // property color accentColor : buttonBackgroundColor // // property color bgColor: Kirigami.Theme.viewBackgroundColor property color headBarBGColor: Kirigami.Theme.backgroundColor property color headBarFGColor: Kirigami.Theme.textColor // readonly property string darkBorderColor: Qt.darker(darkBackgroundColor, 1.5) // readonly property string darkBackgroundColor: "#303030" // readonly property string darkTextColor: "#FAFAFA" // readonly property string darkHighlightColor: "#29B6F6" // readonly property string darkHighlightedTextColor: darkTextColor // readonly property string darkViewBackgroundColor: "#212121" // readonly property string darkDarkColor: "#191919" // readonly property string darkButtonBackgroundColor : "#191919" // readonly property color darkAltColor: "#333" // readonly property color darkAltColorText: darkTextColor // readonly property color darkAccentColor : darkButtonBackgroundColor // readonly property color darkBgColor: darkBackgroundColor property color warningColor : Maui.Style.warningColor property color dangerColor : Maui.Style.dangerColor property color infoColor : Maui.Style.infoColor property color suggestedColor : Maui.Style.suggestedColor /* ANDROID THEMING*/ // Material.theme: Material.Light // Material.accent: Kirigami.Theme.highlightColor // Material.background: headBarBGColor // Material.primary: headBarBGColor // Material.foreground: Kirigami.Theme.textColor /***************************************************/ /**************** READONLY PROPS ******************/ /*************************************************/ readonly property bool isMobile : Kirigami.Settings.isMobile readonly property bool isAndroid: Qt.platform.os == "android" readonly property real screenWidth : Screen.width readonly property real screenHeight : Screen.height /***************************************************/ /********************* PROPS **********************/ /*************************************************/ property alias searchButton : searchBtn property alias menuButton : menuBtn /***************************************************/ /******************** SIGNALS *********************/ /*************************************************/ signal menuButtonClicked(); signal searchButtonClicked(); signal goBackTriggered(); signal goFowardTriggered(); // overlay.modal: Rectangle // { // color: Color.transparent(altColor, 0.5) // } // overlay.modeless: Rectangle { // color: "transparent" // } onClosing: { if(!isMobile) { var height = root.height var width = root.width var x = root.x var y = root.y Maui.FM.saveSettings("GEOMETRY", Qt.rect(x, y, width, height), "WINDOW") } } property bool isPortrait: Screen.primaryOrientation === Qt.PortraitOrientation || Screen.primaryOrientation === Qt.InvertedPortraitOrientation onIsPortraitChanged: { if(isPortrait) { console.log("PORTARIT MODE CHANGED") width: Screen.width height: Screen.height } } // onHeadBarBGColorChanged: // { // if(!isMobile && colorSchemeName.length > 0) // Maui.KDE.setColorScheme(colorSchemeName, headBarBGColor, headBarFGColor) // else if(isAndroid && headBar.position === ToolBar.Header) // Maui.Android.statusbarColor(headBarBGColor, false) // else if(isAndroid && headBar.position === ToolBar.Footer) // Maui.Android.statusbarColor(Kirigami.Theme.viewBackgroundColor, true) // // } // // onHeadBarFGColorChanged: // { // if(!isAndroid && !isMobile && colorSchemeName.length > 0 && headBar.position === ToolBar.Header) // Maui.KDE.setColorScheme(colorSchemeName, headBarBGColor, headBarFGColor) // else if(isAndroid && headBar.position === ToolBar.Header) // Maui.Android.statusbarColor(headBarBGColor, false) // else if(isAndroid && headBar.position === ToolBar.Footer) // Maui.Android.statusbarColor(Kirigami.Theme.viewBackgroundColor, true) // } /* background: Rectangle { color: bgColor } */ // globalDrawer.height: root.height - headBar.height // globalDrawer.y: headBar.height property QtObject mheadBar : Maui.ToolBar { id: _headBar visible: count > 1 position: ToolBar.Header width: root.width // Kirigami.Theme.backgroundColor: headBarBGColor // Kirigami.Theme.textColor: headBarFGColor // Kirigami.Theme.inherit: true leftContent: [ ToolButton { id: menuBtn icon.name: "application-menu" icon.color: headBarFGColor checked: mainMenu.visible onClicked: { menuButtonClicked() mainMenu.visible ? mainMenu.close() : mainMenu.popup(parent, parent.x , parent.height+ space.medium) } Menu { id: mainMenu modal: true z: 999 width: unit * 200 Item { height: _accountCombobox.visible ? _accountCombobox.implicitHeight + space.big: 0 anchors { left: parent.left right: parent.right top: parent.top margins: space.medium } ComboBox { id: _accountCombobox anchors.centerIn: parent // parent: mainMenu popup.z: 999 width: parent.width // visible: (count > 1) && showAccounts textRole: "user" flat: true model: accounts.model onActivated: { var account = accounts.list.get(index) root.currentAccount = account console.log(currentAccount.user, currentAccount.password, currentAccount.server) } // icon.name: "user-identity" // iconButton.isMask: false } } MenuItem { text: qsTr("Accounts") visible: root.showAccounts icon.name: "list-add-user" onTriggered: { if(root.accounts) accounts.open() } } MenuSeparator { visible: _accountCombobox.visible - } - - MenuItem - { - text: qsTr("Accounts") - visible: root.showAccounts - icon.name: "list-add-user" - onTriggered: - { - if(root.accounts) - accounts.open() - } - } + } MenuItem { text: qsTr("About") icon.name: "documentinfo" onTriggered: aboutDialog.open() } } }, Kirigami.Separator { visible: menuBtn.visible Layout.preferredHeight: 16 opacity: 0.5 width: visible ? 2 : 0 } ] rightContent: ToolButton { id: searchBtn icon.name: "edit-find" icon.color: headBarFGColor onClicked: searchButtonClicked() } } property QtObject mfootBar : Maui.ToolBar { id: _footBar visible: count position: ToolBar.Footer width: root.width // Kirigami.Theme.backgroundColor: Kirigami.Theme.backgroundColor } header: headBar.count && headBar.position === ToolBar.Header ? headBar : undefined footer: Column { id: _footer visible : children > 0 children: { if(headBar.position === ToolBar.Footer && headBar.count && footBar.count) return [footBar , headBar] else if(headBar.position === ToolBar.Footer && headBar.count) return [headBar] else if(footBar.count) return [footBar] else return [] } } Maui.AboutDialog { id: aboutDialog } Loader { id: _accountsDialogLoader sourceComponent: root.showAccounts ? _accountsDialogComponent : undefined } Component { id: _accountsDialogComponent AccountsHelper {} } Maui.Dialog { id: _notify property var cb : ({}) verticalAlignment: Qt.AlignTop defaultButtons: false // colorScheme.backgroundColor: altColor // colorScheme.textColor: altColorText maxHeight: Math.max(unit * 120, (_notifyLayout.implicitHeight)) maxWidth: isMobile ? parent.width * 0.9 : unit * 500 Timer { id: _notifyTimer onTriggered: _notify.close() } onClosed: _notifyTimer.stop() MouseArea { anchors.fill: parent onClicked: { if(_notify.cb) _notify.cb() _notify.close() } } GridLayout { anchors.fill: parent columns: 2 rows: 1 Item { Layout.fillHeight: true Layout.preferredWidth: iconSizes.huge + space.big Layout.row: 1 Layout.column: 1 ToolButton { id: _notifyIcon icon.width: iconSizes.large anchors.centerIn: parent // isMask: false } } Item { Layout.fillHeight: true Layout.fillWidth: true Layout.row: 1 Layout.column: 2 ColumnLayout { anchors.fill: parent id: _notifyLayout Label { id: _notifyTitle Layout.fillHeight: true Layout.fillWidth: true font.weight: Font.Bold font.bold: true font.pointSize: fontSizes.big // color: _notify.colorScheme.textColor elide: Qt.ElideRight wrapMode: Text.Wrap } Label { id: _notifyBody Layout.fillHeight: true Layout.fillWidth: true font.pointSize: fontSizes.default // color: _notify.colorScheme.textColor elide: Qt.ElideRight wrapMode: Text.Wrap } } } } function show(callback) { _notify.cb = callback _notifyTimer.start() _notify.open() } } Loader { id: dialogLoader } Component.onCompleted: { if(isAndroid && headBar.position === ToolBar.Footer) Maui.Android.statusbarColor(Kirigami.Theme.backgroundColor, true) if(!isMobile) { var rect = Maui.FM.loadSettings("GEOMETRY", "WINDOW", Qt.rect(root.x, root.y, root.width, root.height)) root.x = rect.x root.y = rect.y root.width = rect.width root.height = rect.height } } // Connections // { // target: Maui.FM // // onNewItem: notify("dialog-information", qsTr("File uploaded"), "Your file has been uploaded to your account /n"+path) // onWarningMessage: notify("dialog-information", "Oops!", message) // } function switchColorScheme(variant) { // switch(variant) // { // case colorScheme.Default: // // backgroundColor = Maui.Style.backgroundColor // textColor = Maui.Style.textColor // highlightColor = Maui.Style.highlightColor // highlightedTextColor = Maui.Style.highlightedTextColor // buttonBackgroundColor = Maui.Style.buttonBackgroundColor // viewBackgroundColor = Maui.Style.viewBackgroundColor // altColor = Maui.Style.altColor // borderColor = Maui.Style.borderColor // if(isAndroid) Maui.Android.statusbarColor(backgroundColor, true) // break // // case colorScheme.Dark: // borderColor = darkBorderColor // backgroundColor = darkBackgroundColor // textColor = darkTextColor // highlightColor = darkHighlightColor // highlightedTextColor = darkHighlightedTextColor // buttonBackgroundColor = darkButtonBackgroundColor // viewBackgroundColor = darkViewBackgroundColor // altColor = darkDarkColor // altColorText = darkAltColorText // bgColor =darkBgColor // // if(isAndroid) Maui.Android.statusbarColor(backgroundColor, false) // break // } } function notify(icon, title, body, callback, timeout) { _notifyIcon.icon.name = icon _notifyTitle.text = title _notifyBody.text = body _notifyTimer.interval = timeout ? timeout : 2500 _notify.show(callback) } /** FUNCTIONS **/ // function riseContent() // { // if(allowRiseContent) // flickable.flick(0, flickable.contentHeight* -2) // } // function dropContent() // { // if(allowRiseContent) // flickable.flick(0, flickable.contentHeight* 2) // } } diff --git a/src/controls/FileBrowser.qml b/src/controls/FileBrowser.qml index 678fdf3..5ca5e66 100644 --- a/src/controls/FileBrowser.qml +++ b/src/controls/FileBrowser.qml @@ -1,1156 +1,1158 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Maui.Page { id: control property alias trackChanges: modelList.trackChanges property alias saveDirProps: modelList.saveDirProps property string currentPath: Maui.FM.homePath() property var copyItems : [] property var cutItems : [] property var indexHistory : [] property bool isCopy : false property bool isCut : false property bool selectionMode : false property bool group : false property bool showEmblems: true property bool singleSelection: false property alias selectionBar : selectionBarLoader.item property alias model : folderModel property alias list : modelList property alias browser : viewLoader.item property var currentFMList : modelList property alias previewer : previewer property alias menu : browserMenu.contentData property alias itemMenu: itemMenu property alias holder: holder property alias dialog : dialogLoader.item property alias goUpButton : goUpButton property int currentPathType : currentFMList.pathType property int thumbnailsSize : iconSizes.large 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) focus: true Kirigami.Theme.colorSet: Kirigami.Theme.View Kirigami.Theme.inherit: false // Kirigami.Theme.backgroundColor: Kirigami.Theme.viewBackgroundColor Loader { id: dialogLoader } Component { id: removeDialogComponent Maui.Dialog { property var items: [] title: qsTr("Remove files?") message: 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.Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.neutralTextColor.r, Kirigami.Theme.neutralTextColor.g, Kirigami.Theme.neutralTextColor.b, 0.2) // acceptButton.Kirigami.Theme.textColor: Kirigami.Theme.neutralTextColor 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: list.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) } } BrowserMenu { id: browserMenu // width: unit *200 z : control.z +1 } Maui.FilePreviewer { id: previewer parent: parent onShareButtonClicked: control.shareFiles([url]) } Maui.BaseModel { id: folderModel list: modelList } Maui.FMList { id: modelList preview: true path: currentPath foldersFirst: true onSortByChanged: if(group) groupBy() onContentReadyChanged: console.log("CONTENT READY?", contentReady) onWarning: { notify("dialog-information", "An error happened", message) } onProgress: { if(percent === 100) _progressBar.value = 0 else _progressBar.value = percent/100 } } FileMenu { id: itemMenu width: 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() } // onSaveToClicked: // { // fmDialog.saveDialog = false // fmDialog.multipleSelection = true // fmDialog.onlyDirs= true // var myPath = path // var paths = browser.selectionBar.selectedPaths // fmDialog.show(function(paths) // { // inx.copy(myPath, paths) // }) // } onRemoveClicked: { dialogLoader.sourceComponent= removeDialogComponent dialog.items = [item] dialog.open() } onShareClicked: control.shareFiles([item.path]) } Component { id: listViewBrowser Maui.ListBrowser { showPreviewThumbnails: modelList.preview keepEmblemOverlay: selectionMode rightEmblem: isMobile ? "document-share" : "" leftEmblem: "list-add" showDetailsInfo: true // itemSize: thumbnailsSize model: folderModel section.delegate: Maui.LabelDelegate { id: delegate label: section labelTxt.font.pointSize: fontSizes.big isSection: true boldLabel: true height: toolBarHeightAlt } } } Component { id: gridViewBrowser Maui.GridBrowser { itemSize : thumbnailsSize + fontSizes.default keepEmblemOverlay: selectionMode showPreviewThumbnails: modelList.preview rightEmblem: isMobile ? "document-share" : "" leftEmblem: "list-add" model: folderModel } } Component { id: millerViewBrowser Kirigami.ColumnView { id: _millerColumns columnWidth: Math.min(Kirigami.Units.gridUnit * 22, control.width) // fillWidth: true columnResizeMode: Kirigami.ColumnView.DynamicColumns signal itemClicked(int index) signal itemDoubleClicked(int index) signal itemRightClicked(int index) signal rightEmblemClicked(int index) signal leftEmblemClicked(int index) signal areaClicked(var mouse) signal areaRightClicked() Maui.PathList { id: _millerList path: control.currentPath onPathChanged: _millerColumns.currentIndex = _repeater.count - 1 } Maui.BaseModel { id: _millerModel list: _millerList } Repeater { id: _repeater model: _millerModel onItemAdded: { // if(viewLoader.sourceComponent === millerViewBrowser) // _millerColumns.currentIndex = _millerColumns.count-1 // _millerColumns.contentX= _millerColumns.columnWidth * _millerColumns.count } Item { Maui.FMList { id: _millersFMList preview: modelList.preview path: model.path foldersFirst: modelList.foldersFirst onWarning: { notify("dialog-information", "An error happened", message) } onProgress: { if(percent === 100) _progressBar.value = 0 else _progressBar.value = percent/100 } } Maui.ListBrowser { id: _millerListView anchors.fill: parent showPreviewThumbnails: modelList.preview keepEmblemOverlay: selectionMode rightEmblem: isMobile ? "document-share" : "" leftEmblem: "list-add" showDetailsInfo: true // itemSize: thumbnailsSize onItemClicked: { control.currentFMList = _millersFMList _millerColumns.itemClicked(index) } // onItemDoubleClicked: // { // modelList.path = _millersFMList.path // _millerColumns.onItemDoubleClicked(index) // } onItemRightClicked: { control.currentFMList = _millersFMList _millerColumns.itemRightClicked(index) } onRightEmblemClicked: { control.currentFMList = _millersFMList _millerColumns.rightEmblemClicked(index) } onLeftEmblemClicked: { control.currentFMList = _millersFMList _millerColumns.leftEmblemClicked(index) } onAreaClicked: { control.currentFMList = _millersFMList _millerColumns.areaClicked(mouse) } onAreaRightClicked: { control.currentFMList = _millersFMList _millerColumns.areaRightClicked() } model: Maui.BaseModel { list: _millersFMList } section.delegate: Maui.LabelDelegate { id: delegate label: section labelTxt.font.pointSize: fontSizes.big isSection: true boldLabel: true height: toolBarHeightAlt } } } } } } Connections { target: browser onItemClicked: { browser.currentIndex = index indexHistory.push(index) control.itemClicked(index) } onItemDoubleClicked: { browser.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: { control.addToSelection(control.currentFMList.get(index), true) 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(!isMobile && mouse.button === Qt.RightButton) browserMenu.show() else return control.rightClicked() } onAreaRightClicked: browserMenu.show() } Maui.Holder { id: holder anchors.fill : parent z: -1 visible: !control.currentFMList.pathExists || control.currentFMList.pathEmpty || !control.currentFMList.contentReady emoji: if(control.currentFMList.pathExists && control.currentFMList.pathEmpty) "qrc:/assets/MoonSki.png" else if(!control.currentFMList.pathExists) "qrc:/assets/ElectricPlug.png" else if(!control.currentFMList.contentReady && currentPathType === Maui.FMList.SEARCH_PATH) "qrc:/assets/animat-search-color.gif" else if(!control.currentFMList.contentReady) "qrc:/assets/animat-rocket-color.gif" isGif: !control.currentFMList.contentReady isMask: false title : if(control.currentFMList.pathExists && control.currentFMList.pathEmpty) qsTr("Folder is empty!") else if(!control.currentFMList.pathExists) qsTr("Folder doesn't exists!") else if(!control.currentFMList.contentReady && currentPathType === Maui.FMList.SEARCH_PATH) qsTr("Searching for content!") else if(!control.currentFMList.contentReady) qsTr("Loading content!") body: if(control.currentFMList.pathExists && control.currentFMList.pathEmpty) qsTr("You can add new files to it") else if(!control.currentFMList.pathExists) qsTr("Create Folder?") else if(!control.currentFMList.contentReady && currentPathType === Maui.FMList.SEARCH_PATH) qsTr("This might take a while!") else if(!control.currentFMList.contentReady) qsTr("Almost ready!") emojiSize: iconSizes.huge onActionTriggered: { if(!control.currentFMList.pathExists) { Maui.FM.createDir(control.currentPath.slice(0, control.currentPath.lastIndexOf("/")), control.currentPath.split("/").pop()) control.openFolder(control.currentFMList.parentPath) } } } Keys.onSpacePressed: previewer.show(control.currentFMList.get(browser.currentIndex).path) headBar.visible: currentPathType !== Maui.FMList.APPS_PATH headBar.position: isMobile ? ToolBar.Footer : ToolBar.Header property list t_actions: [ Action { id: _previewAction icon.name: "image-preview" text: qsTr("Previews") checkable: true checked: list.preview onTriggered: list.preview = !list.preview }, Action { id: _hiddenAction icon.name: "visibility" text: qsTr("Hidden files") checkable: true checked: list.hidden onTriggered: list.hidden = !list.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+"]" icon.name: "edit-paste" enabled: browserMenu.pasteFiles > 0 onTriggered: paste() }] // headBar.stickyRightContent: true headBar.rightContent:[ - ToolButton - { - icon.name: "view-list-icons" - onClicked: list.viewType = Maui.FMList.ICON_VIEW - checkable: false - checked: list.viewType === Maui.FMList.ICON_VIEW - icon.width: iconSizes.medium - autoExclusive: true - }, - - ToolButton - { - icon.name: "view-list-details" - onClicked: list.viewType = Maui.FMList.LIST_VIEW - icon.width: iconSizes.medium - checked: list.viewType === Maui.FMList.LIST_VIEW - autoExclusive: true - }, - - ToolButton - { - icon.name: "view-file-columns" - onClicked: list.viewType = Maui.FMList.MILLERS_VIEW - icon.width: iconSizes.medium - checked: list.viewType === Maui.FMList.MILLERS_VIEW - autoExclusive: true - }, - Kirigami.ActionToolBar { position: ToolBar.Header Layout.fillWidth: true hiddenActions: t_actions display: isWide ? ToolButton.TextBesideIcon : ToolButton.IconOnly actions: [ + Action + { + icon.name: "view-list-icons" + onTriggered: list.viewType = Maui.FMList.ICON_VIEW + checkable: false + checked: list.viewType === Maui.FMList.ICON_VIEW + icon.width: iconSizes.medium + text: qsTr("Grid view") +// autoExclusive: true + }, + + Action + { + icon.name: "view-list-details" + onTriggered: list.viewType = Maui.FMList.LIST_VIEW + icon.width: iconSizes.medium + checked: list.viewType === Maui.FMList.LIST_VIEW + text: qsTr("List view") +// autoExclusive: true + }, + + Action + { + icon.name: "view-file-columns" + onTriggered: list.viewType = Maui.FMList.MILLERS_VIEW + icon.width: iconSizes.medium + checked: list.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: list.foldersFirst onTriggered: list.foldersFirst = !list.foldersFirst } Kirigami.Action { text: qsTr("Type") checked: list.sortBy === Maui.FMList.MIME onTriggered: list.sortBy = Maui.FMList.MIME } Kirigami.Action { text: qsTr("Date") checked: list.sortBy === Maui.FMList.DATE onTriggered: list.sortBy = Maui.FMList.DATE } Kirigami.Action { text: qsTr("Modified") checked: list.sortBy === Maui.FMList.MODIFIED onTriggered: list.sortBy = Maui.FMList.MODIFIED } Kirigami.Action { text: qsTr("Size") checked: list.sortBy === Maui.FMList.SIZE onTriggered: list.sortBy = Maui.FMList.SIZE } Kirigami.Action { text: qsTr("Name") checked: list.sortBy === Maui.FMList.LABEL onTriggered: list.sortBy = Maui.FMList.LABEL } Kirigami.Action { id: groupAction text: qsTr("Group") checked: group onTriggered: { group = !group if(group) groupBy() else browser.section.property = "" } } }, Kirigami.Action { text: qsTr("Select") icon.name: "item-select" checkable: false checked: selectionMode onTriggered: selectionMode = !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() } ] footBar.visible: false Component { id: selectionBarComponent Maui.SelectionBar { anchors.fill: parent onIconClicked: _selectionBarmenu.popup() onExitClicked: clearSelection() 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() } } MenuSeparator{} MenuItem { text: qsTr("Remove...") Kirigami.Theme.textColor: dangerColor onTriggered: { dialogLoader.sourceComponent= removeDialogComponent dialog.items = selectedItems dialog.open() _selectionBarmenu.close() } } } } } ColumnLayout { anchors.fill: parent visible: !holder.visible z: holder.z + 1 spacing: 0 Loader { id: viewLoader z: holder.z + 1 sourceComponent: switch(list.viewType) { case Maui.FMList.ICON_VIEW: return gridViewBrowser case Maui.FMList.LIST_VIEW: return listViewBrowser case Maui.FMList.MILLERS_VIEW: return millerViewBrowser } onLoaded: { if(sourceComponent !== millerViewBrowser) control.currentFMList = modelList } Layout.topMargin: list.viewType == Maui.FMList.ICON_VIEW ? contentMargins * 2 : unit Layout.margins: 0 Layout.fillWidth: true Layout.fillHeight: true } Loader { id: selectionBarLoader Layout.fillWidth: true Layout.preferredHeight: control.selectionBar && control.selectionBar.visible ? control.selectionBar.barHeight: 0 Layout.leftMargin: contentMargins * (isMobile ? 3 : 2) Layout.rightMargin: contentMargins * (isMobile ? 3 : 2) Layout.bottomMargin: control.selectionBar && control.selectionBar.visible ? contentMargins*2 : 0 z: holder.z +1 } ProgressBar { id: _progressBar Layout.fillWidth: true Layout.alignment: Qt.AlignBottom Layout.preferredHeight: visible ? iconSizes.medium : 0 visible: value > 0 } } // PinchArea // { // anchors.fill: parent // // property real initialWidth // property real initialHeight // // onPinchStarted: // { // console.log("pinch started") // } // // onPinchUpdated: // { // console.log(pinch.scale) // } // // onPinchFinished: // { // console.log("pinch finished") // } // } onThumbnailsSizeChanged: { if(trackChanges && saveDirProps) Maui.FM.setDirConf(currentPath+"/.directory", "MAUIFM", "IconSize", thumbnailsSize) else Maui.FM.saveSettings("IconSize", thumbnailsSize, "SETTINGS") if(list.viewType == Maui.FMList.ICON_VIEW) browser.adaptGrid() } 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) { var item = control.currentFMList.get(index) var 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)) addToSelection(item, true) else { if(item.mime === "inode/directory") control.openFolder(path) else if(Maui.FM.isApp(path)) control.launchApp(path) else { if (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(path) + populate(Maui.FM.fileDir(path))// make sure the path is a dir } function setPath(path) { currentPath = path } function populate(path) { if(!path.length) return; browser.currentIndex = 0 setPath(path) if(currentPathType === Maui.FMList.PLACES_PATH) { if(trackChanges && saveDirProps) { var conf = Maui.FM.dirConf(path+"/.directory") var iconsize = conf["iconsize"] || iconSizes.large thumbnailsSize = parseInt(iconsize) }else { thumbnailsSize = parseInt(Maui.FM.loadSettings("IconSize", "SETTINGS", thumbnailsSize)) } } if(list.viewType == Maui.FMList.ICON_VIEW) browser.adaptGrid() } function goBack() { populate(modelList.previousPath) browser.currentIndex = indexHistory.pop() // browser.positionViewAtIndex(browser.currentIndex, ListView.Center) } function goNext() { openFolder(modelList.posteriorPath) } function goUp() { openFolder(modelList.parentPath) } function refresh() { var pos = browser.contentY // control.currentFMList.refresh() browser.contentY = pos } function addToSelection(item, append) { selectionBarLoader.sourceComponent= selectionBarComponent selectionBar.singleSelection = control.singleSelection selectionBar.append(item) } function clearSelection() { clean() // selectionMode = false } function clean() { copyItems = [] cutItems = [] browserMenu.pasteFiles = 0 if(control.selectionBar && control.selectionBar.visible) selectionBar.clear() } function copy(items) { copyItems = items isCut = false isCopy = true } function cut(items) { cutItems = items isCut = true isCopy = false } function paste() { if(isCopy) currentFMList.copyInto(copyItems) else if(isCut) { currentFMList.cutInto(cutItems) clearSelection() } } function remove(items) { for(var i in items) Maui.FM.removeFile(items[i].path) } 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() { var newSize = control.thumbnailsSize - 8 if(newSize >= iconSizes.small) control.thumbnailsSize = newSize } function groupBy() { var prop = "" var criteria = ViewSection.FullString switch(modelList.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; } list.viewType = Maui.FMList.LIST_VIEW if(!prop) { browser.section.property = "" return } browser.section.property = prop browser.section.criteria = criteria } } diff --git a/src/controls/Holder.qml b/src/controls/Holder.qml index 3a8bfcc..de9ddea 100644 --- a/src/controls/Holder.qml +++ b/src/controls/Holder.qml @@ -1,148 +1,141 @@ /* * 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. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.7 as Kirigami import "private" Item { id: control anchors.fill: parent property string emoji property string message property string title property string body property bool isMask : true property bool isGif : false property int emojiSize : iconSizes.large property bool enabled: true signal actionTriggered() clip: true focus: true Component { id: imgComponent Image { id: imageHolder width: Math.min(parent.width, emojiSize) height: width sourceSize.width: width sourceSize.height: height source: emoji asynchronous: true horizontalAlignment: Qt.AlignHCenter fillMode: Image.PreserveAspectFit HueSaturation { anchors.fill: parent source: parent saturation: -1 lightness: 0.3 visible: isMask } } } Component { id: animComponent AnimatedImage { id: animation; source: emoji } } MouseArea { + id: _mouseArea anchors.fill: parent enabled: control.enabled onClicked: actionTriggered() - hoverEnabled: true - - Rectangle - { - anchors.fill: parent - color: parent.hovered ? Kirigami.Theme.backgroundColor : "transparent" - radius: radiusV - } - + hoverEnabled: true } Item { anchors.centerIn: parent height: loader.height + textHolder.implicitHeight width: Math.min(500, control.width) Loader { id: loader height: control.emoji ? emojiSize : 0 width: height sourceComponent: control.emoji ? (isGif ? animComponent : imgComponent) : undefined anchors { bottom: textHolder.top horizontalCenter: parent.horizontalCenter } } Label { id: textHolder width: parent.width opacity: 0.5 text: message ? qsTr(message) : "

"+title+"

"+body+"

" font.pointSize: fontSizes.default padding: space.medium font.bold: true textFormat: Text.RichText horizontalAlignment: Qt.AlignHCenter elide: Text.ElideRight - color: Kirigami.Theme.textColor + color: _mouseArea.hovered ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor wrapMode: Text.Wrap anchors { top: loader.bottom horizontalCenter: parent.horizontalCenter } } } } diff --git a/src/fm/fm.cpp b/src/fm/fm.cpp index cda7621..9842c1a 100644 --- a/src/fm/fm.cpp +++ b/src/fm/fm.cpp @@ -1,941 +1,958 @@ /* * 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::PATH, kfile.url().toString()}, {FMH::MODEL_KEY::THUMBNAIL, kfile.localPath()}, {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::sdDir()}, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES_PATH]); // return drives; // #else // KFilePlacesModel model; // for(const auto &i : model.groupIndexes(KFilePlacesModel::GroupType::RemoteType)) // { // drives << FMH::MODEL{ // {FMH::MODEL_KEY::NAME, model.text(i)}, // {FMH::MODEL_KEY::LABEL, model.text(i)}, // {FMH::MODEL_KEY::PATH, model.url(i).toString()}, // {FMH::MODEL_KEY::ICON, model.icon(i).name()}, // {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES_PATH]}, // }; // } // // #endif // // // auto devices = QStorageInfo::mountedVolumes(); // // for(auto device : devices) // // { // // if(device.isValid() && !device.isReadOnly()) // // { // // QVariantMap drive = // // { // // {FMH::MODEL_NAME[FMH::MODEL_KEY::ICON], "drive-harddisk"}, // // {FMH::MODEL_NAME[FMH::MODEL_KEY::LABEL], device.displayName()}, // // {FMH::MODEL_NAME[FMH::MODEL_KEY::PATH], device.rootPath()}, // // {FMH::MODEL_NAME[FMH::MODEL_KEY::TYPE], FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES]} // // }; // // // // drives << drive; // // } // // } // // // for(auto device : QDir::drives()) // // { // // QVariantMap drive = // // { // // {"iconName", "drive-harddisk"}, // // {"label", device.baseName()}, // // {"path", device.absoluteFilePath()}, // // {"type", "Drives"} // // }; // // // drives << drive; // // } // // 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) { qDebug()<< "trying to create folder at"<< path; 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; qDebug()<< "TAG CONTENT FOR TAG"<< tag; for(const auto &data : this->tag->getUrls(tag, false)) { const auto url = data.toMap().value(TAG::KEYMAP[TAG::KEYS::URL]).toString(); auto item = FMH::getFileInfoModel(QUrl::fromLocalFile(url)); content << item; } return content; } 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; + 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); }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; #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) { 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) { return QDesktopServices::openUrl(QUrl::fromUserInput(url)); } 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); } diff --git a/src/fm/fm.h b/src/fm/fm.h index fa54e9e..9f569b9 100644 --- a/src/fm/fm.h +++ b/src/fm/fm.h @@ -1,150 +1,156 @@ #ifndef FM_H #define FM_H #include #include #include #include #include #include #include "fmdb.h" #include "fmh.h" #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) class KCoreDirLister; #endif class Syncing; class Tagging; #ifdef STATIC_MAUIKIT class FM : public FMDB #else class MAUIKIT_EXPORT FM : public FMDB #endif { Q_OBJECT public: // static FM *getInstance(); Syncing *sync; FM(QObject *parent = nullptr); ~FM(); FMH::MODEL_LIST getTags(const int &limit = 5); FMH::MODEL_LIST getTagContent(const QString &tag); // FMH::MODEL_LIST getBookmarks(); /** Syncing **/ bool getCloudServerContent(const QString &server, const QStringList &filters= QStringList(), const int &depth = 0); FMH::MODEL_LIST getCloudAccounts(); Q_INVOKABLE void createCloudDir(const QString &path, const QString &name); void getTrashContent(); /*** START STATIC METHODS ***/ static FMH::MODEL_LIST search(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); // static FMH::MODEL_LIST getDevices(); static FMH::MODEL_LIST getDefaultPaths(); static FMH::MODEL_LIST getAppsPath(); static FMH::MODEL_LIST packItems(const QStringList &items, const QString &type); void getPathContent(const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags); // static FMH::MODEL_LIST getPathContent(const QString &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags); static FMH::MODEL_LIST getAppsContent(const QString &path); static bool copyPath(QUrl sourceDir, QUrl destinationDir, bool overWriteDirectory); static bool removeDir(const QUrl &path); static QString resolveUserCloudCachePath(const QString &server, const QString &user); QString resolveLocalCloudPath(const QString &path); /** * only keeping this two for legacy. shoudl be removed soon * and instead use FMH::toMap, FMH::toModel, FMH::filterModel **/ static QVariantMap toMap(const FMH::MODEL &model); static FMH::MODEL toModel(const QVariantMap &map); /*** END STATIC METHODS ***/ private: Tagging *tag; #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) KCoreDirLister *dirLister; #endif // static FM* instance; QVariantList get(const QString &queryTxt); signals: void cloudAccountInserted(QString user); void cloudAccountRemoved(QString user); void cloudServerContentReady(FMH::MODEL_LIST list, const QString &url); void cloudItemReady(FMH::MODEL item, QString path); //when a item is downloaded and ready void trashContentReady(FMH::MODEL_LIST list); void pathContentReady(FMH::PATH_CONTENT list); void pathContentChanged(QUrl path); void warningMessage(QString message); void loadProgress(int percent); void dirCreated(FMH::MODEL dir); void newItem(FMH::MODEL item, QString path); // when a new item is created public slots: QVariantList getCloudAccountsList(); bool addCloudAccount(const QString &server, const QString &user, const QString &password); bool removeCloudAccount(const QString &server, const QString &user); void openCloudItem(const QVariantMap &item); void getCloudItem(const QVariantMap &item); static QString formatSize(const int &size); static QString formatDate(const QString &dateStr, const QString &format = QString("dd/MM/yyyy"), const QString &initFormat = QString()); static QString homePath(); static QUrl parentDir(const QUrl &path); static QVariantMap getDirInfo(const QUrl &path, const QString &type); static QVariantMap getFileInfo(const QUrl &path); static bool isDefaultPath(const QString &path); static bool isDir(const QUrl &path); static bool isApp(const QString &path); static bool isCloud(const QUrl &path); static bool fileExists(const QUrl &path); + /** + * if the url is a file path then it returns its directory + * and if it is a directory returns the same path + * */ + static QString fileDir(const QUrl &path); + /* SETTINGS */ static void saveSettings(const QString &key, const QVariant &value, const QString &group); static QVariant loadSettings(const QString &key, const QString &group, const QVariant &defaultValue); static QVariantMap dirConf(const QUrl &path); static void setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value); /* ACTIONS */ bool copy(const QVariantList &data, const QString &where); bool cut(const QVariantList &data, const QString &where); static bool removeFile(const QUrl &path); void moveToTrash(const QUrl &path); static void emptyTrash(); static bool rename(const QUrl &path, const QString &name); static bool createDir(const QUrl &path, const QString &name); static bool createFile(const QUrl &path, const QString &name); static bool openUrl(const QString &url); static void openLocation(const QStringList &urls); static void runApplication(const QString &exec); }; #endif // FM_H