diff --git a/assets.qrc b/assets.qrc index 167a020..3775d78 100644 --- a/assets.qrc +++ b/assets.qrc @@ -1,17 +1,21 @@ assets/face-sleeping.png assets/face-sleeping.svg assets/tag.svg assets/maui-app.colors assets/mauikit-logo.png assets/ElectricPlug.png assets/BugSearch.png assets/MoonSki.png assets/application-x-zerosize.svg assets/animat-rocket-color.gif assets/animat-diamond-color.gif assets/animat-search-color.gif assets/opendesktop.png + assets/folder-add.svg + assets/view-refresh.svg + assets/edit-find.svg + assets/dialog-information.svg diff --git a/assets/dialog-information.svg b/assets/dialog-information.svg new file mode 100644 index 0000000..c91ec19 --- /dev/null +++ b/assets/dialog-information.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/assets/edit-find.svg b/assets/edit-find.svg new file mode 100644 index 0000000..89da349 --- /dev/null +++ b/assets/edit-find.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/assets/folder-add.svg b/assets/folder-add.svg new file mode 100644 index 0000000..881d69a --- /dev/null +++ b/assets/folder-add.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/assets/view-refresh.svg b/assets/view-refresh.svg new file mode 100644 index 0000000..5f58744 --- /dev/null +++ b/assets/view-refresh.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/maui-style/TextField.qml b/maui-style/TextField.qml index bc3b3db..4413eae 100755 --- a/maui-style/TextField.qml +++ b/maui-style/TextField.qml @@ -1,88 +1,89 @@ /* * Copyright 2017 Marco Martin * Copyright 2017 The Qt Company Ltd. * * GNU Lesser General Public License Usage * Alternatively, this file may be used under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software * Foundation and appearing in the file LICENSE.LGPLv3 included in the * packaging of this file. Please review the following information to * ensure the GNU Lesser General Public License version 3 requirements * will be met: https://www.gnu.org/licenses/lgpl.html. * * GNU General Public License Usage * Alternatively, this file may be used under the terms of the GNU * General Public License version 2.0 or later as published by the Free * Software Foundation and appearing in the file LICENSE.GPL included in * the packaging of this file. Please review the following information to * ensure the GNU General Public License version 2.0 requirements will be * met: http://www.gnu.org/licenses/gpl-2.0.html. */ import QtQuick 2.6 import QtQuick.Window 2.1 import QtQuick.Controls 2.3 as Controls import QtQuick.Templates 2.3 as T import org.kde.kirigami 2.2 as Kirigami T.TextField { id: controlRoot Kirigami.Theme.colorSet: Kirigami.Theme.View Kirigami.Theme.inherit: false implicitWidth: Math.max(200, placeholderText ? placeholder.implicitWidth + leftPadding + rightPadding : 0) || contentWidth + leftPadding + rightPadding implicitHeight: Math.max(contentHeight + topPadding + bottomPadding, background ? Kirigami.Units.iconSizes.smallMedium : 0, placeholder.implicitHeight + topPadding + bottomPadding) padding: 6 /* color: controlRoot.enabled ? Kirigami.Theme.textColor : Kirigami.Theme.disabledTextColor selectionColor: Kirigami.Theme.highlightColor selectedTextColor: Kirigami.Theme.highlightedTextColor verticalAlignment: TextInput.AlignVCenter*/ //Text.NativeRendering is broken on non integer pixel ratios renderType: Window.devicePixelRatio % 1 !== 0 ? Text.QtRendering : Text.NativeRendering color: enabled ? Kirigami.Theme.textColor : Kirigami.Theme.disabledtextColor selectionColor: Kirigami.Theme.highlightColor selectedTextColor: Kirigami.Theme.highlightedTextColor verticalAlignment: TextInput.AlignVCenter horizontalAlignment: Text.AlignHCenter // cursorDelegate: CursorDelegate { } Controls.Label { id: placeholder x: control.leftPadding y: control.topPadding width: control.width - (control.leftPadding + control.rightPadding) height: control.height - (control.topPadding + control.bottomPadding) text: control.placeholderText font: control.font color: Qt.lighter(Kirigami.Theme.textColor, 1.4) opacity: 0.4 horizontalAlignment: control.horizontalAlignment verticalAlignment: control.verticalAlignment visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight + wrapMode: Text.NoWrap } background: Rectangle { implicitWidth: unit * 120 implicitHeight: Kirigami.Settings.isMobile ? Kirigami.Units.iconSizes.medium : Kirigami.Units.iconSizes.medium color: control.activeFocus ? Qt.lighter(Kirigami.Theme.backgroundColor, 1.4) : (control.hovered ? Qt.lighter(Kirigami.Theme.backgroundColor, 1.3) : 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)) radius: radiusV border.width: unit } } diff --git a/src/controls/FileBrowser.qml b/src/controls/FileBrowser.qml index e5e074c..aa8bb20 100644 --- a/src/controls/FileBrowser.qml +++ b/src/controls/FileBrowser.qml @@ -1,891 +1,1064 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 +import QtQml.Models 2.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: control.currentFMList.trackChanges - property alias saveDirProps: control.currentFMList.saveDirProps + property var trackChanges: control.currentFMList.trackChanges + property var saveDirProps: control.currentFMList.saveDirProps - property string currentPath: Maui.FM.homePath() + property string currentPath + onCurrentPathChanged: control.browserView.path = control.currentPath 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 browser : _browserView.currentView - property alias currentFMList : _browserView.currentFMList + property alias browserView : _browserList.currentItem + property var browser : browserView.currentView + property Maui.FMList 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") - } - + onGoBackTriggered: control.goBack() onGoForwardTriggered: control.goNext() Keys.onSpacePressed: previewer.show(control.currentFMList.get(browser.currentIndex).path) + + footBar.visible: false + footBar.leftContent: Label + { + Layout.fillWidth: true + text: control.currentFMList.count + " " + qsTr("items") + } + + footBar.rightContent: [ + + ToolButton + { + icon.name: "zoom-in" + onClicked: zoomIn() + }, + + ToolButton + { + icon.name: "zoom-out" + onClicked: zoomOut() + } + ] + headBar.visible: currentPathType !== Maui.FMList.APPS_PATH headBar.position: isMobile ? ToolBar.Footer : ToolBar.Header property list t_actions: [ Action { id: _previewAction icon.name: "image-preview" text: qsTr("Previews") checkable: true checked: control.currentFMList.preview onTriggered: control.currentFMList.preview = !control.currentFMList.preview }, Action { id: _hiddenAction icon.name: "visibility" text: qsTr("Hidden files") checkable: true checked: control.currentFMList.hidden onTriggered: control.currentFMList.hidden = !control.currentFMList.hidden }, Action { id: _bookmarkAction icon.name: "bookmark-new" text: qsTr("Bookmark") onTriggered: newBookmark([currentPath]) }, Action { id: _newFolderAction icon.name: "folder-add" text: qsTr("New folder") onTriggered: { dialogLoader.sourceComponent= newFolderDialogComponent dialog.open() } }, Action { id: _newDocumentAction icon.name: "document-new" text: qsTr("New file") onTriggered: { dialogLoader.sourceComponent= newFileDialogComponent dialog.open() } }, Action { id: _pasteAction text: qsTr("Paste ")+"["+browserMenu.pasteFiles+"]" icon.name: "edit-paste" enabled: browserMenu.pasteFiles > 0 onTriggered: paste() - }] + }, + + Action + { + text: qsTr("Status bar") + checkable: false + checked: control.footBar.visible + onTriggered: control.footBar.visible = !control.footBar.visible + } + ] 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: 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]) } 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]) } 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" + "qrc:/assets/folder-add.svg" else if(!control.currentFMList.pathExists) - "qrc:/assets/ElectricPlug.png" + "qrc:/assets/dialog-information.svg" else if(!control.currentFMList.contentReady && currentPathType === Maui.FMList.SEARCH_PATH) - "qrc:/assets/animat-search-color.gif" + "qrc:/assets/edit-find.svg" else if(!control.currentFMList.contentReady) - "qrc:/assets/animat-rocket-color.gif" + "qrc:/assets/view-refresh.svg" - isGif: !control.currentFMList.contentReady - isMask: false +// 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: _browserView.viewType = Maui.FMList.ICON_VIEW + onTriggered: browserView.viewType = Maui.FMList.ICON_VIEW checkable: false - checked: _browserView.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: _browserView.viewType = Maui.FMList.LIST_VIEW + onTriggered: browserView.viewType = Maui.FMList.LIST_VIEW icon.width: iconSizes.medium - checked: _browserView.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: _browserView.viewType = Maui.FMList.MILLERS_VIEW + onTriggered: browserView.viewType = Maui.FMList.MILLERS_VIEW icon.width: iconSizes.medium - checked: _browserView.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: con.foldersFirst onTriggered: control.currentFMList.foldersFirst = !control.currentFMList.foldersFirst } Kirigami.Action { text: qsTr("Type") checked: control.currentFMList.sortBy === Maui.FMList.MIME onTriggered: control.currentFMList.sortBy = Maui.FMList.MIME } Kirigami.Action { text: qsTr("Date") checked: control.currentFMList.sortBy === Maui.FMList.DATE onTriggered: control.currentFMList.sortBy = Maui.FMList.DATE } Kirigami.Action { text: qsTr("Modified") checked: control.currentFMList.sortBy === Maui.FMList.MODIFIED onTriggered: control.currentFMList.sortBy = Maui.FMList.MODIFIED } Kirigami.Action { text: qsTr("Size") checked: control.currentFMList.sortBy === Maui.FMList.SIZE onTriggered: control.currentFMList.sortBy = Maui.FMList.SIZE } Kirigami.Action { text: qsTr("Name") checked: control.currentFMList.sortBy === Maui.FMList.LABEL onTriggered: control.currentFMList.sortBy = Maui.FMList.LABEL } Kirigami.Action { id: groupAction text: qsTr("Group") checked: control.group onTriggered: { control.group = !control.group if(control.group) groupBy() else browser.section.property = "" } } }, - Kirigami.Action - { - text: qsTr("Select") - icon.name: "item-select" - checkable: false - checked: control.selectionMode - onTriggered: control.selectionMode = !control.selectionMode - - } - ] - } + Kirigami.Action + { + text: qsTr("Select") + icon.name: "item-select" + checkable: false + 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() } } } } } + ObjectModel { id: tabsObjectModel } + ColumnLayout { anchors.fill: parent visible: !holder.visible - z: holder.z + 1 spacing: 0 - BrowserView + TabBar { - id: _browserView - z: holder.z + 1 - Layout.topMargin: _browserView.viewType == Maui.FMList.ICON_VIEW ? contentMargins * 2 : 0 - Layout.margins: 0 - Layout.fillWidth: true - Layout.fillHeight: true - } + id: tabsBar + visible: _browserList.count > 1 + Layout.fillWidth: true + Layout.preferredHeight: visible ? Maui.Style.rowHeight : 0 + Kirigami.Theme.colorSet: Kirigami.Theme.View + Kirigami.Theme.inherit: false + + currentIndex : _browserList.currentIndex + clip: true + + ListModel { id: tabsListModel } + + background: Rectangle + { + color: "transparent" + } + + Repeater + { + id: _repeater + model: tabsListModel + + TabButton + { + id: _tabButton + readonly property int minTabWidth: 150 * unit + implicitWidth: control.width / _repeater.count + implicitHeight: Maui.Style.rowHeight + checked: index === _browserList.currentIndex + + onClicked: _browserList.currentIndex = index + background: Rectangle + { + color: checked ? Kirigami.Theme.focusColor : Kirigami.Theme.backgroundColor + opacity: checked ? 0.4 : 1 + + Kirigami.Separator + { + color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) + z: tabsBar.z + 1 + width : 1 + // visible: tabsListModel.count > 1 + anchors + { + bottom: parent.bottom + top: parent.top + right: parent.right + } + } + } + + contentItem: RowLayout + { + spacing: 0 + + Label + { + text: tabsObjectModel.get(index).currentFMList.pathName + font.pointSize: fontSizes.default + Layout.fillWidth: true + Layout.fillHeight: true + Layout.margins: space.small + Layout.alignment: Qt.AlignCenter + verticalAlignment: Qt.AlignVCenter + horizontalAlignment: Qt.AlignHCenter + color: Kirigami.Theme.textColor + wrapMode: Text.NoWrap + elide: Text.ElideRight + } + + ToolButton + { + Layout.preferredHeight: iconSizes.medium + Layout.preferredWidth: iconSizes.medium + icon.height: iconSizes.medium + icon.width: iconSizes.width + Layout.margins: space.medium + Layout.alignment: Qt.AlignRight + + icon.name: "dialog-close" + + onClicked: + { + var removedIndex = index + tabsObjectModel.remove(removedIndex) + tabsListModel.remove(removedIndex) + } + } + } + } + } + } + + + Kirigami.Separator + { + visible: tabsBar.visible + color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) + Layout.fillWidth: true + Layout.preferredHeight: 1 + } + + ListView + { + id: _browserList + Layout.topMargin: browserView.viewType == Maui.FMList.ICON_VIEW ? contentMargins * 2 : 0 + Layout.margins: 0 + Layout.fillWidth: true + Layout.fillHeight: true + z: holder.z + 1 + orientation: ListView.Horizontal + model: tabsObjectModel + snapMode: ListView.SnapOneItem + spacing: 0 + interactive: isMobile && tabsObjectModel.count > 1 + highlightFollowsCurrentItem: true + highlightMoveDuration: 0 + onMovementEnded: _browserList.currentIndex = indexAt(contentX, contentY) + } Loader { id: selectionBarLoader Layout.fillWidth: true Layout.preferredHeight: control.selectionBar && control.selectionBar.visible ? control.selectionBar.barHeight: 0 Layout.leftMargin: 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 } } + Component.onCompleted: openTab(Maui.FM.homePath()) + onThumbnailsSizeChanged: { if(trackChanges && saveDirProps) Maui.FM.setDirConf(currentPath+"/.directory", "MAUIFM", "IconSize", thumbnailsSize) else Maui.FM.saveSettings("IconSize", thumbnailsSize, "SETTINGS") - if(_browserView.viewType == Maui.FMList.ICON_VIEW) + if(browserView.viewType == Maui.FMList.ICON_VIEW) browser.adaptGrid() } + function openTab(path) + { + var component = Qt.createComponent("private/BrowserView.qml"); + if (component.status === Component.Ready) + { + var object = component.createObject(tabsObjectModel); + tabsObjectModel.append(object); + } + + tabsListModel.append({ + title: qsTr("Untitled"), + path: path, + }) + + _browserList.currentIndex = tabsObjectModel.count - 1 + + if(path && Maui.FM.fileExists(path)) + { + setTabMetadata(path) + openFolder(path) + } + } + + function setTabMetadata(filepath) + { + tabsListModel.setProperty(tabsBar.currentIndex, "path", filepath) + } + + function shareFiles(urls) { if(urls.length <= 0) return; if(isAndroid) Maui.Android.shareDialog(urls[0]) else { dialogLoader.sourceComponent= shareDialogComponent dialog.show(urls) } } function openItem(index) { var item = control.currentFMList.get(index) - var path = item.path + var path = item.path + + console.log("trying to open 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 + control.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(_browserView.viewType == Maui.FMList.ICON_VIEW) + if(browserView.viewType == Maui.FMList.ICON_VIEW) browser.adaptGrid() } function goBack() { populate(control.currentFMList.previousPath) browser.currentIndex = indexHistory.pop() } function goNext() { openFolder(control.currentFMList.posteriorPath) } function goUp() { 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(control.currentFMList.sortBy) { case Maui.FMList.LABEL: prop = "label" criteria = ViewSection.FirstCharacter break; case Maui.FMList.MIME: prop = "mime" break; case Maui.FMList.SIZE: prop = "size" break; case Maui.FMList.DATE: prop = "date" break; case Maui.FMList.MODIFIED: prop = "modified" break; } - _browserView.viewType = Maui.FMList.LIST_VIEW + 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/Holder.qml b/src/controls/Holder.qml index de9ddea..93d7515 100644 --- a/src/controls/Holder.qml +++ b/src/controls/Holder.qml @@ -1,141 +1,131 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.7 as Kirigami import "private" Item { id: control anchors.fill: parent - + visible: false + property string emoji property string message property string title property string body property bool isMask : true property bool isGif : false property int emojiSize : iconSizes.large property bool enabled: true signal actionTriggered() clip: true focus: true - + Component { id: imgComponent Image { id: imageHolder width: Math.min(parent.width, emojiSize) height: width sourceSize.width: width sourceSize.height: height source: emoji asynchronous: true horizontalAlignment: Qt.AlignHCenter fillMode: Image.PreserveAspectFit HueSaturation { anchors.fill: parent source: parent saturation: -1 lightness: 0.3 visible: isMask } } } Component { id: animComponent AnimatedImage { id: animation; source: emoji } } MouseArea { id: _mouseArea anchors.fill: parent enabled: control.enabled onClicked: actionTriggered() hoverEnabled: true } - Item + Column { - anchors.centerIn: parent - height: loader.height + textHolder.implicitHeight - width: Math.min(500, control.width) + anchors.centerIn: parent + Loader { id: loader height: control.emoji ? emojiSize : 0 - width: height - sourceComponent: control.emoji ? (isGif ? animComponent : imgComponent) : undefined - anchors - { - bottom: textHolder.top - horizontalCenter: parent.horizontalCenter - } + width: height + anchors.horizontalCenter: parent.horizontalCenter + sourceComponent: control.emoji ? (isGif ? animComponent : imgComponent) : undefined } Label { id: textHolder - width: parent.width + width: Math.min(control.width * 0.7, implicitWidth) opacity: 0.5 text: message ? qsTr(message) : "

"+title+"

"+body+"

" font.pointSize: fontSizes.default padding: space.medium font.bold: true textFormat: Text.RichText horizontalAlignment: Qt.AlignHCenter elide: Text.ElideRight color: _mouseArea.hovered ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor - wrapMode: Text.Wrap - - anchors - { - top: loader.bottom - horizontalCenter: parent.horizontalCenter - } + wrapMode: Text.Wrap } } } diff --git a/src/controls/IconDelegate.qml b/src/controls/IconDelegate.qml index f1e6776..9543244 100644 --- a/src/controls/IconDelegate.qml +++ b/src/controls/IconDelegate.qml @@ -1,345 +1,344 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtGraphicalEffects 1.0 import "private" ItemDelegate { id: control property bool isDetails : false property bool showDetailsInfo: false property int folderSize : iconSize property int emblemSize: iconSizes.medium property bool isHovered : hovered property bool showLabel : true property bool showEmblem : false property bool showSelectionBackground : true property bool showTooltip : false property bool showThumbnails : false property bool emblemAdded : false property bool keepEmblemOverlay : false property bool isCurrentListItem : ListView.isCurrentItem property color labelColor : (isCurrentListItem || GridView.isCurrentItem || (keepEmblemOverlay && emblemAdded)) && !hovered && showSelectionBackground ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor property color hightlightedColor : GridView.isCurrentItem || hovered || (keepEmblemOverlay && emblemAdded) ? Kirigami.Theme.highlightColor : "transparent" property string rightEmblem property string leftEmblem : "list-add" signal rightClicked() signal emblemClicked(int index) signal rightEmblemClicked(int index) signal leftEmblemClicked(int index) focus: true clip: true hoverEnabled: !isMobile background: Rectangle { color: !isDetails? "transparent" : (isCurrentListItem || (hovered && isDetails) ? Kirigami.Theme.highlightColor : index % 2 === 0 ? Qt.lighter( Kirigami.Theme.backgroundColor,1.2) : Kirigami.Theme.backgroundColor) opacity: hovered ? 0.3 : 1 } // Drag.active: _mouseArea.drag.active // Drag.dragType: Drag.Automatic // Drag.supportedActions: Qt.CopyAction // Drag.mimeData: // { // "text/uri-list": model.path // } MouseArea { id: _mouseArea anchors.fill: parent acceptedButtons: Qt.RightButton // drag.target: parent onClicked: { if(!isMobile && mouse.button === Qt.RightButton) rightClicked() } // onPressed: parent.grabToImage(function(result) // { // parent.Drag.imageSource = result.url // }) } Maui.Badge { id: leftEmblemIcon iconName: leftEmblem visible: (isHovered || keepEmblemOverlay) && showEmblem && leftEmblem z: 999 anchors.top: parent.top anchors.left: parent.left onClicked: leftEmblemClicked(index) // Component.onCompleted: leftEmblemIcon.item.isMask = false size: iconSizes.small Kirigami.Theme.backgroundColor: Kirigami.Theme.highlightColor Kirigami.Theme.textColor: Kirigami.Theme.highlightedTextColor } Maui.Badge { id: rightEmblemIcon iconName: rightEmblem visible: (isHovered || keepEmblemOverlay) && showEmblem && rightEmblem z: 999 size: iconSizes.medium anchors.top: parent.top anchors.right: parent.right onClicked: rightEmblemClicked(index) Kirigami.Theme.backgroundColor: Kirigami.Theme.highlightColor } Component { id: imgComponent Item { anchors.fill: parent Image { id: img clip: true anchors.centerIn: parent source: model.thumbnail ? model.thumbnail : undefined height: Math.min(folderSize, sourceSize.height) width: isDetails ? folderSize : Math.min(control.width * 0.9, sourceSize.width) // sourceSize.width: width // sourceSize.height: height horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter fillMode: Image.PreserveAspectCrop cache: false asynchronous: true layer.enabled: true layer.effect: OpacityMask { maskSource: Item { width: img.width height: img.height Rectangle { anchors.centerIn: parent width: img.width height: img.height radius: radiusV } } } } Loader { anchors.centerIn: parent sourceComponent: img.status === Image.Ready ? undefined : iconComponent } } } Component { id: iconComponent Kirigami.Icon { source: model.icon fallback: "qrc:/assets/application-x-zerosize.svg" - isMask: folderSize <= iconSizes.medium height: folderSize - width: folderSize + width: height } } Component { id: labelComponent Item { anchors.fill: parent Label { id: label text: model.label width: parent.width height: parent.height horizontalAlignment: isDetails? Qt.AlignLeft : Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter elide: Qt.ElideRight wrapMode: Text.Wrap font.pointSize: fontSizes.default color: labelColor Rectangle { visible: parent.visible && showSelectionBackground && !isDetails anchors.fill: parent z: -1 radius: radiusV color: hightlightedColor opacity: hovered ? 0.25 : 0.5 } } } } Component { id: detailsComponent RowLayout { anchors.fill: parent ColumnLayout { Layout.fillHeight: true Layout.fillWidth: false Layout.maximumWidth: 80 Layout.minimumWidth: 80 Layout.preferredWidth: 80 Layout.alignment: Qt.AlignRight Label { Layout.alignment: Qt.AlignRight Layout.fillWidth: true Layout.fillHeight: true horizontalAlignment: Qt.AlignRight verticalAlignment: Qt.AlignBottom elide: Qt.ElideRight wrapMode: Text.Wrap font.pointSize: fontSizes.small color: labelColor opacity: isCurrentListItem ? 1 : 0.5 text: model.mime === "inode/directory" ? (model.count ? model.count + qsTr(" items") : "") : Maui.FM.formatSize(model.size) } Label { Layout.alignment: Qt.AlignRight Layout.fillWidth: true Layout.fillHeight: true text: Maui.FM.formatDate(model.modified, "MM/dd/yyyy") horizontalAlignment: Qt.AlignRight verticalAlignment: Qt.AlignTop elide: Qt.ElideRight wrapMode: Text.Wrap font.pointSize: fontSizes.small color: labelColor opacity: isCurrentListItem ? 1 : 0.5 } } } } GridLayout { id: delegatelayout anchors.fill: parent rows: isDetails ? 1 : 2 columns: isDetails && showDetailsInfo ? 3 : (isDetails && !showDetailsInfo ? 2 : 1) rowSpacing: space.tiny columnSpacing: space.tiny Item { Layout.fillHeight: true Layout.fillWidth: true Layout.maximumWidth: folderSize Layout.row: 1 Layout.column: 1 Layout.alignment: Qt.AlignCenter Layout.leftMargin: isDetails ? space.medium : 0 Loader { id: loader anchors.centerIn: parent sourceComponent: model.mime ? (model.mime.indexOf("image") > -1 && showThumbnails ? imgComponent : iconComponent) : iconComponent } ToolTip.delay: 1000 ToolTip.timeout: 5000 ToolTip.visible: hovered && showTooltip ToolTip.text: model.tooltip ? model.tooltip : model.path } Loader { id: labelLoader Layout.fillWidth: true Layout.maximumHeight: (isDetails ? parent.height : fontSizes.default * 5) Layout.minimumHeight: (isDetails ? parent.height : control.height - folderSize - space.tiny) Layout.preferredHeight: (isDetails ? parent.height : control.height - folderSize - space.tiny) Layout.row: isDetails ? 1 : 2 Layout.column: isDetails ? 2 : 1 Layout.leftMargin: isDetails ? space.medium : 0 sourceComponent: model.label && model.label.length && showLabel? labelComponent : undefined } Loader { id: detailsInfoLoader sourceComponent: isDetails && showDetailsInfo ? detailsComponent : undefined Layout.fillWidth: isDetails && showDetailsInfo Layout.maximumHeight: ( isDetails && showDetailsInfo ? parent.height : fontSizes.default * 5) Layout.minimumHeight: ( isDetails && showDetailsInfo ? parent.height : control.height - folderSize - space.tiny) Layout.preferredHeight: ( isDetails && showDetailsInfo ? parent.height : control.height - folderSize - space.tiny) Layout.maximumWidth: control.width * (isMobile ? 0.5 : 0.3) Layout.row: isDetails && showDetailsInfo ? 1 : 2 Layout.column: isDetails && showDetailsInfo ? 3 : 0 Layout.rightMargin: space.medium // Layout.leftMargin: isDetails ? space.medium : 0 } } } diff --git a/src/controls/ListBrowser.qml b/src/controls/ListBrowser.qml index c0c0ce5..3a1f6d5 100644 --- a/src/controls/ListBrowser.qml +++ b/src/controls/ListBrowser.qml @@ -1,159 +1,155 @@ /* * 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 ScrollView { id: control property int itemSize : iconSizes.big property bool showEmblem : true property bool keepEmblemOverlay : false property string rightEmblem property string leftEmblem property bool showDetailsInfo : false property bool showPreviewThumbnails: true property alias model : _listView.model property alias delegate : _listView.delegate property alias section : _listView.section property alias contentY: _listView.contentY property alias currentIndex : _listView.currentIndex property alias currentItem : _listView.currentItem property alias count : _listView.count property alias cacheBuffer : _listView.cacheBuffer property alias topMargin: _listView.topMargin property alias bottomMargin: _listView.bottomMargin property alias rightMargin: _listView.rightMargin property alias leftMarging: _listView.leftMargin property alias header : _listView.header property alias listView: _listView 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() padding: 0 spacing: 0 ListView - { - anchors.fill: parent + { id: _listView - // maximumFlickVelocity: 400 + anchors.fill: parent snapMode: ListView.SnapToItem boundsBehavior: !isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds keyNavigationEnabled: true - clip: true - focus: true - interactive: true + interactive: isMobile highlightFollowsCurrentItem: true highlightMoveDuration: 0 width: parent.width - height: parent.height - + height: parent.height model: ListModel { id: listModel } delegate: Maui.IconDelegate { id: delegate isDetails: true width: parent.width height: itemSize + space.big showDetailsInfo: control.showDetailsInfo folderSize : itemSize showTooltip: true showEmblem: control.showEmblem keepEmblemOverlay : control.keepEmblemOverlay showThumbnails: showPreviewThumbnails rightEmblem: control.rightEmblem leftEmblem: control.leftEmblem opacity: (model.name).startsWith(".") ? 0.5 : 1 Connections { target: delegate onClicked: { control.currentIndex = index control.itemClicked(index) } onDoubleClicked: { control.currentIndex = index control.itemDoubleClicked(index) } onPressAndHold: { control.currentIndex = index control.itemRightClicked(index) } onRightClicked: { control.currentIndex = index control.itemRightClicked(index) } onRightEmblemClicked: { control.currentIndex = index control.rightEmblemClicked(index) } onLeftEmblemClicked: { control.currentIndex = index control.leftEmblemClicked(index) } } } MouseArea { anchors.fill: parent z: -1 acceptedButtons: Qt.RightButton | Qt.LeftButton onClicked: control.areaClicked(mouse) onPressAndHold: control.areaRightClicked() } } } diff --git a/src/controls/TagsDialog.qml b/src/controls/TagsDialog.qml index 87d7b74..689c734 100644 --- a/src/controls/TagsDialog.qml +++ b/src/controls/TagsDialog.qml @@ -1,196 +1,197 @@ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import TagsModel 1.0 import TagsList 1.0 Maui.Dialog { property var urls : [] property alias taglist :_tagsList property alias listView: _listView property alias composerList: tagListComposer.list signal tagsReady(var tags) defaultButtons: true maxHeight: unit * 500 + page.padding: Maui.Style.space.medium onAccepted: setTags() onRejected: close() headBar.plegable: false headBar.leftContent: ToolButton { icon.name: "view-sort" - text: qsTr("Sort by...") +// text: qsTr("Sort by...") onClicked: sortMenu.popup() Menu { id: sortMenu MenuItem { text: qsTr("Name") checkable: true checked: _tagsList.sortBy === TagsList.TAG onTriggered: _tagsList.sortBy = TagsList.TAG } MenuItem { text: qsTr("Date") checkable: true checked: _tagsList.sortBy === TagsList.ADD_DATE onTriggered: _tagsList.sortBy = TagsList.ADD_DATE } } } headBar.middleContent: Maui.TextField { id: tagText - width: headBar.middleLayout.width * 0.9 + Layout.fillWidth: true placeholderText: qsTr("New tags...") onAccepted: { var tags = tagText.text.split(",") for(var i in tags) { var myTag = tags[i].trim() _tagsList.insert(myTag) tagListComposer.list.append(myTag) } clear() } } headBar.rightContent: ToolButton { icon.name: "view-refresh" // text: qsTr("Refresh...") onClicked: taglist.refresh() } ColumnLayout { anchors.fill: parent Item { Layout.fillHeight: true Layout.fillWidth: true ListView { id: _listView clip: true anchors.fill: parent signal tagClicked(int index) focus: true interactive: true highlightFollowsCurrentItem: true highlightMoveDuration: 0 TagsModel { id: _tagsModel list: _tagsList } TagsList { id: _tagsList } Maui.Holder { id: holder emoji: "qrc:/img/assets/Electricity.png" visible: _listView.count === 0 isMask: false title : "No tags!" body: "Start tagging your pics" emojiSize: iconSizes.huge } model: _tagsModel delegate: Maui.ListDelegate { id: delegate label: tag radius: radiusV Connections { target: delegate onClicked: { _listView.currentIndex = index tagListComposer.list.append(_tagsList.get(index).tag) } } } } } Maui.TagList { id: tagListComposer Layout.fillWidth: true Layout.leftMargin: contentMargins Layout.rightMargin: contentMargins height: 64 width: parent.width onTagRemoved: list.remove(index) placeholderText: "" } } function setTags() { var tags = [] for(var i = 0; i < tagListComposer.count; i++) tags.push(tagListComposer.list.get(i).tag) tagsReady(tags) close() } // function show(urls) // { // control.urls = urls // tagListComposer.list.urls = picUrls // // open() // } // // // function addTagsToPic(urls, tags) // { // if(tags.length < 1) // return // // for(var j in urls) // { // var url = urls[j] // // if(!dba.checkExistance("images", "url", url)) // if(!dba.addPic(url)) // return // // for(var i in tags) // if(PIX.addTagToPic(tags[i], url)) // picTagged(tags[i], url) // // } // close() // } } diff --git a/src/controls/TextField.qml b/src/controls/TextField.qml index e366c58..b703a2c 100644 --- a/src/controls/TextField.qml +++ b/src/controls/TextField.qml @@ -1,150 +1,149 @@ /* * 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.Layouts 1.3 import QtQuick.Controls 2.2 import QtQuick.Controls.Material 2.1 import org.kde.kirigami 2.2 as Kirigami import QtQuick.Controls.impl 2.3 import QtQuick.Controls.Material.impl 2.3 import org.kde.mauikit 1.0 as Maui import "private" TextField { id: control property alias menu : entryMenu signal cleared() signal goBackTriggered(); signal goFowardTriggered(); // height: implicitHeight // width: implicitWidth z: 1 // topPadding: space.tiny bottomPadding: space.tiny rightPadding: clearButton.width + space.small selectByMouse: !isMobile persistentSelection: true focus: true - wrapMode: TextInput.WordWrap - + wrapMode: TextInput.WordWrap onPressAndHold: !isMobile ? entryMenu.popup() : undefined onPressed: { if(!isMobile && event.button === Qt.RightButton) entryMenu.popup() } Keys.onBackPressed: { goBackTriggered(); event.accepted = true } Shortcut { sequence: "Forward" onActivated: goFowardTriggered(); } Shortcut { sequence: StandardKey.Forward onActivated: goFowardTriggered(); } Shortcut { sequence: StandardKey.Back onActivated: goBackTriggered(); } ToolButton { id: clearButton visible: control.text.length anchors.top: control.top anchors.right: control.right anchors.rightMargin: space.small anchors.verticalCenter: parent.verticalCenter icon.name: "edit-clear" icon.color: control.color onClicked: { control.clear() cleared() } } Menu { id: entryMenu z: control.z +1 MenuItem { text: qsTr("Copy") onTriggered: control.copy() enabled: control.selectedText.length } MenuItem { text: qsTr("Cut") onTriggered: control.cut() enabled: control.selectedText.length } MenuItem { text: qsTr("Paste") onTriggered: { var text = control.paste() control.insert(control.cursorPosition, text) } } MenuItem { text: qsTr("Select all") onTriggered: control.selectAll() enabled: control.text.length } MenuItem { text: qsTr("Undo") onTriggered: control.undo() enabled: control.canUndo } MenuItem { text: qsTr("Redo") onTriggered: control.redo() enabled: control.canRedo } } } diff --git a/src/controls/private/BrowserMenu.qml b/src/controls/private/BrowserMenu.qml index 4e61959..27dff94 100644 --- a/src/controls/private/BrowserMenu.qml +++ b/src/controls/private/BrowserMenu.qml @@ -1,68 +1,68 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.6 as Kirigami Menu { property int pasteFiles : 0 // popup.z : 999 /* Maui.MenuItem * { * che * ckable: true * checked: saveDirProps * text: qsTr("Per dir props") * onTriggered: saveDirProps = !saveDirProps }*/ // property list actions: t_actions MenuItem { action: _previewAction } MenuItem { action: _hiddenAction } MenuItem { action: _bookmarkAction } MenuItem { action: _newFolderAction } MenuItem { action: _newDocumentAction } MenuItem { action: _pasteAction - } + } function show() { if(currentPathType === Maui.FMList.PLACES_PATH || currentPathType === Maui.FMList.TAGS_PATH || currentPathType === Maui.FMList.CLOUD_PATH) { if(isCopy) pasteFiles = copyItems.length else if(isCut) pasteFiles = cutItems.length popup() } } } diff --git a/src/controls/private/BrowserView.qml b/src/controls/private/BrowserView.qml index 5eb3e1a..db19143 100644 --- a/src/controls/private/BrowserView.qml +++ b/src/controls/private/BrowserView.qml @@ -1,299 +1,290 @@ 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 string path property Maui.FMList currentFMList : null property alias currentView : viewLoader.item - property int viewType : Maui.FMList.LIST_VIEW + property int viewType : Maui.FM.loadSettings("VIEW_TYPE", "BROWSER", Maui.FMList.LIST_VIEW) + + onViewTypeChanged: Maui.FM.saveSettings("VIEW_TYPE", viewType, "BROWSER") + + height: _browserList.height + width: _browserList.width + 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 + Maui.FMList { - id: listViewBrowser + id: _commonFMList + preview: true + path: control.path + 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 + } + } + + Component + { + id: listViewBrowser Maui.ListBrowser { - property alias currentFMList : _listViewFMList - showPreviewThumbnails: modelList.preview + property alias currentFMList : _browserModel.list + showPreviewThumbnails: _listViewFMList.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 - } - } + showDetailsInfo: true model: Maui.BaseModel { id: _browserModel - list: _listViewFMList + list: _commonFMList } 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 + property alias currentFMList : _browserModel.list itemSize : thumbnailsSize + fontSizes.default keepEmblemOverlay: selectionMode - showPreviewThumbnails: modelList.preview + showPreviewThumbnails: _gridViewFMList.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 - } - } + leftEmblem: "list-add" model: Maui.BaseModel { id: _browserModel - list: _gridViewFMList + list: _commonFMList } } } 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 + boundsBehavior: !isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds + + keyNavigationEnabled: true + interactive: Kirigami.Settings.isMobile + highlightFollowsCurrentItem: true + orientation: ListView.Horizontal snapMode: ListView.SnapToItem + ScrollBar.horizontal: ScrollBar { } + onCurrentItemChanged: { _millerControl.currentFMList = currentItem.currentFMList control.setCurrentFMList() } - highlightFollowsCurrentItem: true Maui.PathList { id: _millerList - path: currentPath + path: control.path } 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() + ListView.onAdd: _millerColumns.currentIndex = _millerColumns.count-1 + 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 + preview: true path: model.path - foldersFirst: modelList.foldersFirst + foldersFirst: true 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 + showPreviewThumbnails: _millersFMList.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) + _millerControl.itemClicked(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/controls/private/FileMenu.qml b/src/controls/private/FileMenu.qml index 753f773..557d97d 100644 --- a/src/controls/private/FileMenu.qml +++ b/src/controls/private/FileMenu.qml @@ -1,151 +1,159 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.2 as Kirigami Menu { id: control implicitWidth: colorBar.implicitWidth + space.big property var item : ({}) property int index : -1 property bool isDir : false signal bookmarkClicked(var item) signal removeClicked(var item) signal shareClicked(var item) signal copyClicked(var item) signal cutClicked(var item) signal renameClicked(var item) signal tagsClicked(var item) MenuItem { text: qsTr("Select") onTriggered: { addToSelection(currentFMList.get(index)) } } + MenuSeparator{} + + MenuItem + { + visible: isDir + text: qsTr("Open in tab") + onTriggered: openTab(item.path) + } MenuSeparator{} MenuItem { text: qsTr("Copy...") onTriggered: { copyClicked(control.item) close() } } MenuItem { text: qsTr("Cut...") onTriggered: { cutClicked(control.item) close() } } MenuItem { text: qsTr("Rename...") onTriggered: { renameClicked(control.item) close() } } MenuSeparator{} MenuItem { text: qsTr("Bookmark") enabled: isDir onTriggered: { bookmarkClicked(control.item) close() } } MenuItem { text: qsTr("Tags...") onTriggered: { tagsClicked(control.item) close() } } MenuItem { text: qsTr("Share...") onTriggered: { shareClicked(control.item) close() } } MenuItem { text: qsTr("Preview...") onTriggered: { previewer.show(control.item.path) close() } } MenuSeparator{} MenuItem { text: qsTr("Remove...") Kirigami.Theme.textColor: dangerColor onTriggered: { removeClicked(control.item) close() } } MenuSeparator{ visible: colorBar.visible } MenuItem { width: parent.width height: visible ? iconSize + space.big : 0 visible: isDir Maui.ColorsBar { id: colorBar visible: parent.visible anchors.centerIn: parent size: iconSize onColorPicked: currentFMList.setDirIcon(index, color) } } function show(index) { control.item = currentFMList.get(index) if(item) { control.index = index isDir = Maui.FM.isDir(item.path) popup() } } } diff --git a/src/fm/fm.h b/src/fm/fm.h index 9f569b9..17cafe2 100644 --- a/src/fm/fm.h +++ b/src/fm/fm.h @@ -1,156 +1,156 @@ #ifndef FM_H #define FM_H #include #include #include #include #include #include #include "fmdb.h" #include "fmh.h" #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) class KCoreDirLister; #endif class Syncing; class Tagging; #ifdef STATIC_MAUIKIT class FM : public FMDB #else class MAUIKIT_EXPORT FM : public FMDB #endif { Q_OBJECT public: // static FM *getInstance(); Syncing *sync; FM(QObject *parent = nullptr); ~FM(); FMH::MODEL_LIST getTags(const int &limit = 5); FMH::MODEL_LIST getTagContent(const QString &tag); // FMH::MODEL_LIST getBookmarks(); /** Syncing **/ bool getCloudServerContent(const QString &server, const QStringList &filters= QStringList(), const int &depth = 0); FMH::MODEL_LIST getCloudAccounts(); Q_INVOKABLE void createCloudDir(const QString &path, const QString &name); void getTrashContent(); /*** START STATIC METHODS ***/ static FMH::MODEL_LIST search(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); // static FMH::MODEL_LIST getDevices(); static FMH::MODEL_LIST getDefaultPaths(); static FMH::MODEL_LIST getAppsPath(); static FMH::MODEL_LIST packItems(const QStringList &items, const QString &type); void getPathContent(const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags); // static FMH::MODEL_LIST getPathContent(const QString &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags); static FMH::MODEL_LIST getAppsContent(const QString &path); static bool copyPath(QUrl sourceDir, QUrl destinationDir, bool overWriteDirectory); static bool removeDir(const QUrl &path); static QString resolveUserCloudCachePath(const QString &server, const QString &user); QString resolveLocalCloudPath(const QString &path); /** * only keeping this two for legacy. shoudl be removed soon * and instead use FMH::toMap, FMH::toModel, FMH::filterModel **/ static QVariantMap toMap(const FMH::MODEL &model); - static FMH::MODEL toModel(const QVariantMap &map); + static FMH::MODEL toModel(const QVariantMap &map); /*** END STATIC METHODS ***/ private: Tagging *tag; #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) KCoreDirLister *dirLister; #endif // static FM* instance; QVariantList get(const QString &queryTxt); signals: void cloudAccountInserted(QString user); void cloudAccountRemoved(QString user); void cloudServerContentReady(FMH::MODEL_LIST list, const QString &url); void cloudItemReady(FMH::MODEL item, QString path); //when a item is downloaded and ready void trashContentReady(FMH::MODEL_LIST list); void pathContentReady(FMH::PATH_CONTENT list); void pathContentChanged(QUrl path); void warningMessage(QString message); void loadProgress(int percent); void dirCreated(FMH::MODEL dir); void newItem(FMH::MODEL item, QString path); // when a new item is created public slots: QVariantList getCloudAccountsList(); bool addCloudAccount(const QString &server, const QString &user, const QString &password); bool removeCloudAccount(const QString &server, const QString &user); void openCloudItem(const QVariantMap &item); void getCloudItem(const QVariantMap &item); static QString formatSize(const int &size); static QString formatDate(const QString &dateStr, const QString &format = QString("dd/MM/yyyy"), const QString &initFormat = QString()); static QString homePath(); static QUrl parentDir(const QUrl &path); static QVariantMap getDirInfo(const QUrl &path, const QString &type); static QVariantMap getFileInfo(const QUrl &path); static bool isDefaultPath(const QString &path); static bool isDir(const QUrl &path); static bool isApp(const QString &path); static bool isCloud(const QUrl &path); static bool fileExists(const QUrl &path); /** * if the url is a file path then it returns its directory * and if it is a directory returns the same path * */ static QString fileDir(const QUrl &path); /* SETTINGS */ static void saveSettings(const QString &key, const QVariant &value, const QString &group); static QVariant loadSettings(const QString &key, const QString &group, const QVariant &defaultValue); static QVariantMap dirConf(const QUrl &path); static void setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value); /* ACTIONS */ bool copy(const QVariantList &data, const QString &where); bool cut(const QVariantList &data, const QString &where); static bool removeFile(const QUrl &path); void moveToTrash(const QUrl &path); static void emptyTrash(); static bool rename(const QUrl &path, const QString &name); static bool createDir(const QUrl &path, const QString &name); static bool createFile(const QUrl &path, const QString &name); static bool openUrl(const QString &url); static void openLocation(const QStringList &urls); static void runApplication(const QString &exec); }; #endif // FM_H diff --git a/src/fm/fmlist.cpp b/src/fm/fmlist.cpp index 9daf669..720b795 100644 --- a/src/fm/fmlist.cpp +++ b/src/fm/fmlist.cpp @@ -1,877 +1,884 @@ /* * * 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->count = this->list.size(); + emit this->countChanged(); 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->count = this->list.size(); + emit this->countChanged(); 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; - + return; emit this->preListChanged(); this->list = res.content; - this->pathEmpty = this->list.isEmpty() /*&& FM::fileExists(this->path)*/; emit this->pathEmptyChanged(); - this->sortList(); + this->sortList(); + this->count = this->list.size(); + emit this->countChanged(); 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()); }else { this->sort = static_cast(UTIL::loadSettings("SortBy", "SETTINGS", this->sort).toInt()); } emit this->sortByChanged(); 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; } 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(); } +uint FMList::getCount() const +{ + return this->count; +} + diff --git a/src/fm/fmlist.h b/src/fm/fmlist.h index 2cc3128..1441a8c 100644 --- a/src/fm/fmlist.h +++ b/src/fm/fmlist.h @@ -1,245 +1,250 @@ /* * * 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(int cloudDepth READ getCloudDepth WRITE setCloudDepth NOTIFY cloudDepthChanged) + Q_PROPERTY(uint count READ getCount NOTIFY countChanged) 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); int getCloudDepth() const; void setCloudDepth(const int &value); + uint getCount() const; + 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; + uint count = 0; QString searchPath; 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 cloudDepthChanged(); + void countChanged(); void pathEmptyChanged(); void pathExistsChanged(); void warning(QString message); void progress(int percent); void searchResultReady(); }; #endif // FMLIST_H diff --git a/src/fm/pathlist.cpp b/src/fm/pathlist.cpp index 613da36..089d076 100644 --- a/src/fm/pathlist.cpp +++ b/src/fm/pathlist.cpp @@ -1,99 +1,101 @@ /* * * Copyright (C) 2019 camilo * * 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 "pathlist.h" #include "fm.h" PathList::PathList(QObject *parent) : MauiList(parent) { } PathList::~PathList() {} QVariantMap PathList::get(const int& index) const { - if(this->list.isEmpty() || index >= this->list.size() || index < 0) - { - return QVariantMap(); - } - + if(this->list.isEmpty() || index >= this->list.size() || index < 0) + { + return QVariantMap(); + } + const auto model = this->list.at(index); return FM::toMap(model); } QString PathList::getPath() const { return this->m_path; } FMH::MODEL_LIST PathList::items() const { return this->list; } void PathList::setPath(const QString& path) { if(path == this->m_path) return; if(!this->list.isEmpty() && FM::parentDir(path) == this->m_path) { // qDebug() << "APPENDING PATHS TO MODEL << "<< FM::parentDir(this->m_path) << this->list.last()[FMH::MODEL_KEY::PATH]; emit this->preItemAppended(); this->list << FMH::getDirInfoModel(path); emit this->postItemAppended(); }else{ emit this->preListChanged(); this->list.clear(); this->list << PathList::splitPath(path); emit this->postListChanged(); } this->m_path = path; emit this->pathChanged(); } FMH::MODEL_LIST PathList::splitPath(const QString& path) { auto __url = QUrl(path); const auto scheme = __url.scheme(); __url.setScheme(""); const auto m_url = __url.toString(); - const auto paths = m_url.split("/", QString::SplitBehavior::SkipEmptyParts); - - qDebug()<< "PATHBAR LIST"<< m_url << paths; + auto paths = m_url.split("/", QString::SplitBehavior::SkipEmptyParts); + if(paths.isEmpty()) + { + return {{{FMH::MODEL_KEY::LABEL, QString()}, {FMH::MODEL_KEY::PATH, path}}}; + } return std::accumulate(paths.constBegin(), paths.constEnd(), FMH::MODEL_LIST(), [scheme](FMH::MODEL_LIST &list, const QString &part) -> FMH::MODEL_LIST { const auto url = list.isEmpty() ? QString(scheme + (scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::PLACES_PATH] ? ":///" : "://") +part) : list.last()[FMH::MODEL_KEY::PATH] + QString("/"+part); if(!url.isEmpty()) list << FMH::MODEL { {FMH::MODEL_KEY::LABEL, part}, {FMH::MODEL_KEY::PATH, url} }; return list; }); }