diff --git a/mauikit.qrc b/mauikit.qrc index a2f248a..e835f80 100644 --- a/mauikit.qrc +++ b/mauikit.qrc @@ -1,53 +1,54 @@ src/controls/ToolBar.qml src/controls/SideBar.qml src/controls/ApplicationWindow.qml src/controls/Style.qml src/controls/ShareDialog.qml src/controls/PieButton.qml src/controls/Page.qml src/controls/private/SideBarDelegate.qml src/controls/private/PathBarDelegate.qml src/controls/private/EdgeShadow.qml - src/controls/private/BrowserMenu.qml - src/controls/private/FileMenu.qml + src/controls/private/BrowserMenu.qml + src/controls/private/BrowserView.qml + src/controls/private/FileMenu.qml src/controls/private/AudioPreview.qml src/controls/private/ImagePreview.qml src/controls/private/TextPreview.qml src/controls/private/VideoPreview.qml src/controls/private/DefaultPreview.qml src/controls/private/AccountsHelper.qml src/controls/Holder.qml src/controls/ListDelegate.qml src/controls/GlobalDrawer.qml src/controls/SelectionBar.qml src/controls/IconDelegate.qml src/controls/LabelDelegate.qml src/controls/NewDialog.qml src/controls/TagsBar.qml src/controls/TagsDialog.qml src/controls/private/TagList.qml src/controls/private/TagDelegate.qml src/controls/ColorsBar.qml src/controls/FileBrowser.qml src/controls/FilePreviewer.qml src/controls/FileDialog.qml src/controls/ListBrowser.qml src/controls/PathBar.qml src/controls/GridBrowser.qml src/controls/Dialog.qml src/controls/AboutDialog.qml src/controls/Popup.qml src/controls/TextField.qml src/controls/Badge.qml src/controls/GridView.qml src/controls/SyncDialog.qml src/controls/Terminal.qml src/controls/Editor.qml src/controls/PlacesSidebar.qml src/controls/Store.qml src/controls/ImageViewer.qml src/controls/private/StoreDelegate.qml diff --git a/src/controls/Badge.qml b/src/controls/Badge.qml index 6e654be..f3fb252 100644 --- a/src/controls/Badge.qml +++ b/src/controls/Badge.qml @@ -1,105 +1,105 @@ /* * 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 org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import "private" Rectangle { id: control Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Complementary property alias item : loader.item property bool hovered : false property int size: isMobile ? iconSizes.medium : iconSizes.small property string iconName : "" property string text : "" signal clicked() signal pressed() signal hovered() signal released() z: parent.z+1 height: size + space.small - width: Math.max(implicitWidth, size + space.small) - implicitWidth: (loader.sourceComponent == labelComponent ? loader.item.implicitWidth : size ) + space.small + width: Math.max(implicitWidth, height) + implicitWidth: (loader.sourceComponent == labelComponent ? Math.max(loader.item.implicitWidth + Maui.Style.space.small, control.height) : control.height) radius: Math.min(width, height) color: Kirigami.Theme.backgroundColor border.color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) clip: false Loader { id: loader anchors.fill: parent sourceComponent: control.text.length && !control.iconName.length ? labelComponent : (!control.text.length && control.iconName.length ? iconComponent : undefined) } Component { id: labelComponent Label { height: parent.height width: parent.width text: control.text font.weight: Font.Bold font.bold: true font.pointSize: fontSizes.default color: Kirigami.Theme.textColor verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter } } Component { id: iconComponent ToolButton { anchors.centerIn: parent icon.name: control.iconName icon.color: Kirigami.Theme.textColor icon.width: control.size enabled: false } } MouseArea { id: mouseArea anchors.fill: parent onClicked: control.clicked() onPressed: control.pressed() onReleased: control.released() hoverEnabled: true onEntered: hovered = true onExited: hovered = false } } diff --git a/src/controls/FileBrowser.qml b/src/controls/FileBrowser.qml index ead64f7..e5e074c 100644 --- a/src/controls/FileBrowser.qml +++ b/src/controls/FileBrowser.qml @@ -1,1108 +1,891 @@ 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 alias trackChanges: control.currentFMList.trackChanges + property alias saveDirProps: control.currentFMList.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 browser : _browserView.currentView + property alias currentFMList : _browserView.currentFMList 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 onGoBackTriggered: { control.goBack() console.log("trying to go BACCCCCCCCCCCCCCCCCK") } onGoForwardTriggered: control.goNext() 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 + checked: control.currentFMList.preview + onTriggered: control.currentFMList.preview = !control.currentFMList.preview }, Action { id: _hiddenAction icon.name: "visibility" text: qsTr("Hidden files") checkable: true - checked: list.hidden - onTriggered: list.hidden = !list.hidden + checked: control.currentFMList.hidden + onTriggered: control.currentFMList.hidden = !control.currentFMList.hidden }, Action { id: _bookmarkAction icon.name: "bookmark-new" text: qsTr("Bookmark") onTriggered: newBookmark([currentPath]) }, Action { id: _newFolderAction icon.name: "folder-add" text: qsTr("New folder") onTriggered: { dialogLoader.sourceComponent= newFolderDialogComponent dialog.open() } }, Action { id: _newDocumentAction icon.name: "document-new" text: qsTr("New file") onTriggered: { dialogLoader.sourceComponent= newFileDialogComponent dialog.open() } }, Action { id: _pasteAction text: qsTr("Paste ")+"["+browserMenu.pasteFiles+"]" icon.name: "edit-paste" enabled: browserMenu.pasteFiles > 0 onTriggered: paste() }] 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.visible: !isMobile 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) + onFinished: control.currentFMList.createDir(text) rejectButton.visible: false textEntry.placeholderText: qsTr("Folder name...") } } Component { id: newFileDialogComponent Maui.NewDialog { title: qsTr("New file") message: qsTr("Create a new file with a custom name and extension") acceptButton.text: qsTr("Create") onFinished: Maui.FM.createFile(control.currentPath, text) rejectButton.visible: false textEntry.placeholderText: qsTr("File name...") } } Component { id: renameDialogComponent Maui.NewDialog { title: qsTr("Rename file") message: qsTr("Rename a file or folder to a new custom name") textEntry.text: itemMenu.item.label textEntry.placeholderText: qsTr("New name...") onFinished: Maui.FM.rename(itemMenu.item.path, textEntry.text) onRejected: close() acceptText: qsTr("Rename") rejectText: qsTr("Cancel") } } Component { id: shareDialogComponent Maui.ShareDialog {} } Component { id: tagsDialogComponent Maui.TagsDialog { onTagsReady: composerList.updateToUrls(tags) } } BrowserMenu { id: browserMenu 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() } 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 - 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) - 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 - - - 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 - onItemClicked: - { - control.currentFMList = _millersFMList - _millerColumns.itemClicked(index) - } - - onItemDoubleClicked: - { - control.currentFMList = _millersFMList - _millerColumns.itemDoubleClicked(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: { + console.log("item clicked connections:", index) 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) } } } // headBar.stickyRightContent: true headBar.rightContent:[ 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 + onTriggered: _browserView.viewType = Maui.FMList.ICON_VIEW checkable: false - checked: list.viewType === Maui.FMList.ICON_VIEW + checked: _browserView.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 + onTriggered: _browserView.viewType = Maui.FMList.LIST_VIEW icon.width: iconSizes.medium - checked: list.viewType === Maui.FMList.LIST_VIEW + checked: _browserView.viewType === Maui.FMList.LIST_VIEW text: qsTr("List view") // autoExclusive: true }, Action { icon.name: "view-file-columns" - onTriggered: list.viewType = Maui.FMList.MILLERS_VIEW + onTriggered: _browserView.viewType = Maui.FMList.MILLERS_VIEW icon.width: iconSizes.medium - checked: list.viewType === Maui.FMList.MILLERS_VIEW + checked: _browserView.viewType === Maui.FMList.MILLERS_VIEW text: qsTr("Column view") // autoExclusive: true }, Kirigami.Action { icon.name: "view-sort" text: qsTr("Sort") Kirigami.Action { text: qsTr("Folders first") - checked: list.foldersFirst - onTriggered: list.foldersFirst = !list.foldersFirst + checked: con.foldersFirst + onTriggered: control.currentFMList.foldersFirst = !control.currentFMList.foldersFirst } Kirigami.Action { text: qsTr("Type") - checked: list.sortBy === Maui.FMList.MIME - onTriggered: list.sortBy = Maui.FMList.MIME + checked: control.currentFMList.sortBy === Maui.FMList.MIME + onTriggered: control.currentFMList.sortBy = Maui.FMList.MIME } Kirigami.Action { text: qsTr("Date") - checked: list.sortBy === Maui.FMList.DATE - onTriggered: list.sortBy = Maui.FMList.DATE + checked: control.currentFMList.sortBy === Maui.FMList.DATE + onTriggered: control.currentFMList.sortBy = Maui.FMList.DATE } Kirigami.Action { text: qsTr("Modified") - checked: list.sortBy === Maui.FMList.MODIFIED - onTriggered: list.sortBy = Maui.FMList.MODIFIED + checked: control.currentFMList.sortBy === Maui.FMList.MODIFIED + onTriggered: control.currentFMList.sortBy = Maui.FMList.MODIFIED } Kirigami.Action { text: qsTr("Size") - checked: list.sortBy === Maui.FMList.SIZE - onTriggered: list.sortBy = Maui.FMList.SIZE + checked: control.currentFMList.sortBy === Maui.FMList.SIZE + onTriggered: control.currentFMList.sortBy = Maui.FMList.SIZE } Kirigami.Action { text: qsTr("Name") - checked: list.sortBy === Maui.FMList.LABEL - onTriggered: list.sortBy = Maui.FMList.LABEL + checked: control.currentFMList.sortBy === Maui.FMList.LABEL + onTriggered: control.currentFMList.sortBy = Maui.FMList.LABEL } Kirigami.Action { id: groupAction text: qsTr("Group") - checked: group + checked: control.group onTriggered: { - group = !group - if(group) + control.group = !control.group + if(control.group) groupBy() - else + else browser.section.property = "" } } }, Kirigami.Action { text: qsTr("Select") icon.name: "item-select" checkable: false - checked: selectionMode - onTriggered: selectionMode = !selectionMode + checked: control.selectionMode + onTriggered: control.selectionMode = !control.selectionMode } ] } ] headBar.leftContent: [ ToolButton { icon.name: "go-previous" onClicked: control.goBack() }, ToolButton { id: goUpButton visible: true icon.name: "go-up" onClicked: control.goUp() }, ToolButton { icon.name: "go-next" onClicked: control.goNext() } ] footBar.visible: false Component { id: selectionBarComponent Maui.SelectionBar { anchors.fill: parent onIconClicked: _selectionBarmenu.popup() onExitClicked: clean() 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 + BrowserView { - id: viewLoader + id: _browserView 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.topMargin: _browserView.viewType == Maui.FMList.ICON_VIEW ? contentMargins * 2 : 0 + 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 } } 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) + if(_browserView.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 + 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(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) + if(_browserView.viewType == Maui.FMList.ICON_VIEW) browser.adaptGrid() } function goBack() { - populate(modelList.previousPath) + populate(control.currentFMList.previousPath) browser.currentIndex = indexHistory.pop() } function goNext() { - openFolder(modelList.posteriorPath) + openFolder(control.currentFMList.posteriorPath) } function goUp() { - openFolder(modelList.parentPath) + openFolder(control.currentFMList.parentPath) } function refresh() { var pos = browser.contentY browser.contentY = pos } function addToSelection(item, append) { selectionBarLoader.sourceComponent= selectionBarComponent selectionBar.singleSelection = control.singleSelection selectionBar.append(item) } 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) clean() } } 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) + 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; } - list.viewType = Maui.FMList.LIST_VIEW + _browserView.viewType = Maui.FMList.LIST_VIEW if(!prop) { browser.section.property = "" return } browser.section.property = prop browser.section.criteria = criteria } } diff --git a/src/controls/FileDialog.qml b/src/controls/FileDialog.qml index f91fee7..512edbe 100644 --- a/src/controls/FileDialog.qml +++ b/src/controls/FileDialog.qml @@ -1,286 +1,287 @@ /* * 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 org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Layouts 1.3 Maui.Dialog { id: control maxHeight: isMobile ? parent.height * 0.95 : unit * 500 maxWidth: unit * 700 // defaultButtons: false page.padding: 0 property string initPath property string suggestedFileName : "" property var filters: [] property int filterType: Maui.FMList.NONE property bool onlyDirs: false property int sortBy: Maui.FMList.MODIFIED property bool searchBar : false readonly property var modes : ({OPEN: 0, SAVE: 1}) property int mode : modes.OPEN property var callback : ({}) property alias textField: _textField property alias singleSelection : browser.singleSelection rejectButton.visible: false acceptButton.text: control.mode === modes.SAVE ? qsTr("Save") : qsTr("Open") footBar.leftSretch: false footBar.middleContent: Maui.TextField { id: _textField visible: control.mode === modes.SAVE Layout.fillWidth: true placeholderText: qsTr("File name") text: suggestedFileName } onAccepted: { console.log("CURRENT PATHb", browser.currentPath+"/"+textField.text) if(control.mode === modes.SAVE && Maui.FM.fileExists(browser.currentPath+"/"+textField.text)) { _confirmationDialog.open() }else { done() } } Maui.Dialog { id: _confirmationDialog // anchors.centerIn: parent acceptButton.text: qsTr("Accept") rejectButton.text: qsTr("Cancel") title: qsTr(textField.text+" already exists!") message: qsTr("If you are sure you want to replace the existing file click on Accept, otherwise click on cancel and change the name of the file to something different...") onAccepted: control.done() onRejected: close() } Maui.Page { id: page anchors.fill: parent leftPadding: 0 rightPadding: leftPadding topPadding: leftPadding bottomPadding: leftPadding headBar.implicitHeight: toolBarHeight + space.medium Component { id: _pathBarComponent Maui.PathBar { anchors.fill: parent // colorScheme.backgroundColor: "#fff" // colorScheme.textColor: "#333" // colorScheme.borderColor: Qt.darker(headBarBGColor, 1.4) onPathChanged: browser.openFolder(path) url: browser.currentPath onHomeClicked: browser.openFolder(Maui.FM.homePath()) onPlaceClicked: browser.openFolder(path) } } Component { id: _searchFieldComponent Maui.TextField { anchors.fill: parent placeholderText: qsTr("Search for files... ") onAccepted: browser.openFolder("search://"+text) // onCleared: browser.goBack() onGoBackTriggered: { searchBar = false clear() // browser.goBack() } background: Rectangle { border.color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) radius: radiusV color: Kirigami.Theme.backgroundColor } } } headBar.middleContent: Item { id: _pathBarLoader Layout.fillWidth: true Layout.margins: space.medium height: iconSizes.big Loader { anchors.fill: parent sourceComponent: searchBar ? _searchFieldComponent : _pathBarComponent } } headBar.rightContent: ToolButton { id: searchButton icon.name: "edit-find" onClicked: searchBar = !searchBar checked: searchBar } Kirigami.PageRow { id: pageRow anchors.fill: parent clip: true property int sidebarWidth: Kirigami.Units.gridUnit * (isMobile? 15 : 8) separatorVisible: wideMode initialPage: [sidebar, browser] defaultColumnWidth: sidebarWidth // interactive: currentIndex === 1 Maui.PlacesSidebar { id: sidebar onPlaceClicked: { pageRow.currentIndex = 1 browser.openFolder(path) } list.groups: control.mode === modes.OPEN ? [ Maui.FMList.PLACES_PATH, Maui.FMList.CLOUD_PATH, Maui.FMList.REMOTE_PATH, Maui.FMList.DRIVES_PATH, Maui.FMList.TAGS_PATH] : [Maui.FMList.PLACES_PATH, Maui.FMList.REMOTE_PATH, Maui.FMList.CLOUD_PATH, Maui.FMList.DRIVES_PATH] } Maui.FileBrowser { id: browser previewer.parent: ApplicationWindow.overlay - trackChanges: false selectionMode: control.mode === modes.OPEN - list.onlyDirs: control.onlyDirs - list.filters: control.filters - list.sortBy: control.sortBy - list.filterType: control.filterType + + currentFMList.trackChanges: false + currentFMList.onlyDirs: control.onlyDirs + currentFMList.filters: control.filters + currentFMList.sortBy: control.sortBy + currentFMList.filterType: control.filterType onNewBookmark: { for(var index in paths) sidebar.list.addPlace(paths[index]) } onItemClicked: { switch(control.mode) { case modes.OPEN : { openItem(index) break } case modes.SAVE: { if(Maui.FM.isDir(list.get(index).path)) openItem(index) else textField.text = list.get(index).label break } } } onCurrentPathChanged: { for(var i=0; i < sidebar.count; i++) if(currentPath === sidebar.list.get(i).path) sidebar.currentIndex = i } } } } function show(cb) { if(cb) callback = cb browser.openFolder(initPath ? initPath :browser.currentPath) open() } function closeIt() { browser.clearSelection() close() } function done() { var paths = browser.selectionBar && browser.selectionBar.visible ? browser.selectionBar.selectedPaths : browser.currentPath if(control.mode === modes.SAVE) { if (typeof paths == 'string') { paths = paths + "/" + textField.text }else { for(var i in paths) paths[i] = paths[i] + "/" + textField.text } } if(callback) callback(paths) control.closeIt() } } diff --git a/src/controls/private/BrowserView.qml b/src/controls/private/BrowserView.qml new file mode 100644 index 0000000..5eb3e1a --- /dev/null +++ b/src/controls/private/BrowserView.qml @@ -0,0 +1,299 @@ +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 + +Maui.Page +{ + id: control + + property Maui.FMList currentFMList : null + property alias currentView : viewLoader.item + property int viewType : Maui.FMList.LIST_VIEW + + function setCurrentFMList() + { + console.log("SETTING CURRENT FM LIST") + control.currentFMList = currentView.currentFMList + } + + Loader + { + id: viewLoader + anchors.fill: parent + sourceComponent: switch(control.viewType) + { + case Maui.FMList.ICON_VIEW: return gridViewBrowser + case Maui.FMList.LIST_VIEW: return listViewBrowser + case Maui.FMList.MILLERS_VIEW: return millerViewBrowser + } + + onLoaded: setCurrentFMList() + } + + Component + { + id: listViewBrowser + + + Maui.ListBrowser + { + property alias currentFMList : _listViewFMList + showPreviewThumbnails: modelList.preview + keepEmblemOverlay: selectionMode + rightEmblem: isMobile ? "document-share" : "" + leftEmblem: "list-add" + showDetailsInfo: true + + Maui.FMList + { + id: _listViewFMList + 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 + } + } + + model: Maui.BaseModel + { + id: _browserModel + list: _listViewFMList + } + + section.delegate: Maui.LabelDelegate + { + id: delegate + label: section + labelTxt.font.pointSize: fontSizes.big + + isSection: true + boldLabel: true + height: toolBarHeightAlt + } + } + } + + Component + { + id: gridViewBrowser + + Maui.GridBrowser + { + property alias currentFMList : _gridViewFMList + itemSize : thumbnailsSize + fontSizes.default + keepEmblemOverlay: selectionMode + showPreviewThumbnails: modelList.preview + rightEmblem: isMobile ? "document-share" : "" + leftEmblem: "list-add" + + Maui.FMList + { + id: _gridViewFMList + 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 + } + } + + model: Maui.BaseModel + { + id: _browserModel + list: _gridViewFMList + } + } + } + + Component + { + id: millerViewBrowser + + Item + { + id: _millerControl + property Maui.FMList currentFMList + property int currentIndex + + 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() + + ListView + { + id: _millerColumns + anchors.fill: parent + + orientation: ListView.Horizontal + snapMode: ListView.SnapToItem + + onCurrentItemChanged: + { + _millerControl.currentFMList = currentItem.currentFMList + control.setCurrentFMList() + } + highlightFollowsCurrentItem: true + + Maui.PathList + { + id: _millerList + path: currentPath + } + + model: Maui.BaseModel + { + id: _millerModel + list: _millerList + } + + delegate: ItemDelegate + { + property alias currentFMList : _millersFMList + property int _index : index + + width: Math.min(Kirigami.Units.gridUnit * 22, control.width) + height: parent.height + + background: Rectangle + { + color: "transparent" + } + + ListView.onAdd: _millerColumns.positionViewAtEnd() + Kirigami.Separator + { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + width: 1 + z: 999 + } + + 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 + currentIndex : _millerControl.currentIndex + + onItemClicked: + { + _millerColumns.currentIndex = _index + _millerControl.itemClicked(index) + + console.log(" ITEM CLICKED ", _index, index) + } + + onItemDoubleClicked: + { + _millerColumns.currentIndex = _index + _millerControl.itemDoubleClicked(index) + } + + onItemRightClicked: + { + _millerColumns.currentIndex = _index + _millerControl.itemRightClicked(index) + } + + onRightEmblemClicked: + { + _millerColumns.currentIndex = _index + _millerControl.rightEmblemClicked(index) + } + + onLeftEmblemClicked: + { + _millerColumns.currentIndex = _index + _millerControl.leftEmblemClicked(index) + } + + onAreaClicked: + { + _millerColumns.currentIndex = _index + _millerControl.areaClicked(mouse) + } + + onAreaRightClicked: + { + _millerColumns.currentIndex = _index + _millerControl.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 + } + } + } + } + } + } +} diff --git a/src/fm/fmlist.cpp b/src/fm/fmlist.cpp index 9a9301b..9daf669 100644 --- a/src/fm/fmlist.cpp +++ b/src/fm/fmlist.cpp @@ -1,900 +1,877 @@ /* * * Copyright (C) 2018 camilo higuita * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, 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 General Public License * along with this program. If not, see . */ #include "fmlist.h" #include "fm.h" #include "utils.h" #include #include #include #include #include #include #include FMList::FMList(QObject *parent) : MauiList(parent), fm(new FM(this)), watcher(new QFileSystemWatcher(this)) { connect(this->fm, &FM::cloudServerContentReady, [&](const FMH::MODEL_LIST &list, const QString &url) { if(this->path == url) { this->pre(); this->list = list; this->pathEmpty = this->list.isEmpty(); emit this->pathEmptyChanged(); this->pos(); this->setContentReady(true); } }); connect(this->fm, &FM::trashContentReady, [&](const FMH::MODEL_LIST &list) { if(this->path == "trash://") { this->pre(); this->list = list; this->pathEmpty = this->list.isEmpty(); emit this->pathEmptyChanged(); this->pos(); this->setContentReady(true); } }); connect(this->fm, &FM::pathContentReady, [&](const FMH::PATH_CONTENT &res) { qDebug()<< "PATHCN ONTEN READY" << res.path << this->path << res.content; // if(this->pathType != FMList::PATHTYPE::PLACES_PATH) // return; if(res.path != this->path) return; emit this->preListChanged(); this->list = res.content; this->pathEmpty = this->list.isEmpty() /*&& FM::fileExists(this->path)*/; emit this->pathEmptyChanged(); this->sortList(); emit this->postListChanged(); this->setContentReady(true); }); connect(this->fm, &FM::warningMessage, [&](const QString &message) { emit this->warning(message); }); connect(this->fm, &FM::loadProgress, [&](const int &percent) { emit this->progress(percent); }); // with kio based on android it watches the directory itself, so better relay on that #ifdef Q_OS_ANDROID connect(this->watcher, &QFileSystemWatcher::directoryChanged, [&](const QString &path) { qDebug()<< "FOLDER PATH CHANGED" << path; this->reset(); }); #else connect(this->fm, &FM::pathContentChanged, [&](const QUrl &path) { qDebug()<< "FOLDER PATH CHANGED" << path; if(path.toString() != this->path) return; this->sortList(); }); #endif connect(this->fm, &FM::newItem, [&] (const FMH::MODEL &item, const QString &url) { if(this->path == url) { emit this->preItemAppended(); this->list << item; this->pathEmpty = this->list.isEmpty(); emit this->pathEmptyChanged(); emit this->postListChanged(); } }); connect(this, &FMList::pathChanged, this, &FMList::reset); // connect(this, &FMList::hiddenChanged, this, &FMList::setList); // connect(this, &FMList::onlyDirsChanged, this, &FMList::setList); // connect(this, &FMList::filtersChanged, this, &FMList::setList); const auto value = UTIL::loadSettings("SaveDirProps", "SETTINGS", this->saveDirProps).toBool(); this->setSaveDirProps(value); } FMList::~FMList() {} void FMList::pre() { emit this->preListChanged(); // this->setContentReady(false); } void FMList::pos() { // this->setContentReady(true); emit this->postListChanged(); } void FMList::watchPath(const QString& path, const bool& clear) { #ifdef Q_OS_ANDROID if(!this->watcher->directories().isEmpty() && clear) this->watcher->removePaths(this->watcher->directories()); if(path.isEmpty() || !FMH::fileExists(path)) return; this->watcher->addPath(QString(path).replace("file://", "")); qDebug()<< "WATCHING PATHS" << this->watcher->directories(); #else Q_UNUSED(path) Q_UNUSED(clear) #endif } void FMList::setList() { this->setContentReady(true); switch(this->pathType) { case FMList::PATHTYPE::FISH_PATH: case FMList::PATHTYPE::MTP_PATH: case FMList::PATHTYPE::DRIVES_PATH: case FMList::PATHTYPE::REMOTE_PATH: case FMList::PATHTYPE::PLACES_PATH: this->list.clear(); this->setContentReady(false); this->fm->getPathContent(this->path, this->hidden, this->onlyDirs, this->filters); return; //ASYNC case FMList::PATHTYPE::TRASH_PATH: this->list.clear(); this->setContentReady(false); this->fm->getTrashContent(); break;//ASYNC case FMList::PATHTYPE::SEARCH_PATH: this->list.clear(); this->setContentReady(false); this->search(QString(this->path).right(this->path.length()- 1 - this->path.lastIndexOf("/")), this->searchPath, this->hidden, this->onlyDirs, this->filters); return; //ASYNC case FMList::PATHTYPE::APPS_PATH: this->list = FM::getAppsContent(this->path); break; case FMList::PATHTYPE::TAGS_PATH: this->list = this->fm->getTagContent(QString(this->path).right(this->path.length()- 1 - this->path.lastIndexOf("/"))); break; case FMList::PATHTYPE::CLOUD_PATH: this->list.clear(); if(this->fm->getCloudServerContent(this->path, this->filters, this->cloudDepth)) { this->setContentReady(false); return; }else break; } this->pathEmpty = this->list.isEmpty() && FM::fileExists(this->path); emit this->pathEmptyChanged(); this->sortList(); } void FMList::reset() { this->pre(); switch(this->pathType) { case FMList::PATHTYPE::APPS_PATH: this->hidden = false; this->preview = false; break; case FMList::PATHTYPE::CLOUD_PATH: case FMList::PATHTYPE::SEARCH_PATH: case FMList::PATHTYPE::TAGS_PATH: this->hidden = false; this->preview = true; break; case FMList::PATHTYPE::PLACES_PATH: { if(this->saveDirProps) { auto conf = FMH::dirConf(this->path+"/.directory"); this->hidden = conf[FMH::MODEL_NAME[FMH::MODEL_KEY::HIDDEN]].toBool(); this->preview = conf[FMH::MODEL_NAME[FMH::MODEL_KEY::SHOWTHUMBNAIL]].toBool(); this->foldersFirst = conf[FMH::MODEL_NAME[FMH::MODEL_KEY::FOLDERSFIRST]].toBool(); }else { this->hidden = UTIL::loadSettings("HiddenFilesShown", "SETTINGS", this->hidden).toBool(); this->preview = UTIL::loadSettings("ShowThumbnail", "SETTINGS", this->preview).toBool(); this->foldersFirst = UTIL::loadSettings("FoldersFirst", "SETTINGS", this->foldersFirst).toBool(); } break; } default: break; } if(this->saveDirProps) { auto conf = FMH::dirConf(this->path+"/.directory"); this->sort = static_cast(conf[FMH::MODEL_NAME[FMH::MODEL_KEY::SORTBY]].toInt()); - this->viewType = static_cast(conf[FMH::MODEL_NAME[FMH::MODEL_KEY::VIEWTYPE]].toInt()); }else { this->sort = static_cast(UTIL::loadSettings("SortBy", "SETTINGS", this->sort).toInt()); - this->viewType = static_cast(UTIL::loadSettings("ViewType", "SETTINGS", this->viewType).toInt()); } emit this->sortByChanged(); - emit this->viewTypeChanged(); emit this->hiddenChanged(); emit this->previewChanged(); qDebug()<< "RESETING PATH CONTENTE" << this->path; this->setList(); this->pos(); } FMH::MODEL_LIST FMList::items() const { return this->list; } FMList::SORTBY FMList::getSortBy() const { return this->sort; } void FMList::setSortBy(const FMList::SORTBY &key) { if(this->sort == key) return; this->pre(); this->sort = key; this->sortList(); if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) FMH::setDirConf(this->path+"/.directory", "MAUIFM", "SortBy", this->sort); else UTIL::saveSettings("SortBy", this->sort, "SETTINGS"); emit this->sortByChanged(); this->pos(); } void FMList::sortList() { FMH::MODEL_KEY key = static_cast(this->sort); auto index = 0; if(this->foldersFirst) { qSort(this->list.begin(), this->list.end(), [](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool { Q_UNUSED(e2) const auto key = FMH::MODEL_KEY::MIME; if(e1[key] == "inode/directory") return true; return false; }); for(auto item : this->list) if(item[FMH::MODEL_KEY::MIME] == "inode/directory") index++; else break; qSort(this->list.begin(),this->list.begin() + index, [key](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool { auto role = key; switch(role) { case FMH::MODEL_KEY::SIZE: { if(e1[role].toDouble() > e2[role].toDouble()) return true; break; } case FMH::MODEL_KEY::MODIFIED: case FMH::MODEL_KEY::DATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::LABEL: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } qSort(this->list.begin() + index, this->list.end(), [key](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool { auto role = key; switch(role) { case FMH::MODEL_KEY::MIME: if(e1[role] == "inode/directory") return true; break; case FMH::MODEL_KEY::SIZE: { if(e1[role].toDouble() > e2[role].toDouble()) return true; break; } case FMH::MODEL_KEY::MODIFIED: case FMH::MODEL_KEY::DATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::LABEL: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } QString FMList::getPathName() const { return this->pathName; } QString FMList::getPath() const { return this->path; } void FMList::setPath(const QString &path) { if(this->path == path) return; if(this->pathType == FMList::PATHTYPE::PLACES_PATH) this->searchPath = this->path; this->path = path; this->setPreviousPath(this->path); qDebug()<< "Prev History" << this->prevHistory; const auto __scheme = QUrl(this->path).scheme(); qDebug()<< "CurrentPath" <<__scheme; // if(path.startsWith(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::SEARCH_PATH]+"/")) if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::SEARCH_PATH]) { this->pathExists = true; this->pathType = FMList::PATHTYPE::SEARCH_PATH; this->pathName = "Search"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]) { this->pathExists = true; this->pathType = FMList::PATHTYPE::CLOUD_PATH; this->pathName = "Cloud"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::APPS_PATH]) { this->pathExists = true; this->pathType = FMList::PATHTYPE::APPS_PATH; this->pathName = "Apps"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::TAGS_PATH]) { this->pathExists = true; this->pathType = FMList::PATHTYPE::TAGS_PATH; emit this->pathName = "Tags"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::TRASH_PATH]) { this->pathExists = true; this->pathType = FMList::PATHTYPE::TRASH_PATH; this->pathName = "Trash"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::PLACES_PATH]) { this->watchPath(this->path); this->pathExists = FMH::fileExists(this->path); this->pathType = FMList::PATHTYPE::PLACES_PATH; this->pathName = FMH::getDirInfoModel(this->path)[FMH::MODEL_KEY::LABEL]; emit this->pathExistsChanged(); emit this->pathTypeChanged(); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::MTP_PATH]) { this->pathExists = true; this->pathType = FMList::PATHTYPE::MTP_PATH; this->pathName = "MTP"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::FISH_PATH] ) { this->pathExists = true; this->pathType = FMList::PATHTYPE::FISH_PATH; this->pathName = "Fish"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::REMOTE_PATH] ) { this->pathExists = true; this->pathType = FMList::PATHTYPE::REMOTE_PATH; this->pathName = "Remote"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::DRIVES_PATH] ) { this->pathExists = true; this->pathType = FMList::PATHTYPE::DRIVES_PATH; this->pathName = "Drives"; emit this->pathExistsChanged(); emit this->pathTypeChanged(); } qDebug() << "PATHTYPE IS" << this->pathType << FMH::PATHTYPE_SCHEME[static_cast(this->pathType)]; emit this->pathChanged(); emit this->pathNameChanged(); } FMList::PATHTYPE FMList::getPathType() const { return this->pathType; } QStringList FMList::getFilters() const { return this->filters; } void FMList::setFilters(const QStringList &filters) { if(this->filters == filters) return; this->filters = filters; emit this->filtersChanged(); this->reset(); } FMList::FILTER FMList::getFilterType() const { return this->filterType; } void FMList::setFilterType(const FMList::FILTER &type) { this->filterType = type; this->filters = FMH::FILTER_LIST[static_cast(this->filterType)]; emit this->filtersChanged(); emit this->filterTypeChanged(); this->reset(); } bool FMList::getHidden() const { return this->hidden; } void FMList::setHidden(const bool &state) { if(this->hidden == state) return; this->hidden = state; if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) FMH::setDirConf(this->path+"/.directory", "Settings", "HiddenFilesShown", this->hidden); else UTIL::saveSettings("HiddenFilesShown", this->hidden, "SETTINGS"); emit this->hiddenChanged(); this->reset(); } bool FMList::getPreview() const { return this->preview; } void FMList::setPreview(const bool &state) { if(this->preview == state) return; this->preview = state; if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) FMH::setDirConf(this->path+"/.directory", "MAUIFM", "ShowThumbnail", this->preview); else UTIL::saveSettings("ShowThumbnail", this->preview, "SETTINGS"); emit this->previewChanged(); } bool FMList::getOnlyDirs() const { return this->onlyDirs; } void FMList::setOnlyDirs(const bool &state) { if(this->onlyDirs == state) return; this->onlyDirs = state; emit this->onlyDirsChanged(); this->reset(); } QVariantMap FMList::get(const int &index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); const auto model = this->list.at(index); return FM::toMap(model); } void FMList::refresh() { emit this->pathChanged(); } void FMList::createDir(const QString& name) { if(this->pathType == FMList::PATHTYPE::PLACES_PATH) this->fm->createDir(this->path, name); else if(this->pathType == FMList::PATHTYPE::CLOUD_PATH) { this->fm->createCloudDir(QString(this->path).replace(FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]+"/"+this->fm->sync->getUser(), ""), name); } } void FMList::copyInto(const QVariantList& files) { if(this->pathType == FMList::PATHTYPE::PLACES_PATH || this->pathType == FMList::PATHTYPE::CLOUD_PATH) this->fm->copy(files, this->path); } void FMList::cutInto(const QVariantList& files) { if(this->pathType == FMList::PATHTYPE::PLACES_PATH) this->fm->cut(files, this->path); // else if(this->pathType == FMList::PATHTYPE::CLOUD_PATH) // { // this->fm->createCloudDir(QString(this->path).replace(FMH::PATHTYPE_NAME[FMList::PATHTYPE::CLOUD_PATH]+"/"+this->fm->sync->getUser(), ""), name); // } } void FMList::setDirIcon(const int &index, const QString &iconName) { if(index >= this->list.size() || index < 0) return; const auto path = QUrl(this->list.at(index)[FMH::MODEL_KEY::PATH]); if(!FM::isDir(path)) return; FMH::setDirConf(path.toString()+"/.directory", "Desktop Entry", "Icon", iconName); this->list[index][FMH::MODEL_KEY::ICON] = iconName; emit this->updateModel(index, QVector {FMH::MODEL_KEY::ICON}); } QString FMList::getParentPath() { switch(this->pathType) { case FMList::PATHTYPE::PLACES_PATH: return FM::parentDir(this->path).toString(); default: return this->getPreviousPath(); } } QString FMList::getPosteriorPath() { if(this->postHistory.isEmpty()) return this->path; return this->postHistory.takeAt(this->postHistory.length()-1); } void FMList::setPosteriorPath(const QString& path) { this->postHistory.append(path); } QString FMList::getPreviousPath() { if(this->prevHistory.isEmpty()) return this->path; if(this->prevHistory.length() < 2) return this->prevHistory.at(0); auto post = this->prevHistory.takeAt(this->prevHistory.length()-1); this->setPosteriorPath(post); return this->prevHistory.takeAt(this->prevHistory.length()-1); } void FMList::setPreviousPath(const QString& path) { this->prevHistory.append(path); } bool FMList::getPathEmpty() const { return this->pathEmpty; } bool FMList::getPathExists() const { return this->pathExists; } bool FMList::getTrackChanges() const { return this->trackChanges; } void FMList::setTrackChanges(const bool& value) { if(this->trackChanges == value) return; this->trackChanges = value; emit this->trackChangesChanged(); } bool FMList::getFoldersFirst() const { return this->foldersFirst; } void FMList::setFoldersFirst(const bool &value) { if(this->foldersFirst == value) return; this->pre(); this->foldersFirst = value; if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) FMH::setDirConf(this->path+"/.directory", "MAUIFM", "FoldersFirst", this->foldersFirst); else UTIL::saveSettings("FoldersFirst", this->foldersFirst, "SETTINGS"); emit this->foldersFirstChanged(); this->sortList(); this->pos(); } void FMList::setSaveDirProps(const bool& value) { if(this->saveDirProps == value) return; this->saveDirProps = value; UTIL::saveSettings("SaveDirProps", this->saveDirProps, "SETTINGS"); emit this->saveDirPropsChanged(); } bool FMList::getSaveDirProps() const { return this->saveDirProps; } void FMList::setContentReady(const bool& value) { this->contentReady = value; emit this->contentReadyChanged(); } bool FMList::getContentReady() const { return this->contentReady; } -FMList::VIEW_TYPE FMList::getViewType() const -{ - return this->viewType; -} - -void FMList::setViewType(const FMList::VIEW_TYPE& value) -{ - if(this->viewType == value) - return; - - this->viewType = value; - - if(this->trackChanges && this->saveDirProps) - FMH::setDirConf(this->path+"/.directory", "MAUIFM", "ViewType", this->viewType); - else - UTIL::saveSettings("ViewType", this->viewType, "SETTINGS"); - - emit this->viewTypeChanged(); -} - void FMList::search(const QString& query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) { qDebug()<< "SEARCHING FOR" << query << path; if(!path.isLocalFile()) { qWarning() << "URL recived is not a local file. search" << path; return; } QFutureWatcher *watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, [=]() { if(this->pathType != FMList::PATHTYPE::SEARCH_PATH) return; const auto res = watcher->future().result(); if(res.path != this->searchPath) return; emit this->preListChanged(); this->list = res.content; emit this->postListChanged(); emit this->searchResultReady(); this->pathEmpty = this->list.isEmpty() && FM::fileExists(this->path); emit this->pathEmptyChanged(); this->sortList(); this->setContentReady(true); watcher->deleteLater(); }); QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT { FMH::PATH_CONTENT res; res.path = path.toString(); res.content = FM::search(query, path, hidden, onlyDirs, filters); return res; }); watcher->setFuture(t1); } int FMList::getCloudDepth() const { return this->cloudDepth; } void FMList::setCloudDepth(const int& value) { if(this->cloudDepth == value) return; this->cloudDepth = value; emit this->cloudDepthChanged(); this->reset(); } diff --git a/src/fm/fmlist.h b/src/fm/fmlist.h index ffd8c9f..2cc3128 100644 --- a/src/fm/fmlist.h +++ b/src/fm/fmlist.h @@ -1,250 +1,245 @@ /* * * Copyright (C) 2018 Camilo Higuita * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, 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 General Public License * along with this program. If not, see . */ #ifndef FMLIST_H #define FMLIST_H #include #include "fmh.h" #include "mauilist.h" struct PathContent { QString path; FMH::MODEL_LIST content; }; class FM; class QFileSystemWatcher; class FMList : public MauiList { Q_OBJECT Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged) Q_PROPERTY(QString pathName READ getPathName NOTIFY pathNameChanged) Q_PROPERTY(bool hidden READ getHidden WRITE setHidden NOTIFY hiddenChanged) Q_PROPERTY(bool onlyDirs READ getOnlyDirs WRITE setOnlyDirs NOTIFY onlyDirsChanged) Q_PROPERTY(bool preview READ getPreview WRITE setPreview NOTIFY previewChanged) - Q_PROPERTY(FMList::VIEW_TYPE viewType READ getViewType WRITE setViewType NOTIFY viewTypeChanged) + Q_PROPERTY(int cloudDepth READ getCloudDepth WRITE setCloudDepth NOTIFY cloudDepthChanged) Q_PROPERTY(bool contentReady READ getContentReady NOTIFY contentReadyChanged) Q_PROPERTY(QStringList filters READ getFilters WRITE setFilters NOTIFY filtersChanged) Q_PROPERTY(FMList::FILTER filterType READ getFilterType WRITE setFilterType NOTIFY filterTypeChanged) Q_PROPERTY(FMList::SORTBY sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged) Q_PROPERTY(bool foldersFirst READ getFoldersFirst WRITE setFoldersFirst NOTIFY foldersFirstChanged) Q_PROPERTY(FMList::PATHTYPE pathType READ getPathType NOTIFY pathTypeChanged) Q_PROPERTY(bool trackChanges READ getTrackChanges WRITE setTrackChanges NOTIFY trackChangesChanged) Q_PROPERTY(bool saveDirProps READ getSaveDirProps WRITE setSaveDirProps NOTIFY saveDirPropsChanged) Q_PROPERTY(bool pathExists READ getPathExists NOTIFY pathExistsChanged) Q_PROPERTY(bool pathEmpty READ getPathEmpty NOTIFY pathEmptyChanged) Q_PROPERTY(QString previousPath READ getPreviousPath) Q_PROPERTY(QString posteriorPath READ getPosteriorPath) Q_PROPERTY(QString parentPath READ getParentPath) public: enum SORTBY : uint_fast8_t { SIZE = FMH::MODEL_KEY::SIZE, MODIFIED = FMH::MODEL_KEY::MODIFIED, DATE = FMH::MODEL_KEY::DATE, LABEL = FMH::MODEL_KEY::LABEL, MIME = FMH::MODEL_KEY::MIME, ADDDATE = FMH::MODEL_KEY::MIME, TITLE = FMH::MODEL_KEY::TITLE, PLACE = FMH::MODEL_KEY::PLACE, FORMAT = FMH::MODEL_KEY::FORMAT }; Q_ENUM(SORTBY) enum FILTER : uint_fast8_t { AUDIO = FMH::FILTER_TYPE::AUDIO, VIDEO= FMH::FILTER_TYPE::VIDEO, TEXT = FMH::FILTER_TYPE::TEXT, IMAGE = FMH::FILTER_TYPE::IMAGE, NONE = FMH::FILTER_TYPE::NONE }; Q_ENUM(FILTER) enum PATHTYPE : uint_fast8_t { PLACES_PATH = FMH::PATHTYPE_KEY::PLACES_PATH, FISH_PATH = FMH::PATHTYPE_KEY::FISH_PATH, MTP_PATH = FMH::PATHTYPE_KEY::MTP_PATH, REMOTE_PATH = FMH::PATHTYPE_KEY::REMOTE_PATH, DRIVES_PATH = FMH::PATHTYPE_KEY::DRIVES_PATH, REMOVABLE_PATH = FMH::PATHTYPE_KEY::REMOVABLE_PATH, TAGS_PATH = FMH::PATHTYPE_KEY::TAGS_PATH, APPS_PATH = FMH::PATHTYPE_KEY::APPS_PATH, TRASH_PATH = FMH::PATHTYPE_KEY::TRASH_PATH, SEARCH_PATH = FMH::PATHTYPE_KEY::SEARCH_PATH, CLOUD_PATH = FMH::PATHTYPE_KEY::CLOUD_PATH }; Q_ENUM(PATHTYPE) enum VIEW_TYPE : uint_fast8_t { ICON_VIEW, LIST_VIEW, MILLERS_VIEW }; Q_ENUM(VIEW_TYPE) FMList(QObject *parent = nullptr); ~FMList(); FMH::MODEL_LIST items() const final override; FMList::SORTBY getSortBy() const; void setSortBy(const FMList::SORTBY &key); QString getPath() const; void setPath(const QString &path); QString getPathName() const; FMList::PATHTYPE getPathType() const; QStringList getFilters() const; void setFilters(const QStringList &filters); FMList::FILTER getFilterType() const; void setFilterType(const FMList::FILTER &type); bool getHidden() const; void setHidden(const bool &state); bool getPreview() const; void setPreview(const bool &state); bool getOnlyDirs() const; void setOnlyDirs(const bool &state); QString getParentPath(); QString getPreviousPath(); void setPreviousPath(const QString &path); QString getPosteriorPath(); void setPosteriorPath(const QString &path); bool getPathEmpty() const; bool getPathExists() const; bool getTrackChanges() const; void setTrackChanges(const bool &value); bool getFoldersFirst() const; void setFoldersFirst(const bool &value); bool getSaveDirProps() const; void setSaveDirProps(const bool &value); bool getContentReady() const; void setContentReady(const bool &value); - VIEW_TYPE getViewType() const; - void setViewType(const VIEW_TYPE &value); - int getCloudDepth() const; void setCloudDepth(const int &value); private: FM *fm; QFileSystemWatcher *watcher; void pre(); void pos(); void reset(); void setList(); void sortList(); void watchPath(const QString &path, const bool &clear = true); void search(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); FMH::MODEL_LIST list = {{}}; QString path = QString(); QString pathName = QString(); QStringList filters = {}; bool onlyDirs = false; bool hidden = false; bool preview = false; bool pathExists = false; bool pathEmpty = true; bool trackChanges = true; bool foldersFirst = false; bool saveDirProps = false; bool contentReady = false; int cloudDepth = 1; QString searchPath; - VIEW_TYPE viewType = VIEW_TYPE::ICON_VIEW; FMList::SORTBY sort = FMList::SORTBY::MODIFIED; FMList::FILTER filterType = FMList::FILTER::NONE; FMList::PATHTYPE pathType = FMList::PATHTYPE::PLACES_PATH; QStringList prevHistory = {}; QStringList postHistory = {}; public slots: QVariantMap get(const int &index) const; void refresh(); void createDir(const QString &name); void copyInto(const QVariantList &files); void cutInto(const QVariantList &files); void setDirIcon(const int &index, const QString &iconName); signals: void pathChanged(); void pathNameChanged(); void pathTypeChanged(); void filtersChanged(); void filterTypeChanged(); void hiddenChanged(); void previewChanged(); void onlyDirsChanged(); void sortByChanged(); void trackChangesChanged(); void foldersFirstChanged(); void saveDirPropsChanged(); void contentReadyChanged(); - void viewTypeChanged(); void cloudDepthChanged(); void pathEmptyChanged(); void pathExistsChanged(); void warning(QString message); void progress(int percent); void searchResultReady(); }; #endif // FMLIST_H