diff --git a/mauikit.pri b/mauikit.pri index d847b6c..9e9b0c3 100644 --- a/mauikit.pri +++ b/mauikit.pri @@ -1,338 +1,338 @@ QT *= \ core \ qml \ quick \ gui \ svg \ concurrent CONFIG *= c++17 DEFINES *= \ MAUI_APP \ - STATIC_MAUIKIT \ + STATIC_MAUIKIT #REPO VARIABLES LUV_REPO = https://github.com/milohr/luv-icon-theme OPENSSL_REPO = https://github.com/mauikit/openssl ATTICA_REPO = https://github.com/mauikit/attica KQUICKSYNTAXHIGHLIGHTER_REPO = https://github.com/mauikit/kquicksyntaxhighlighter.git KSYNTAXHIGHLIGHTING_REPO = https://github.com/mauikit/KSyntaxHighlighting.git #ANDROID FILES VALUES ANDROID_FILES_DIR = $$_PRO_FILE_PWD_/android_files ANDROID_FILES_MANIFEST = $$_PRO_FILE_PWD_/android_files/AndroidManifest.xml ANDROID_FILES_GRADLE = $$_PRO_FILE_PWD_/android_files/build.gradle ANDROID_FILES_RES_DIR = $$_PRO_FILE_PWD_/android_files/res linux:unix:!android { message(Building Maui helpers for Linux KDE) include($$PWD/src/kde/kde.pri) } else:android|win32 { message(Building Maui helpers for Android or Windows) android { include($$PWD/src/android/android.pri) contains(DEFINES, ANDROID_OPENSSL):{ exists($$PWD/src/utils/syncing/openssl/openssl.pri) { message("Using OpenSSL for Android") include($$PWD/src/utils/syncing/openssl/openssl.pri) }else { message("Getting OpenSSL for Android") system(git clone $$OPENSSL_REPO $$PWD/src/utils/syncing/openssl) include($$PWD/src/utils/syncing/openssl/openssl.pri) } } }else:win32 { message("Using OpenSSL for Windows") LIBS += -L$$PWD/../../../../../../Qt/Tools/OpenSSL/Win_x64/lib/ -llibssl LIBS += -L$$PWD/../../../../../../Qt/Tools/OpenSSL/Win_x64/lib/ -llibcrypto } contains(DEFINES, COMPONENT_EDITOR):{ include($$PWD/src/utils/editor/syntaxhighlighter.pri) } contains(DEFINES, COMPONENT_STORE):{ exists($$PWD/src/utils/store/attica/attica.pri):{ message("Using Attica for Android or Windows") include($$PWD/src/utils/store/attica/attica.pri) }else { message("Getting Attica for Android") system(git clone $$ATTICA_REPO $$PWD/src/utils/store/attica) include($$PWD/src/utils/store/attica/attica.pri) } } } else { message("Unknown configuration") } contains(DEFINES, MAUIKIT_STYLE):{ exists($$PWD/src/maui-style/icons/luv-icon-theme) { message("Using Luv icon theme") }else { message("Getting Luv icon theme") system(git clone $$LUV_REPO $$PWD/src/maui-style/icons/luv-icon-theme) } RESOURCES += $$PWD/src/maui-style/style.qrc win32 { DEFINES += ICONS_PNG RESOURCES += $$PWD/src/maui-style/icons_png.qrc }else { RESOURCES += $$PWD/src/maui-style/icons.qrc } } contains(DEFINES, COMPONENT_TAGGING):{ message("INCLUDING TAGGING COMPONENT") include($$PWD/src/utils/tagging/tagging.pri) } else { warning("SKIPPING TAGGING COMPONENT") } contains(DEFINES, COMPONENT_EDITOR):{ message("INCLUDING EDITOR COMPONENT") HEADERS += \ $$PWD/src/utils/editor/documenthandler.h \ $$PWD/src/utils/editor/syntaxhighlighterutil.h SOURCES += \ $$PWD/src/utils//editor/documenthandler.cpp \ $$PWD/src/utils/editor/syntaxhighlighterutil.cpp INCLUDEPATH += $$PWD/src/utils/editor } else { warning("SKIPPING EDITOR COMPONENT") } contains(DEFINES, COMPONENT_STORE):{ message("INCLUDING STORE COMPONENT") HEADERS += \ $$PWD/src/utils/store/store.h \ $$PWD/src/utils/store/storemodel.h \ $$PWD/src/utils/store/storelist.h SOURCES += \ $$PWD/src/utils/store/store.cpp \ $$PWD/src/utils/store/storemodel.cpp \ $$PWD/src/utils/store/storelist.cpp RESOURCES += $$PWD/src/utils/store/store.qrc INCLUDEPATH += $$PWD/src/utils/store } else { warning("SKIPPING STORE COMPONENT") } contains(DEFINES, COMPONENT_SYNCING):{ message("INCLUDING SYNCING COMPONENT") include($$PWD/src/utils/syncing/libwebdavclient/webdavclient.pri) HEADERS += $$PWD/src/utils/syncing/syncing.h SOURCES += $$PWD/src/utils/syncing/syncing.cpp INCLUDEPATH += $$PWD/src/utils/syncing } else { warning("SKIPPING SYNCING COMPONENT") } contains(DEFINES, COMPONENT_ACCOUNTS):{ message("INCLUDING ACCOUNTS COMPONENT") QT *= sql HEADERS += \ $$PWD/src/utils/accounts/mauiaccounts.h \ $$PWD/src/utils/accounts/accountsdb.h \ SOURCES += \ $$PWD/src/utils/accounts/mauiaccounts.cpp\ $$PWD/src/utils/accounts/accountsdb.cpp RESOURCES += $$PWD/src/utils/accounts/accounts.qrc DISTFILES += $$PWD//src/utils/accounts/script.sql INCLUDEPATH += $$PWD/src/utils/accounts DEPENDPATH += $$PWD/src/utils/accounts } else { warning("SKIPPING ACCOUNTS COMPONENT") } contains(DEFINES, COMPONENT_FM):{ message("INCLUDING FM COMPONENT") HEADERS += \ $$PWD/src/fm/fm.h \ $$PWD/src/fm/fmlist.h \ $$PWD/src/fm/placeslist.h \ $$PWD/src/fm/downloader.h SOURCES += \ $$PWD/src/fm/fm.cpp \ $$PWD/src/fm/fmlist.cpp \ $$PWD/src/fm/placeslist.cpp \ $$PWD/src/fm/downloader.cpp INCLUDEPATH += $$PWD/src/fm DEPENDPATH += $$PWD/src/fm } else { warning("SKIPPING FM COMPONENT") } RESOURCES += \ $$PWD/src/mauikit.qrc \ $$PWD/src/assets.qrc HEADERS += \ $$PWD/src/utils/fmstatic.h \ $$PWD/src/mauikit.h \ $$PWD/src/utils/fmh.h \ $$PWD/src/utils/model_template/mauimodel.h \ $$PWD/src/utils/model_template/mauilist.h \ $$PWD/src/utils/handy.h \ $$PWD/src/utils/utils.h \ $$PWD/src/utils/mauiapp.h \ $$PWD/src/utils/models/pathlist.h SOURCES += \ $$PWD/src/utils/fmstatic.cpp \ $$PWD/src/mauikit.cpp \ $$PWD/src/utils/model_template/mauimodel.cpp \ $$PWD/src/utils/model_template/mauilist.cpp \ $$PWD/src/utils/handy.cpp \ $$PWD/src/utils/mauiapp.cpp \ $$PWD/src/utils/models/pathlist.cpp DEPENDPATH += \ $$PWD/src \ $$PWD/src/utils/model_template INCLUDEPATH += \ $$PWD/src \ $$PWD/src/utils \ $$PWD/src/utils/models \ $$PWD/src/utils/model_template API_VER = 1.0 DISTFILES += \ $$PWD/CMakeLists.txt \ $$PWD/src/controls/qmldir #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5KIOFileWidgets.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5KIOWidgets.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Bookmarks.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Solid.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5XmlGui.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5IconThemes.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5KIOCore.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5JobWidgets.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Service.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Completion.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ItemViews.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ConfigWidgets.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5I18n.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5WidgetsAddons.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Codecs.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ConfigGui.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ConfigCore.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ConfigCore.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libdbus-1.so ##KIOFileWidgets #LIBS += -L$$PWD/libs/bin/ -lKF5KIOFileWidgets #INCLUDEPATH += $$PWD/libs/includes/KIOFileWidgets #DEPENDPATH += $$PWD/libs/includes/KIOFileWidgets ##KBookmarks #LIBS += -L$$PWD/libs/bin/ -lKF5Bookmarks #INCLUDEPATH += $$PWD/libs/includes/KBookmarks #DEPENDPATH += $$PWD/libs/includes/KBookmarks ##KSolid #LIBS += -L$$PWD//libs/bin/ -lKF5Solid #INCLUDEPATH += $$PWD//libs/includes/Solid #DEPENDPATH += $$PWD/libs/includes/Solid ##KIOWidgets #LIBS += -L$$PWD/libs/bin/ -lKF5KIOWidgets #INCLUDEPATH += $$PWD/libs/includes/KIOWidgets #DEPENDPATH += $$PWD/libs/includes/KIOWidgets ##KXmlGui #LIBS += -L$$PWD/libs/bin/ -lKF5XmlGui #INCLUDEPATH += $$PWD/libs/includes/KXmlGui #DEPENDPATH += $$PWD/libs/includes/KXmlGui ##KIconThemes #LIBS += -L$$PWD/libs/bin/ -lKF5IconThemes #INCLUDEPATH += $$PWD/libs/includes/KIconThemes #DEPENDPATH += $$PWD/libs/includes/KIconThemes ##KIOCore #LIBS += -L$$PWD/libs/bin/ -lKF5KIOCore #INCLUDEPATH += $$PWD/libs/includes/KIOCore #DEPENDPATH += $$PWD/libs/includes/KIOCore ##KJobWidgets #LIBS += -L$$PWD/libs/bin/ -lKF5JobWidgets #INCLUDEPATH += $$PWD/libs/includes/KJobWidgets #DEPENDPATH += $$PWD/libs/includes/KJobWidgets ##KService #LIBS += -L$$PWD/libs/bin/ -lKF5Service #INCLUDEPATH += $$PWD/libs/includes/KService #DEPENDPATH += $$PWD/libs/includes/KService ##KCompletion #LIBS += -L$$PWD/libs/bin/ -lKF5Completion #INCLUDEPATH += $$PWD/libs/includes/KCompletion #DEPENDPATH += $$PWD/libs/includes/KCompletion ##KItemViews #LIBS += -L$$PWD/libs/bin/ -lKF5ItemViews #INCLUDEPATH += $$PWD/libs/includes/KItemViews #DEPENDPATH += $$PWD/libs/includes/KItemViews ##KConfigWidgets #LIBS += -L$$PWD/libs/bin/ -lKF5ConfigWidgets #INCLUDEPATH += $$PWD/libs/includes/KConfigWidgets #DEPENDPATH += $$PWD/libs/includes/KConfigWidgets ##KI18n #LIBS += -L$$PWD/libs/bin/ -lKF5I18n #INCLUDEPATH += $$PWD/libs/includes/KI18n #DEPENDPATH += $$PWD/libs/includes/KI18n ##KWidgetsAddons #LIBS += -L$$PWD/libs/bin/ -lKF5WidgetsAddons #INCLUDEPATH += $$PWD/libs/includes/KWidgetsAddons #DEPENDPATH += $$PWD/libs/includes/KWidgetsAddons ##KCodecs #LIBS += -L$$PWD/libs/bin/ -lKF5Codecs #INCLUDEPATH += $$PWD/libs/includes/KCodecs #DEPENDPATH += $$PWD/libs/includes/KCodecs ##KConfigGui #LIBS += -L$$PWD/libs/bin/ -lKF5ConfigGui #INCLUDEPATH += $$PWD/libs/includes/KConfigGui #DEPENDPATH += $$PWD/libs/includes/KConfigGui ##KConfigCore #LIBS += -L$$PWD/libs/bin/ -lKF5ConfigCore #INCLUDEPATH += $$PWD/libs/includes/KConfigCore #DEPENDPATH += $$PWD/libs/includes/KConfigCore diff --git a/src/controls/FileBrowser.qml b/src/controls/FileBrowser.qml index b610328..381c3a4 100644 --- a/src/controls/FileBrowser.qml +++ b/src/controls/FileBrowser.qml @@ -1,1188 +1,1192 @@ /* * 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.10 import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import QtQml.Models 2.3 import QtQml 2.1 import org.kde.kirigami 2.8 as Kirigami import org.kde.mauikit 1.0 as Maui import org.kde.mauikit 1.1 as MauiLab import "private" Maui.Page { id: control property url currentPath - onCurrentPathChanged: control.browserView.path = control.currentPath + onCurrentPathChanged: + { + if(control.browserView) + control.browserView.path = control.currentPath + } property int viewType : Maui.FMList.LIST_VIEW onViewTypeChanged: browserView.viewType = control.viewType property int thumbnailsSize : Maui.Style.iconSizes.large * 1.7 property var indexHistory : [] property bool isCopy : false property bool isCut : false property bool group : false //group properties from the browser since the browser views are loaded async and //their properties can not be accesed inmediately, so they are stored here and then when completed they are set property BrowserSettings settings : BrowserSettings {} property alias selectionBar : selectionBarLoader.item property alias browserView : _browserList.currentItem readonly 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 || String(control.currentPath).startsWith("trash:/") 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() }, ToolButton { visible: String(control.currentPath).startsWith("trash:/") icon.name: "trash-empty" text: qsTr("Empty trash") onClicked: Maui.FM.emptyTrash() } ] headBar.position: Kirigami.Settings.isMobile ? ToolBar.Footer : ToolBar.Header headBar.rightContent:[ ToolButton { icon.name: "item-select" checkable: true checked: settings.selectionMode onClicked: settings.selectionMode = !settings.selectionMode }, Maui.ToolButtonMenu { icon.name: "view-sort" MenuItem { text: qsTr("Folders first") checked: control.currentFMList.foldersFirst checkable: true onTriggered: control.currentFMList.foldersFirst = !control.currentFMList.foldersFirst } MenuSeparator {} MenuItem { text: qsTr("Type") checked: control.currentFMList.sortBy === Maui.FMList.MIME checkable: true onTriggered: control.currentFMList.sortBy = Maui.FMList.MIME autoExclusive: true } MenuItem { text: qsTr("Date") checked: control.currentFMList.sortBy === Maui.FMList.DATE checkable: true onTriggered: control.currentFMList.sortBy = Maui.FMList.DATE autoExclusive: true } MenuItem { text: qsTr("Modified") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.MODIFIED onTriggered: control.currentFMList.sortBy = Maui.FMList.MODIFIED autoExclusive: true } MenuItem { text: qsTr("Size") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.SIZE onTriggered: control.currentFMList.sortBy = Maui.FMList.SIZE autoExclusive: true } MenuItem { text: qsTr("Name") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.LABEL onTriggered: control.currentFMList.sortBy = Maui.FMList.LABEL autoExclusive: true } MenuSeparator{} MenuItem { id: groupAction text: qsTr("Group") checkable: true checked: control.group onTriggered: { control.group = !control.group if(control.group) control.groupBy() else browserView.currentView.section.property = "" } } }, ToolButton { id: _optionsButton icon.name: "overflow-menu" enabled: currentFMList.pathType !== Maui.FMList.TAGS_PATH && currentFMList.pathType !== Maui.FMList.TRASH_PATH && currentFMList.pathType !== Maui.FMList.APPS_PATH onClicked: { if(browserMenu.visible) browserMenu.close() else browserMenu.show(_optionsButton, 0, height) } checked: browserMenu.visible checkable: false } ] headBar.leftContent: [ ToolButton { icon.name: "go-previous" onClicked: control.goBack() }, ToolButton { icon.name: "go-next" onClicked: control.goNext() }, Maui.ToolActions { direction: Qt.Vertical currentAction: switch(browserView.viewType) { case Maui.FMList.ICON_VIEW: return actions[0] case Maui.FMList.LIST_VIEW: return actions[1] case Maui.FMList.MILLERS_VIEW: return actions[2] } Action { icon.name: "view-list-icons" text: qsTr("Grid") onTriggered: control.viewType = Maui.FMList.ICON_VIEW checked: browserView.viewType === Maui.FMList.ICON_VIEW icon.width: Maui.Style.iconSizes.medium } Action { icon.name: "view-list-details" text: qsTr("List") onTriggered: control.viewType = Maui.FMList.LIST_VIEW icon.width: Maui.Style.iconSizes.medium checkable: true checked: browserView.viewType === Maui.FMList.LIST_VIEW } Action { icon.name: "view-file-columns" text: qsTr("Columns") onTriggered: control.viewType = Maui.FMList.MILLERS_VIEW icon.width: Maui.Style.iconSizes.medium checkable: true checked: browserView.viewType === Maui.FMList.MILLERS_VIEW } } ] Loader { id: dialogLoader } Component { id: removeDialogComponent Maui.Dialog { property var urls: [] title: qsTr(String("Removing %1 files").arg(urls.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.animate() control.clearSelection() } for(var i in urls) Maui.FM.removeFile(urls[i]) close() } onAccepted: { if(control.selectionBar && control.selectionBar.visible) { control.selectionBar.animate() control.clearSelection() } for(var i in urls) Maui.FM.moveToTrash(urls[i]) 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 { taglist.strict: false onTagsReady: { composerList.updateToUrls(tags) if(control.previewer.visible) control.previewer.tagBar.list.refresh() } } } Component { id: _configDialogComponent Maui.Dialog { maxHeight: _configLayout.implicitHeight * 1.5 maxWidth: 300 defaultButtons: false Kirigami.FormLayout { id: _configLayout width: parent.width anchors.centerIn: parent Kirigami.Separator { Kirigami.FormData.label: qsTr("Navigation") Kirigami.FormData.isSection: true } Switch { icon.name: "image-preview" checkable: true checked: settings.showThumbnails Kirigami.FormData.label: qsTr("Thumbnails") onToggled: settings.showThumbnails = !settings.showThumbnails } Switch { Kirigami.FormData.label: qsTr("Hidden files") checkable: true checked: control.currentFMList.hidden onToggled: control.currentFMList.hidden = !control.currentFMList.hidden } Kirigami.Separator { Kirigami.FormData.label: qsTr("Others") Kirigami.FormData.isSection: true } Switch { Kirigami.FormData.label: qsTr("Status bar") checkable: true checked: control.footBar.visible onToggled: control.footBar.visible = !control.footBar.visible } } } } Maui.FilePreviewer { id: previewer onShareButtonClicked: control.shareFiles([url]) } BrowserMenu { id: browserMenu } FileMenu { id: itemMenu width: Maui.Style.unit *200 onBookmarkClicked: control.bookmarkFolder([item.path]) onCopyClicked: { if(item) control.copy([item.path]) } onCutClicked: { if(item) control.cut([item.path]) } onTagsClicked: { if(item) { dialogLoader.sourceComponent = tagsDialogComponent dialog.composerList.urls = [item.path] dialog.open() } } onRenameClicked: { dialogLoader.sourceComponent = renameDialogComponent dialog.open() } onRemoveClicked: { control.remove([item.path]) } onShareClicked: control.shareFiles([item.path]) } Connections { target: browserView.currentView onKeyPress: { console.log(event.key, event.modifier, event.count) const index = browserView.currentView.currentIndex const item = control.currentFMList.get(index) // Shortcuts for refreshing if((event.key == Qt.Key_F5)) { control.currentFMList.refresh() } // Shortcuts for selecting file if((event.key == Qt.Key_A) && (event.modifiers & Qt.ControlModifier)) { control.selectAll() } if(event.key == Qt.Key_S) { if(control.selectionBar && control.selectionBar.contains(item.path)) { control.selectionBar.removeAtUri(item.path) }else { control.addToSelection(item) } } if((event.key == Qt.Key_Left || event.key == Qt.Key_Right || event.key == Qt.Key_Down || event.key == Qt.Key_Up) && (event.modifiers & Qt.ControlModifier) && (event.modifiers & Qt.ShiftModifier)) { if(control.selectionBar && control.selectionBar.contains(item.path)) { control.selectionBar.removeAtUri(item.path) }else { control.addToSelection(item) } } // Shortcut for pasting an item if((event.key == Qt.Key_V) && (event.modifiers & Qt.ControlModifier)) { control.paste(Maui.Handy.getClipboard().urls) } // Shortcut for cutting an item if((event.key == Qt.Key_X) && (event.modifiers & Qt.ControlModifier)) { var urls = [] if(control.selectionBar) { urls = control.selectionBar.uris } else { urls = [item.path] } control.cut(urls) } // Shortcut for copying an item if((event.key == Qt.Key_C) && (event.modifiers & Qt.ControlModifier)) { var urls = [] if(control.selectionBar) { urls = control.selectionBar.uris } else { urls = [item.path] } control.copy(urls) } // Shortcut for removing an item if(event.key == Qt.Key_Delete) { var urls = [] if(control.selectionBar) { urls = control.selectionBar.uris } else { urls = [item.path] } control.remove(urls) } // Shortcut for opening new tab if((event.key == Qt.Key_T) && (event.modifiers & Qt.ControlModifier)) { const _path = (currentPath).toString() control.openTab(" ") control.currentPath = _path } // Shortcut for closing tab if((event.key == Qt.Key_W) && (event.modifiers & Qt.ControlModifier)) { if(tabsBar.count > 1) control.closeTab(tabsBar.currentIndex) } // Shortcut for opening files in new tab , previewing or launching if((event.key == Qt.Key_Return) && (event.modifiers & Qt.ControlModifier)) { if(item.isdir == "true") control.openTab(item.path) }else if((event.key == Qt.Key_Return) && (event.modifiers & Qt.AltModifier)) { control.previewer.show(control.currentFMList.get(index).path) }else if(event.key == Qt.Key_Return) { indexHistory.push(index) control.itemClicked(index) } // Shortcut for going back in browsing history if(event.key == Qt.Key_Backspace || event.key == Qt.Key_Back) { if(control.selectionBar) control.clearSelection() else control.goBack() } // Shortcut for clearing selection if(event.key == Qt.Key_Escape) { if(control.selectionBar) control.clearSelection() } } onItemClicked: { browserView.currentView.currentIndex = index indexHistory.push(index) control.itemClicked(index) } onItemDoubleClicked: { browserView.currentView.currentIndex = index indexHistory.push(index) control.itemDoubleClicked(index) } onItemRightClicked: { if(control.currentFMList.pathType !== Maui.FMList.TRASH_PATH && control.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.removeAtUri(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(control) else return control.rightClicked() } onAreaRightClicked: browserMenu.show(control) // onWarning: // { // notify("dialog-information", "An error happened", message) // } // onProgress: // { // if(percent === 100) // _progressBar.value = 0 // else // _progressBar.value = percent/100 // } } Component { id: selectionBarComponent MauiLab.SelectionBar { id: _selectionBar singleSelection: settings.singleSelection onCountChanged: { if(_selectionBar.count < 1) control.clearSelection() } onExitClicked: control.clearSelection() listDelegate: ListBrowserDelegate { Kirigami.Theme.inherit: true width: parent.width height: Maui.Style.iconSizes.big + Maui.Style.space.big label1.text: model.label label2.text: model.path showEmblem: true showThumbnails: true leftEmblem: "list-remove" folderSize: Maui.Style.iconSizes.big onLeftEmblemClicked: _selectionBar.removeAtIndex(index) keepEmblemOverlay: Kirigami.Settings.isMobile background: null onClicked: control.previewer.show(model.path) onPressAndHold: removeAtIndex(index) } Action { text: qsTr("Open") icon.name: "document-open" onTriggered: { if(control.selectionBar) { for(var i in uris) openFile(uris[i]) } } } Action { text: qsTr("Copy") icon.name: "edit-copy" onTriggered: if(control.selectionBar) { control.selectionBar.animate() control.copy(uris) } } Action { text: qsTr("Cut") icon.name: "edit-cut" onTriggered: if(control.selectionBar) { control.selectionBar.animate() control.cut(uris) } } Action { text: qsTr("Tags") icon.name: "tag" onTriggered: if(control.selectionBar) { dialogLoader.sourceComponent = tagsDialogComponent dialog.composerList.urls = uris dialog.open() } } Action { text: qsTr("Share") icon.name: "document-share" onTriggered: { control.shareFiles(uris) } } Action { text: qsTr("Remove") icon.name: "edit-delete" Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor onTriggered: { control.remove(uris) } } } } ObjectModel { id: tabsObjectModel } ColumnLayout { id: _layout anchors.fill: parent spacing: 0 Maui.TabBar { id: tabsBar visible: _browserList.count > 1 Layout.fillWidth: true Layout.preferredHeight: tabsBar.implicitHeight position: TabBar.Header currentIndex : _browserList.currentIndex ListModel { id: tabsListModel } Keys.onPressed: { if(event.key == Qt.Key_Return) { _browserList.currentIndex = currentIndex control.currentPath = tabsObjectModel.get(currentIndex).path } } Repeater { id: _repeater model: tabsListModel Maui.TabButton { id: _tabButton implicitHeight: tabsBar.implicitHeight implicitWidth: Math.max(control.width / _repeater.count, 120) checked: index === _browserList.currentIndex text: tabsObjectModel.get(index).currentFMList.pathName onClicked: { _browserList.currentIndex = index control.currentPath = tabsObjectModel.get(index).path } onCloseClicked: control.closeTab(index) } } } ListView { id: _browserList Layout.margins: 0 Layout.fillWidth: true Layout.fillHeight: true clip: true focus: true 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) // DropArea // { // id: _dropArea // anchors.fill: parent // z: parent.z -2 // onDropped: // { // const urls = drop.urls // for(var i in urls) // { // const item = Maui.FM.getFileInfo(urls[i]) // if(item.isdir == "true") // { // control.openTab(urls[i]) // } // } // } // } } Loader { id: selectionBarLoader Layout.alignment: Qt.AlignCenter Layout.margins: Maui.Style.space.medium Layout.preferredHeight: control.selectionBar && control.selectionBar.visible ? control.selectionBar.barHeight: 0 Layout.maximumWidth: 500 Layout.minimumWidth: 100 Layout.fillWidth: true 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.currentView.forceActiveFocus() } 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 closeTab(index) { tabsObjectModel.remove(index) tabsListModel.remove(index) } function openTab(path) { if(path) { - console.log(" OPENIGN A PATH") + control.currentPath = path const component = Qt.createComponent("private/BrowserView.qml"); if (component.status === Component.Ready) { - const object = component.createObject(tabsObjectModel, {'path': path}); + const object = component.createObject(tabsObjectModel, {'path': control.currentPath}); tabsObjectModel.append(object) tabsListModel.append({"path": path}) _browserList.currentIndex = tabsObjectModel.count - 1 browserView.viewType = control.viewType } } } 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(control.currentFMList.pathType) { case Maui.FMList.CLOUD_PATH: if(item.isdir === "true") { control.openFolder(path) } else { Maui.FM.openCloudItem(item) } break; default: if(settings.selectionMode && item.isdir == "false") { if(control.selectionBar && control.selectionBar.contains(item.path)) { control.selectionBar.removeAtPath(item.path) }else { control.addToSelection(item) } } else { if(item.isdir == "true") { control.openFolder(path) } else { if (Kirigami.Settings.isMobile) { control.previewer.show(path) } else { control.openFile(path) } } } } } function openFile(path) { Maui.FM.openUrl(path) } function openFolder(path) { if(!String(path).length) return; control.currentPath = path } function goBack() { openFolder(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(item.path.startsWith("tags://") || item.path.startsWith("applications://") ) return if(!control.selectionBar) selectionBarLoader.sourceComponent = selectionBarComponent control.selectionBar.append(item.path, item) } function clearSelection() { if(control.selectionBar) { control.selectionBar.clear() selectionBarLoader.sourceComponent = null settings.selectionMode = false } } function copy(urls) { Maui.Handy.copyToClipboard({"urls": urls}) control.isCut = false control.isCopy = true } function cut(urls) { Maui.Handy.copyToClipboard({"urls": urls}) control.isCut = true control.isCopy = false } function paste() { const urls = Maui.Handy.getClipboard().urls if(!urls) return if(control.isCut) { control.currentFMList.cutInto(urls) control.clearSelection() }else { control.currentFMList.copyInto(urls) } } function remove(urls) { dialogLoader.sourceComponent= removeDialogComponent dialog.urls = urls dialog.open() } 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 bookmarkFolder(paths) //multiple paths { control.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; } if(!prop) { control.browserView.currentView.section.property = "" return } control.browserView.viewType = Maui.FMList.LIST_VIEW control.browserView.currentView.section.property = prop control.browserView.currentView.section.criteria = criteria } function openConfigDialog() { dialogLoader.sourceComponent = _configDialogComponent control.dialog.open() } } diff --git a/src/fm/fm.cpp b/src/fm/fm.cpp index f0857bc..175dd91 100644 --- a/src/fm/fm.cpp +++ b/src/fm/fm.cpp @@ -1,507 +1,507 @@ /* * 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" #ifdef COMPONENT_TAGGING #include "tagging.h" #endif #ifdef COMPONENT_SYNCING #include "syncing.h" #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #elif defined Q_OS_LINUX #include "mauikde.h" #include #include #include #include #include #include #include #include #endif FM::FM(QObject *parent) : QObject(parent) #ifdef COMPONENT_SYNCING ,sync(new Syncing(this)) #endif #ifdef COMPONENT_TAGGING ,tag(Tagging::getInstance()) #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) ,dirLister(new KCoreDirLister(this)) #endif { #ifdef Q_OS_ANDROID MAUIAndroid::checkRunTimePermissions(); #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()) { 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.mostLocalUrl().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::FAVORITE, QVariant(this->urlTagExists(kfile.mostLocalUrl().toString(), "fav")).toString()}, {FMH::MODEL_KEY::COUNT, kfile.isLocalFile() && kfile.isDir() ? QString::number(QDir(kfile.localPath()).count() - 2) : "0"} }; } res.path = url; 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 #ifdef COMPONENT_SYNCING connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QUrl &url) { emit this->cloudServerContentReady(list, url); }); connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QUrl &url, const Syncing::SIGNAL_TYPE &signalType) { switch(signalType) { case Syncing::SIGNAL_TYPE::OPEN: FMStatic::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 QUrl &url) { emit this->newItem(dir, url); }); connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QUrl &url) { emit this->newItem(item, url); }); #endif } FM::~FM() {} void FM::getPathContent(const QUrl& path, const bool &hidden, const bool &onlyDirs, const QStringList& filters, const QDirIterator::IteratorFlags &iteratorFlags) { qDebug()<< "Getting async path contents"; #if defined Q_OS_ANDROID || defined Q_OS_WIN32 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; FMH::MODEL_LIST content; if (FMStatic::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(" ")); qDebug() << "NAME FILTERS SET" << this->dirLister->nameFilter(); // if(this->dirLister->url() == path) // { // this->dirLister->emitChanges(); // return; // } if(this->dirLister->openUrl(path)) qDebug()<< "GETTING PATH CONTENT" << path; #endif } FMH::MODEL_LIST FM::getAppsPath() { #if defined Q_OS_ANDROID || defined Q_OS_WIN32 return FMH::MODEL_LIST(); #else 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]} } }; #endif } FMH::MODEL_LIST FM::getTags(const int &limit) { Q_UNUSED(limit); FMH::MODEL_LIST data; #ifdef COMPONENT_TAGGING if(this->tag) { for(const auto &tag : this->tag->getAllTags(false)) { QVariantMap item = tag.toMap(); const auto label = item.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::MODIFIED, QDateTime::fromString(item.value(TAG::KEYMAP[TAG::KEYS::ADD_DATE]).toString(), Qt::TextDate).toString()}, {FMH::MODEL_KEY::IS_DIR, "true"}, {FMH::MODEL_KEY::LABEL, label}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::TAGS_PATH]} }; } } #endif return data; } bool FM::getCloudServerContent(const QUrl &path, const QStringList &filters, const int &depth) { #ifdef COMPONENT_SYNCING const auto __list = path.toString().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)); QVariantList data; 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; #else return false; #endif } void FM::createCloudDir(const QString &path, const QString &name) { #ifdef COMPONENT_SYNCING this->sync->createDir(path, name); #endif } void FM::openCloudItem(const QVariantMap &item) { #ifdef COMPONENT_SYNCING 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); #endif } void FM::getCloudItem(const QVariantMap &item) { #ifdef COMPONENT_SYNCING this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::DOWNLOAD); #endif } QString FM::resolveUserCloudCachePath(const QString &server, const QString &user) { return FMH::CloudCachePath+"opendesktop/"+user; } QString FM::resolveLocalCloudPath(const QString& path) { #ifdef COMPONENT_SYNCING return QString(path).replace(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+this->sync->getUser(), ""); #else return QString(); #endif } static bool doNameFilter(const QString &name, const QStringList &filters) { for(const auto &filter : std::accumulate(filters.constBegin(), filters.constEnd(), QVector {}, [](QVector &res, const QString &filter) -> QVector { res.append(QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard)); return res; })) { if(filter.exactMatch(name)) { return true; } } return false; } FMH::MODEL_LIST FM::getTagContent(const QString &tag, const QStringList &filters) { FMH::MODEL_LIST content; #ifdef COMPONENT_TAGGING if(tag.isEmpty()) { return this->getTags(); }else { for(const auto &data : this->tag->getUrls(tag, false, [filters](QVariantMap &item) -> bool - { return doNameFilter(FMH::mapValue(item, FMH::MODEL_KEY::URL), filters); })) + { return filters.isEmpty() ? true : doNameFilter(FMH::mapValue(item, FMH::MODEL_KEY::URL), filters); })) { const auto url = QUrl(data.toMap()[TAG::KEYMAP[TAG::KEYS::URL]].toString()); if(url.isLocalFile() && !FMH::fileExists(url)) continue; content << FMH::getFileInfoModel(url); } } #endif return content; } FMH::MODEL_LIST FM::getUrlTags(const QUrl &url) { FMH::MODEL_LIST content; #ifdef COMPONENT_TAGGING content = FMH::toModelList(this->tag->getUrlTags(url.toString(), false)); #endif return content; } bool FM::urlTagExists(const QUrl& url, const QString tag) { #ifdef COMPONENT_TAGGING return this->tag->urlTagExists(url.toString(), tag, false); #endif } bool FM::addTagToUrl(const QString tag, const QUrl& url) { #ifdef COMPONENT_TAGGING return this->tag->tagUrl(url.toString(), tag); #endif } bool FM::removeTagToUrl(const QString tag, const QUrl& url) { #ifdef COMPONENT_TAGGING return this->tag->removeUrlTag(url.toString(), tag); #endif } bool FM::cut(const QList &urls, const QUrl &where) { for(const auto &url : urls) { if(FMStatic::isCloud(url.toString())) { #ifdef COMPONENT_SYNCING this->sync->setCopyTo(where.toString()); // this->sync->resolveFile(url, Syncing::SIGNAL_TYPE::COPY); #endif }else { FMStatic::cut(url, where); } } return true; } bool FM::copy(const QList &urls, const QUrl &where) { QStringList cloudPaths; for(const auto &url : urls) { if(FMStatic::isDir(url)) { FMStatic::copy(url, where.toString()+"/"+QFileInfo(url.toLocalFile()).fileName(), false); }else if(FMStatic::isCloud(url)) { #ifdef COMPONENT_SYNCING this->sync->setCopyTo(where.toString()); // this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); #endif }else { if(FMStatic::isCloud(where)) cloudPaths << url.toString(); else FMStatic::copy(url, where.toString()+"/"+FMH::getFileInfoModel(url)[FMH::MODEL_KEY::LABEL], false); } } #ifdef COMPONENT_SYNCING if(!cloudPaths.isEmpty()) { qDebug()<<"UPLOAD QUEUE" << cloudPaths; const auto firstPath = cloudPaths.takeLast(); this->sync->setUploadQueue(cloudPaths); if(where.toString().split("/").last().contains(".")) { QStringList whereList = where.toString().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.toString()), firstPath); } #endif return true; }