diff --git a/src/controls/IconDelegate.qml b/src/controls/IconDelegate.qml index 7e431b0..82fe3db 100644 --- a/src/controls/IconDelegate.qml +++ b/src/controls/IconDelegate.qml @@ -1,350 +1,353 @@ /* * 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.2 as Kirigami import org.kde.mauikit 1.0 as Maui import QtGraphicalEffects 1.0 import "private" ItemDelegate { id: control /* Controlc color scheming */ ColorScheme { id: colorScheme } property alias colorScheme : colorScheme /***************************/ 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 ? highlightedTextColor : control.colorScheme.textColor property color hightlightedColor : GridView.isCurrentItem || hovered || (keepEmblemOverlay && emblemAdded) ? control.colorScheme.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 ? control.colorScheme.highlightColor : + color: !isDetails? "transparent" : (isCurrentListItem || (hovered && isDetails) ? control.colorScheme.highlightColor : index % 2 === 0 ? Qt.lighter( control.colorScheme.backgroundColor,1.2) : control.colorScheme.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 && leftEmblem) || showEmblem z: 999 anchors.top: parent.top anchors.left: parent.left onClicked: leftEmblemClicked(index) // Component.onCompleted: leftEmblemIcon.item.isMask = false size: iconSizes.small colorScheme.backgroundColor: control.colorScheme.accentColor } 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) colorScheme.backgroundColor: control.colorScheme.accentColor } Component { id: imgComponent Item { anchors.fill: parent Image { id: img clip: true anchors.centerIn: parent source: "file://"+model.thumbnail height: folderSize width: isDetails ? folderSize : control.width * 0.9 sourceSize.width: width sourceSize.height: folderSize horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter fillMode: Image.PreserveAspectCrop cache: false asynchronous: true layer.enabled: true layer.effect: OpacityMask { maskSource: Item { width: img.sourceSize.width height: img.sourceSize.height Rectangle { anchors.centerIn: parent width: img.sourceSize.width height: img.sourceSize.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 } } 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 4c67492..9f39539 100644 --- a/src/controls/ListBrowser.qml +++ b/src/controls/ListBrowser.qml @@ -1,147 +1,153 @@ /* * 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 2.9 +import QtQuick.Controls 2.4 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui ScrollView { id: control - property bool detailsView : false property int itemSize : iconSizes.big property bool showEmblem : true 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() ListView { anchors.fill: parent id: _listView // maximumFlickVelocity: 400 snapMode: ListView.SnapToItem boundsBehavior: !isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds - width: parent.width - height: parent.height + keyNavigationEnabled: true + clip: true + focus: true + interactive: true + highlightFollowsCurrentItem: true + highlightMoveDuration: 0 - clip: true - focus: true + width: parent.width + 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 showThumbnails: showPreviewThumbnails rightEmblem: control.rightEmblem leftEmblem: control.leftEmblem 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/SideBar.qml b/src/controls/SideBar.qml index 3dc02c9..1d73024 100644 --- a/src/controls/SideBar.qml +++ b/src/controls/SideBar.qml @@ -1,81 +1,71 @@ /* * 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.kirigami 2.0 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" -ListView +Maui.ListBrowser { id: control /* Controlc color scheming */ ColorScheme {id: colorScheme} property alias colorScheme : colorScheme /***************************/ property color bgColor: isCollapsed ? colorScheme.altColor : colorScheme.backgroundColor property color fgColor : isCollapsed ? colorScheme.altColorText : colorScheme.textColor property int iconSize : isMobile ? (isCollapsed || isWide ? iconSizes.medium : iconSizes.big) : iconSizes.small property bool collapsable : true property bool isCollapsed : false - signal itemClicked(int index) - - keyNavigationEnabled: true - clip: true - focus: true - interactive: true - highlightFollowsCurrentItem: true - highlightMoveDuration: 0 - snapMode: ListView.SnapToItem - boundsBehavior: !isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds - +// signal itemClicked(int index) Rectangle { anchors.fill: parent z: -1 color: bgColor } model: ListModel {} delegate: SideBarDelegate { id: itemDelegate sidebarIconSize: iconSize labelsVisible: !isCollapsed itemFgColor: fgColor Connections { target: itemDelegate onClicked: { control.currentIndex = index itemClicked(index) } } } } diff --git a/src/controls/private/SideBarDelegate.qml b/src/controls/private/SideBarDelegate.qml index 35103a1..00a8da8 100644 --- a/src/controls/private/SideBarDelegate.qml +++ b/src/controls/private/SideBarDelegate.qml @@ -1,104 +1,104 @@ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui ItemDelegate { id: control property bool isCurrentListItem : ListView.isCurrentItem property bool labelsVisible : true property int sidebarIconSize : iconSizes.small property alias label: controlLabel.text width: parent.width height: Math.max(sidebarIconSize + space.big, rowHeight) clip: true property color itemFgColor : textColor property string labelColor: ListView.isCurrentItem ? highlightedTextColor : itemFgColor hoverEnabled: !isMobile ToolTip.delay: 1000 ToolTip.timeout: 5000 ToolTip.visible: hovered && isCollapsed ToolTip.text: qsTr(model.label) background: Rectangle { anchors.fill: parent color: isCurrentListItem ? highlightColor : "transparent" // index % 2 === 0 ? Qt.lighter(backgroundColor,1.2) : // backgroundColor } RowLayout { anchors.fill: parent Item { Layout.fillHeight: true Layout.fillWidth: isCollapsed width: !isCollapsed ? parent.height : parent.width Kirigami.Icon { anchors.centerIn: parent source: model.icon ? model.icon : "" width: sidebarIconSize height: width - isMask: !isMobile +// isMask: !isMobile color: labelColor } } Item { visible: labelsVisible Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter Label { id: controlLabel height: parent.height width: parent.width verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignLeft text: model.label font.bold: false elide: Text.ElideRight font.pointSize: isMobile ? Maui.Style.fontSizes.big : Maui.Style.fontSizes.default color: labelColor } } Item { visible: model.count && model.count > 0 Layout.fillHeight: true width: iconSizes.big + space.small Layout.alignment: Qt.AlignRight Maui.Badge { anchors.centerIn: parent text: model.count } } } function clearCount() { console.log("CLEANING SIDEBAR COUNT") model.count = 0 } } diff --git a/src/fm/fm.cpp b/src/fm/fm.cpp index 13e9b70..eb086f0 100644 --- a/src/fm/fm.cpp +++ b/src/fm/fm.cpp @@ -1,891 +1,891 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fm.h" #include "utils.h" #include "tagging.h" #include "syncing.h" #include #include #include #include #include #include #include #include #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #else #include "mauikde.h" #include #include #endif /* FM *FM::instance = nullptr; FM* FM::getInstance() { if(!instance) { instance = new FM(); qDebug() << "getInstance(): First instance\n"; instance->init(); return instance; } else { qDebug()<< "getInstance(): previous instance\n"; return instance; } }*/ void FM::init() { this->tag = Tagging::getInstance(); this->sync = new Syncing(this); connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QString &url) { emit this->cloudServerContentReady(list, url); }); connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QString &url, const Syncing::SIGNAL_TYPE &signalType) { switch(signalType) { case Syncing::SIGNAL_TYPE::OPEN: this->openUrl(item[FMH::MODEL_KEY::PATH]); break; case Syncing::SIGNAL_TYPE::DOWNLOAD: emit this->cloudItemReady(item, url); break; case Syncing::SIGNAL_TYPE::COPY: { QVariantMap data; for(auto key : item.keys()) data.insert(FMH::MODEL_NAME[key], item[key]); this->copy(QVariantList {data}, this->sync->getCopyTo()); break; } default: return; } }); connect(this->sync, &Syncing::error, [this](const QString &message) { emit this->warningMessage(message); }); connect(this->sync, &Syncing::progress, [this](const int &percent) { emit this->loadProgress(percent); }); connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QString &url) { emit this->newItem(dir, url); }); connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QString &url) { emit this->newItem(item, url); }); } FM::FM(QObject *parent) : FMDB(parent) { this->init(); } FM::~FM() {} QVariantMap FM::toMap(const FMH::MODEL& model) { QVariantMap map; for(const auto &key : model.keys()) map.insert(FMH::MODEL_NAME[key], model[key]); return map; } FMH::MODEL FM::toModel(const QVariantMap& map) { FMH::MODEL model; for(const auto &key : map.keys()) model.insert(FMH::MODEL_NAME_KEY[key], map[key].toString()); return model; } FMH::MODEL_LIST FM::packItems(const QStringList &items, const QString &type) { FMH::MODEL_LIST data; for(const auto &path : items) if(UTIL::fileExists(path)) { auto model = FMH::getFileInfoModel(path); model.insert(FMH::MODEL_KEY::TYPE, type); data << model; } return data; } QVariantList FM::get(const QString &queryTxt) { QVariantList mapList; auto query = this->getQuery(queryTxt); if(query.exec()) { while(query.next()) { QVariantMap data; for(auto key : FMH::MODEL_NAME.keys()) if(query.record().indexOf(FMH::MODEL_NAME[key]) > -1) data[FMH::MODEL_NAME[key]] = query.value(FMH::MODEL_NAME[key]).toString(); mapList<< data; } }else qDebug()<< query.lastError()<< query.lastQuery(); return mapList; } FMH::MODEL_LIST FM::getPathContent(const QString& path, const bool &hidden, const bool &onlyDirs, const QStringList& filters, const QDirIterator::IteratorFlags &iteratorFlags) { FMH::MODEL_LIST content; if (FM::isDir(path)) { QDir::Filters dirFilter; dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); if(hidden) dirFilter = dirFilter | QDir::Hidden | QDir::System; QDirIterator it (path, filters, dirFilter, iteratorFlags); while (it.hasNext()) { auto url = it.next(); content << FMH::getFileInfoModel(url); } } return content; } FMH::MODEL_LIST FM::getAppsContent(const QString& path) { FMH::MODEL_LIST res; #if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID)) if(path.startsWith(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::APPS_PATH]+"/")) return MAUIKDE::getApps(QString(path).replace(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::APPS_PATH]+"/","")); else return MAUIKDE::getApps(); #endif return res; } FMH::MODEL_LIST FM::getDefaultPaths() { return packItems(FMH::defaultPaths, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::PLACES_PATH]); } -FMH::MODEL_LIST FM::getCustomPaths() +FMH::MODEL_LIST FM::getAppsPath() { #ifdef Q_OS_ANDROID return FMH::MODEL_LIST(); #endif return FMH::MODEL_LIST { FMH::MODEL { {FMH::MODEL_KEY::ICON, "system-run"}, {FMH::MODEL_KEY::LABEL, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::APPS_PATH]}, {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::APPS_PATH]+"/"}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::PLACES_PATH]} } }; } FMH::MODEL_LIST FM::search(const QString& query, const QString &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) { FMH::MODEL_LIST content; if (FM::isDir(path)) { QDir::Filters dirFilter; dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); if(hidden) dirFilter = dirFilter | QDir::Hidden | QDir::System; QDirIterator it (path, filters, dirFilter, QDirIterator::Subdirectories); while (it.hasNext()) { auto url = it.next(); auto info = it.fileInfo(); qDebug()<< info.completeBaseName() << info.completeBaseName().contains(query); if(info.completeBaseName().contains(query, Qt::CaseInsensitive)) { content << FMH::getFileInfoModel(url); } } } qDebug()<< content; return content; } -FMH::MODEL_LIST FM::getDevices() -{ - FMH::MODEL_LIST drives; - -#if defined(Q_OS_ANDROID) - drives << packItems({MAUIAndroid::sdDir()}, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES_PATH]); - return drives; -#else - KFilePlacesModel model; - for(const auto &i : model.groupIndexes(KFilePlacesModel::GroupType::RemoteType)) - { - drives << FMH::MODEL{ - {FMH::MODEL_KEY::NAME, model.text(i)}, - {FMH::MODEL_KEY::LABEL, model.text(i)}, - {FMH::MODEL_KEY::PATH, model.url(i).toString()}, - {FMH::MODEL_KEY::ICON, model.icon(i).name()}, - {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES_PATH]}, - }; - } - -#endif - - // auto devices = QStorageInfo::mountedVolumes(); - // for(auto device : devices) - // { - // if(device.isValid() && !device.isReadOnly()) - // { - // QVariantMap drive = - // { - // {FMH::MODEL_NAME[FMH::MODEL_KEY::ICON], "drive-harddisk"}, - // {FMH::MODEL_NAME[FMH::MODEL_KEY::LABEL], device.displayName()}, - // {FMH::MODEL_NAME[FMH::MODEL_KEY::PATH], device.rootPath()}, - // {FMH::MODEL_NAME[FMH::MODEL_KEY::TYPE], FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES]} - // }; - // - // drives << drive; - // } - // } - - // for(auto device : QDir::drives()) - // { - // QVariantMap drive = - // { - // {"iconName", "drive-harddisk"}, - // {"label", device.baseName()}, - // {"path", device.absoluteFilePath()}, - // {"type", "Drives"} - // }; - - // drives << drive; - // } - - return drives; -} +// FMH::MODEL_LIST FM::getDevices() +// { +// FMH::MODEL_LIST drives; +// +// #if defined(Q_OS_ANDROID) +// drives << packItems({MAUIAndroid::sdDir()}, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES_PATH]); +// return drives; +// #else +// KFilePlacesModel model; +// for(const auto &i : model.groupIndexes(KFilePlacesModel::GroupType::RemoteType)) +// { +// drives << FMH::MODEL{ +// {FMH::MODEL_KEY::NAME, model.text(i)}, +// {FMH::MODEL_KEY::LABEL, model.text(i)}, +// {FMH::MODEL_KEY::PATH, model.url(i).toString()}, +// {FMH::MODEL_KEY::ICON, model.icon(i).name()}, +// {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES_PATH]}, +// }; +// } +// +// #endif +// +// // auto devices = QStorageInfo::mountedVolumes(); +// // for(auto device : devices) +// // { +// // if(device.isValid() && !device.isReadOnly()) +// // { +// // QVariantMap drive = +// // { +// // {FMH::MODEL_NAME[FMH::MODEL_KEY::ICON], "drive-harddisk"}, +// // {FMH::MODEL_NAME[FMH::MODEL_KEY::LABEL], device.displayName()}, +// // {FMH::MODEL_NAME[FMH::MODEL_KEY::PATH], device.rootPath()}, +// // {FMH::MODEL_NAME[FMH::MODEL_KEY::TYPE], FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::DRIVES]} +// // }; +// // +// // drives << drive; +// // } +// // } +// +// // for(auto device : QDir::drives()) +// // { +// // QVariantMap drive = +// // { +// // {"iconName", "drive-harddisk"}, +// // {"label", device.baseName()}, +// // {"path", device.absoluteFilePath()}, +// // {"type", "Drives"} +// // }; +// +// // drives << drive; +// // } +// +// return drives; +// } FMH::MODEL_LIST FM::getTags(const int &limit) { Q_UNUSED(limit); FMH::MODEL_LIST data; if(this->tag) { for(auto tag : this->tag->getUrlsTags(false)) { qDebug()<< "TAG << "<< tag; auto label = tag.toMap().value(TAG::KEYMAP[TAG::KEYS::TAG]).toString(); data << FMH::MODEL { {FMH::MODEL_KEY::PATH, label}, {FMH::MODEL_KEY::ICON, "tag"}, {FMH::MODEL_KEY::LABEL, label}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::TAGS_PATH]} }; } } return data; } -FMH::MODEL_LIST FM::getBookmarks() -{ - QStringList bookmarks; - -#ifdef Q_OS_ANDROID - for(const auto &bookmark : this->get("select * from bookmarks")) - bookmarks << bookmark.toMap().value(FMH::MODEL_NAME[FMH::MODEL_KEY::PATH]).toString(); - -#else -KFilePlacesModel model; - qDebug()<< "PLACES MODEL COUNT"<< model.rowCount() << model.columnCount(); - for(const auto &i : model.groupIndexes(KFilePlacesModel::GroupType::PlacesType)) - { - const auto url = model.url(i).toString().replace("file://",""); - if(!FMH::defaultPaths.contains(url)) - bookmarks << url; - } -#endif - - return packItems(bookmarks, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::BOOKMARKS_PATH]); -} +// FMH::MODEL_LIST FM::getBookmarks() +// { +// QStringList bookmarks; +// +// #ifdef Q_OS_ANDROID +// for(const auto &bookmark : this->get("select * from bookmarks")) +// bookmarks << bookmark.toMap().value(FMH::MODEL_NAME[FMH::MODEL_KEY::PATH]).toString(); +// +// #else +// KFilePlacesModel model; +// qDebug()<< "PLACES MODEL COUNT"<< model.rowCount() << model.columnCount(); +// for(const auto &i : model.groupIndexes(KFilePlacesModel::GroupType::PlacesType)) +// { +// const auto url = model.url(i).toString().replace("file://",""); +// if(!FMH::defaultPaths.contains(url)) +// bookmarks << url; +// } +// #endif +// +// return packItems(bookmarks, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::BOOKMARKS_PATH]); +// } bool FM::getCloudServerContent(const QString &path, const QStringList &filters, const int &depth) { auto user = path.split("/")[1]; auto data = this->get(QString("select * from clouds where user = '%1'").arg(user)); if(data.isEmpty()) return false; auto map = data.first().toMap(); user = map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString(); auto server = map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString(); auto password = map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString(); this->sync->setCredentials(server, user, password); this->sync->listContent(path, filters, depth); return true; } FMH::MODEL_LIST FM::getCloudAccounts() { auto accounts = this->get("select * from clouds"); FMH::MODEL_LIST res; for(auto account : accounts) { auto map = account.toMap(); res << FMH::MODEL { {FMH::MODEL_KEY::PATH, QStringLiteral("Cloud/")+map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, {FMH::MODEL_KEY::ICON, "folder-cloud"}, {FMH::MODEL_KEY::LABEL, map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, {FMH::MODEL_KEY::USER, map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, {FMH::MODEL_KEY::SERVER, map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString()}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::CLOUD_PATH]}}; } return res; } void FM::createCloudDir(const QString &path, const QString &name) { qDebug()<< "trying to create folder at"<< path; this->sync->createDir(path, name); } void FM::openCloudItem(const QVariantMap &item) { qDebug()<< item; FMH::MODEL data; for(auto key : item.keys()) data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::OPEN); } void FM::getCloudItem(const QVariantMap &item) { qDebug()<< item; FMH::MODEL data; for(auto key : item.keys()) data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::DOWNLOAD); } QVariantList FM::getCloudAccountsList() { QVariantList res; auto data = this->getCloudAccounts(); for(auto item : data) { QVariantMap map; for(auto key : item.keys()) map.insert(FMH::MODEL_NAME[key], item[key]); res << map; } return res; } bool FM::addCloudAccount(const QString &server, const QString &user, const QString &password) { QVariantMap account = { {FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER], server}, {FMH::MODEL_NAME[FMH::MODEL_KEY::USER], user}, {FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD], password} }; if(this->insert(FMH::TABLEMAP[FMH::TABLE::CLOUDS], account)) { emit this->cloudAccountInserted(user); return true; } return false; } bool FM::removeCloudAccount(const QString &server, const QString &user) { FMH::DB account = { {FMH::MODEL_KEY::SERVER, server}, {FMH::MODEL_KEY::USER, user}, }; if(this->remove(FMH::TABLEMAP[FMH::TABLE::CLOUDS], account)) { emit this->cloudAccountRemoved(user); return true; } return false; } QString FM::resolveUserCloudCachePath(const QString &server, const QString &user) { return FMH::CloudCachePath+"opendesktop/"+user; } QString FM::resolveLocalCloudPath(const QString& path) { return QString(path).replace(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::CLOUD_PATH]+"/"+this->sync->getUser(), ""); } FMH::MODEL_LIST FM::getTagContent(const QString &tag) { FMH::MODEL_LIST content; qDebug()<< "TAG CONTENT FOR TAG"<< tag; for(auto data : this->tag->getUrls(tag, false)) { const auto url = data.toMap().value(TAG::KEYMAP[TAG::KEYS::URL]).toString(); auto item = FMH::getFileInfoModel(url); content << item; } return content; } QVariantMap FM::getDirInfo(const QString &path, const QString &type) { return FMH::getDirInfo(path, type); } QVariantMap FM::getFileInfo(const QString &path) { return FMH::getFileInfo(path); } bool FM::isDefaultPath(const QString &path) { return FMH::defaultPaths.contains(path); } QString FM::parentDir(const QString &path) { auto dir = QDir(path); dir.cdUp(); return dir.absolutePath(); } bool FM::isDir(const QString &path) { return QFileInfo(path).isDir(); } bool FM::isApp(const QString& path) { return /*QFileInfo(path).isExecutable() ||*/ path.endsWith(".desktop"); } bool FM::isCloud(const QString &path) { return path.startsWith(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::CLOUD_PATH]); } bool FM::bookmark(const QString &path) { if(FMH::defaultPaths.contains(path)) return false; if(!FMH::fileExists(path)) return false; QFileInfo file (path); #ifdef Q_OS_ANDROID QVariantMap bookmark_map { {FMH::MODEL_NAME[FMH::MODEL_KEY::PATH], path}, {FMH::MODEL_NAME[FMH::MODEL_KEY::LABEL], file.baseName()}, {FMH::MODEL_NAME[FMH::MODEL_KEY::DATE], QDateTime::currentDateTime()} }; if(this->insert(FMH::TABLEMAP[FMH::TABLE::BOOKMARKS], bookmark_map)) { emit this->bookmarkInserted(path); return true; } #else KFilePlacesModel model; model.addPlace(file.fileName(), QStringLiteral("file://") + file.filePath()); #endif return false; } bool FM::removeBookmark(const QString& path) { #ifdef Q_OS_ANDROID FMH::DB data = {{FMH::MODEL_KEY::PATH, path}}; if(this->remove(FMH::TABLEMAP[FMH::TABLE::BOOKMARKS], data)) { emit this->bookmarkRemoved(path); return true; } #else KFilePlacesModel model; for(const auto &i : model.groupIndexes(KFilePlacesModel::GroupType::PlacesType)) { if(path == model.url(i).toString().replace("file://","")) { model.removePlace(i); return true; } } #endif return false; } -bool FM::isBookmark(const QString& path) -{ - #ifdef Q_OS_ANDROID - return this->checkExistance(QString("select * from bookmarks where path = '%1'").arg(path)); - - -#else -const auto bookmarks = this->getBookmarks(); - -for(const auto &item : bookmarks) - if(item[FMH::MODEL_KEY::PATH] == path) - return true; - -return false; -#endif -} +// bool FM::isBookmark(const QString& path) +// { +// #ifdef Q_OS_ANDROID +// return this->checkExistance(QString("select * from bookmarks where path = '%1'").arg(path)); +// +// +// #else +// const auto bookmarks = this->getBookmarks(); +// +// for(const auto &item : bookmarks) +// if(item[FMH::MODEL_KEY::PATH] == path) +// return true; +// +// return false; +// #endif +// } bool FM::fileExists(const QString &path) { return FMH::fileExists(path); } void FM::saveSettings(const QString &key, const QVariant &value, const QString &group) { UTIL::saveSettings(key, value, group); } QVariant FM::loadSettings(const QString &key, const QString &group, const QVariant &defaultValue) { return UTIL::loadSettings(key, group, defaultValue); } QString FM::formatSize(const int &size) { QLocale locale; return locale.formattedDataSize(size); } QString FM::formatDate(const QString &dateStr, const QString &format, const QString &initFormat) { QDateTime date; if( initFormat.isEmpty() ) date = QDateTime::fromString(dateStr, Qt::TextDate); else date = QDateTime::fromString(dateStr, initFormat); return date.toString(format); } QString FM::homePath() { return FMH::HomePath; } bool FM::cut(const QVariantList &data, const QString &where) { FMH::MODEL_LIST items; for(auto k : data) { auto map = k.toMap(); FMH::MODEL model; for(auto key : map.keys()) model.insert(FMH::MODEL_NAME_KEY[key], map[key].toString()); items << model; } for(auto item : items) { auto path = item[FMH::MODEL_KEY::PATH]; if(this->isCloud(path)) { this->sync->setCopyTo(where); this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); }else if(UTIL::fileExists(path)) { QFile file(path); file.rename(where+"/"+QFileInfo(path).fileName()); } } return true; } bool FM::copy(const QVariantList &data, const QString &where) { FMH::MODEL_LIST items; for(auto k : data) { auto map = k.toMap(); FMH::MODEL model; for(auto key : map.keys()) model.insert(FMH::MODEL_NAME_KEY[key], map[key].toString()); items << model; } QStringList cloudPaths; for(auto item : items) { auto path = item[FMH::MODEL_KEY::PATH]; if(this->isDir(path)) { auto state = copyPath(path, where+"/"+QFileInfo(path).fileName(), false); if(!state) return false; }else if(this->isCloud(path)) { this->sync->setCopyTo(where); this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); }else if(UTIL::fileExists(path)) { QFile file(path); qDebug()<< path << "is a file" << where; if(this->isCloud(where)) cloudPaths << path; else file.copy(where+"/"+FMH::getFileInfoModel(path)[FMH::MODEL_KEY::LABEL]); } } if(!cloudPaths.isEmpty()) { qDebug()<<"UPLOAD QUEUE" << cloudPaths; const auto firstPath = cloudPaths.takeLast(); this->sync->setUploadQueue(cloudPaths); if(where.split("/").last().contains(".")) { QStringList whereList = where.split("/"); whereList.removeLast(); auto whereDir = whereList.join("/"); qDebug()<< "Trying ot copy to cloud" << where << whereDir; this->sync->upload(this->resolveLocalCloudPath(whereDir), firstPath); } else this->sync->upload(this->resolveLocalCloudPath(where), firstPath); } return true; } bool FM::copyPath(QString sourceDir, QString destinationDir, bool overWriteDirectory) { QDir originDirectory(sourceDir); if (!originDirectory.exists()) return false; QDir destinationDirectory(destinationDir); if(destinationDirectory.exists() && !overWriteDirectory) return false; else if(destinationDirectory.exists() && overWriteDirectory) destinationDirectory.removeRecursively(); originDirectory.mkpath(destinationDir); foreach(QString directoryName, originDirectory.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { QString destinationPath = destinationDir + "/" + directoryName; originDirectory.mkpath(destinationPath); copyPath(sourceDir + "/" + directoryName, destinationPath, overWriteDirectory); } foreach (QString fileName, originDirectory.entryList(QDir::Files)) { QFile::copy(sourceDir + "/" + fileName, destinationDir + "/" + fileName); } /*! Possible race-condition mitigation? */ QDir finalDestination(destinationDir); finalDestination.refresh(); if(finalDestination.exists()) return true; return false; } bool FM::removeFile(const QString &path) { if(QFileInfo(path).isDir()) return removeDir(path); else return QFile(path).remove(); } bool FM::removeDir(const QString &path) { bool result = true; QDir dir(path); if (dir.exists(path)) { Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { if (info.isDir()) { result = removeDir(info.absoluteFilePath()); } else { result = QFile::remove(info.absoluteFilePath()); } if (!result) { return result; } } result = dir.rmdir(path); } return result; } bool FM::rename(const QString &path, const QString &name) { QFile file(path); auto url = QFileInfo(path).dir().absolutePath(); qDebug()<< "RENAME FILE TO:" << path << name << url; return file.rename(url+"/"+name); } bool FM::createDir(const QString &path, const QString &name) { return QDir(path).mkdir(name); } bool FM::createFile(const QString &path, const QString &name) { QFile file(path + "/" + name); if(file.open(QIODevice::ReadWrite)) { file.close(); return true; } return false; } bool FM::openUrl(const QString &url) { return QDesktopServices::openUrl(QUrl::fromUserInput(url)); } void FM::openLocation(const QStringList &urls) { for(auto url : urls) QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(url).dir().absolutePath())); } void FM::runApplication(const QString& exec) { #if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID)) return MAUIKDE::launchApp(exec); #endif } QVariantMap FM::dirConf(const QString &path) { return FMH::dirConf(path); } void FM::setDirConf(const QString &path, const QString &group, const QString &key, const QVariant &value) { FMH::setDirConf(path, group, key, value); } diff --git a/src/fm/fm.h b/src/fm/fm.h index 0473bdf..caa5b8b 100644 --- a/src/fm/fm.h +++ b/src/fm/fm.h @@ -1,138 +1,138 @@ #ifndef FM_H #define FM_H #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 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(); +// 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); /*** START STATIC METHODS ***/ static FMH::MODEL_LIST search(const QString &query, const QString &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); - static FMH::MODEL_LIST getDevices(); +// static FMH::MODEL_LIST getDevices(); static FMH::MODEL_LIST getDefaultPaths(); - static FMH::MODEL_LIST getCustomPaths(); + static FMH::MODEL_LIST getAppsPath(); static FMH::MODEL_LIST packItems(const QStringList &items, const QString &type); FMH::MODEL_LIST static getPathContent(const QString &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags); FMH::MODEL_LIST static getAppsContent(const QString &path); static bool copyPath(QString sourceDir, QString destinationDir, bool overWriteDirectory); static bool removeDir(const QString &path); static QString resolveUserCloudCachePath(const QString &server, const QString &user); QString resolveLocalCloudPath(const QString &path); static QVariantMap toMap(const FMH::MODEL &model); static FMH::MODEL toModel(const QVariantMap &map); /*** END STATIC METHODS ***/ private: Tagging *tag; // static FM* instance; void init(); QVariantList get(const QString &queryTxt); signals: void bookmarkInserted(QString bookmark); void bookmarkRemoved(QString bookmark); 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 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: bool bookmark(const QString &path); bool removeBookmark(const QString &path); - bool isBookmark(const QString &path); +// bool isBookmark(const QString &path); 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 QString parentDir(const QString &path); static QVariantMap getDirInfo(const QString &path, const QString &type); static QVariantMap getFileInfo(const QString &path); static bool isDefaultPath(const QString &path); static bool isDir(const QString &path); static bool isApp(const QString &path); static bool isCloud(const QString &path); static bool fileExists(const QString &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 QString &path); static void setDirConf(const QString &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 QString &path); static bool rename(const QString &path, const QString &name); static bool createDir(const QString &path, const QString &name); static bool createFile(const QString &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/fmh.h b/src/fm/fmh.h index 52bca84..bbba3b0 100644 --- a/src/fm/fmh.h +++ b/src/fm/fmh.h @@ -1,804 +1,809 @@ /* * 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. */ #ifndef FMH_H #define FMH_H #include #include #include #include #include #include #include #include #include #include #include #include +#include #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #elif defined(Q_OS_LINUX) #include #include #include #endif namespace FMH { inline bool isAndroid() { #if defined(Q_OS_ANDROID) return true; #elif defined(Q_OS_LINUX) return false; #elif defined(Q_OS_WIN32) return false; #elif defined(Q_OS_WIN64) return false; #elif defined(Q_OS_MACOS) return false; #elif defined(Q_OS_IOS) return false; #elif defined(Q_OS_HAIKU) return false; #endif } enum FILTER_TYPE : uint_fast8_t { AUDIO, VIDEO, TEXT, IMAGE, DOCUMENT, NONE }; static const QHash FILTER_LIST = { {FILTER_TYPE::AUDIO, QStringList {"*.mp3", "*.mp4", "*.wav", "*.ogg", "*.flac"}}, {FILTER_TYPE::VIDEO, QStringList {"*.mp4", "*.mkv", "*.mov", "*.avi", "*.flv"}}, {FILTER_TYPE::TEXT, QStringList {"*.txt", "*.cpp", "*.js", "*.doc", "*.h", "*.json", "*.html", "*.rtf"}}, {FILTER_TYPE::DOCUMENT, QStringList {"*.pdf", "*.txt", "*.cbz", "*.cbr", "*.epub", "*.cbt", "*.cba", "*.cb7"}}, {FILTER_TYPE::IMAGE, QStringList {"*.png", "*.jpg", "*.jpeg", "*.gif", "*.svg", "*.bmp"}}, {FILTER_TYPE::NONE, QStringList()} }; enum MODEL_KEY : uint_fast8_t { ICON, LABEL, PATH, URL, TYPE, GROUP, OWNER, SUFFIX, NAME, DATE, SIZE, MODIFIED, MIME, TAG, PERMISSIONS, THUMBNAIL, THUMBNAIL_1, THUMBNAIL_2, THUMBNAIL_3, HIDDEN, ICONSIZE, DETAILVIEW, SHOWTHUMBNAIL, SHOWTERMINAL, COUNT, SORTBY, USER, PASSWORD, SERVER, FOLDERSFIRST, VIEWTYPE, ADDDATE, FAV, COLOR, RATE, FORMAT, PLACE, LOCATION, ALBUM, ARTIST, TRACK, DURATION, ARTWORK, PLAYLIST, LYRICS, WIKI, MOOD, SOURCETYPE, GENRE, NOTE, COMMENT, CONTEXT, SOURCE, TITLE, ID, RELEASEDATE, LICENSE, DESCRIPTION, BOOKMARK, ACCOUNT, VERSION, DOMAIN, /** ccdav keys **/ N, PHOTO, GENDER, ADR, ADR_2, ADR_3, EMAIL, EMAIL_2, EMAIL_3, LANG, NICKNAME, ORG, PROFILE, TZ, TEL, TEL_2, TEL_3, IM, /** other keys **/ CITY, STATE, COUNTRY }; static const QHash MODEL_NAME = { {MODEL_KEY::ICON, "icon"}, {MODEL_KEY::LABEL, "label"}, {MODEL_KEY::PATH, "path"}, {MODEL_KEY::URL, "url"}, {MODEL_KEY::TYPE, "type"}, {MODEL_KEY::GROUP, "group"}, {MODEL_KEY::OWNER, "owner"}, {MODEL_KEY::SUFFIX, "suffix"}, {MODEL_KEY::NAME, "name"}, {MODEL_KEY::DATE, "date"}, {MODEL_KEY::MODIFIED, "modified"}, {MODEL_KEY::MIME, "mime"}, {MODEL_KEY::SIZE, "size"}, {MODEL_KEY::TAG, "tag"}, {MODEL_KEY::PERMISSIONS, "permissions"}, {MODEL_KEY::THUMBNAIL, "thumbnail"}, {MODEL_KEY::THUMBNAIL_1, "thumbnail_1"}, {MODEL_KEY::THUMBNAIL_2, "thumbnail_2"}, {MODEL_KEY::THUMBNAIL_3, "thumbnail_3"}, {MODEL_KEY::ICONSIZE, "iconsize"}, {MODEL_KEY::HIDDEN, "hidden"}, {MODEL_KEY::DETAILVIEW, "detailview"}, {MODEL_KEY::SHOWTERMINAL, "showterminal"}, {MODEL_KEY::SHOWTHUMBNAIL, "showthumbnail"}, {MODEL_KEY::COUNT, "count"}, {MODEL_KEY::SORTBY, "sortby"}, {MODEL_KEY::USER, "user"}, {MODEL_KEY::PASSWORD, "password"}, {MODEL_KEY::SERVER, "server"}, {MODEL_KEY::FOLDERSFIRST, "foldersfirst"}, {MODEL_KEY::VIEWTYPE, "viewtype"}, {MODEL_KEY::ADDDATE, "adddate"}, {MODEL_KEY::FAV, "fav"}, {MODEL_KEY::COLOR, "color"}, {MODEL_KEY::RATE, "rate"}, {MODEL_KEY::FORMAT, "format"}, {MODEL_KEY::PLACE, "place"}, {MODEL_KEY::LOCATION, "location"}, {MODEL_KEY::ALBUM, "album"}, {MODEL_KEY::DURATION, "duration"}, {MODEL_KEY::RELEASEDATE, "releasedate"}, {MODEL_KEY::ARTIST, "artist"}, {MODEL_KEY::LYRICS, "lyrics"}, {MODEL_KEY::TRACK, "track"}, {MODEL_KEY::GENRE, "genre"}, {MODEL_KEY::WIKI, "wiki"}, {MODEL_KEY::CONTEXT, "context"}, {MODEL_KEY::SOURCETYPE, "sourcetype"}, {MODEL_KEY::ARTWORK, "artwork"}, {MODEL_KEY::NOTE, "note"}, {MODEL_KEY::MOOD, "mood"}, {MODEL_KEY::COMMENT, "comment"}, {MODEL_KEY::PLAYLIST, "playlist"}, {MODEL_KEY::SOURCE, "source"}, {MODEL_KEY::TITLE, "title"}, {MODEL_KEY::ID, "id"}, {MODEL_KEY::LICENSE, "license"}, {MODEL_KEY::DESCRIPTION, "description"}, {MODEL_KEY::BOOKMARK, "bookmark"}, {MODEL_KEY::ACCOUNT, "account"}, {MODEL_KEY::VERSION, "version"}, {MODEL_KEY::DOMAIN, "domain"}, /** ccdav keys **/ {MODEL_KEY::N, "n"}, {MODEL_KEY::IM, "im"}, {MODEL_KEY::PHOTO, "photo"}, {MODEL_KEY::GENDER, "gender"}, {MODEL_KEY::ADR, "adr"}, {MODEL_KEY::ADR_2, "adr2"}, {MODEL_KEY::ADR_3, "adr3"}, {MODEL_KEY::EMAIL, "email"}, {MODEL_KEY::EMAIL_2, "email2"}, {MODEL_KEY::EMAIL_3, "email3"}, {MODEL_KEY::LANG, "lang"}, {MODEL_KEY::NICKNAME, "nickname"}, {MODEL_KEY::ORG, "org"}, {MODEL_KEY::PROFILE, "profile"}, {MODEL_KEY::TZ, "tz"}, {MODEL_KEY::TEL, "tel"}, {MODEL_KEY::TEL_2, "tel2"}, {MODEL_KEY::TEL_3, "tel3"}, {MODEL_KEY::CITY, "city"}, {MODEL_KEY::STATE, "state"}, {MODEL_KEY::COUNTRY, "country"}, }; static const QHash MODEL_NAME_KEY = { {MODEL_NAME[MODEL_KEY::ICON], MODEL_KEY::ICON}, {MODEL_NAME[MODEL_KEY::LABEL], MODEL_KEY::LABEL}, {MODEL_NAME[MODEL_KEY::PATH], MODEL_KEY::PATH}, {MODEL_NAME[MODEL_KEY::URL], MODEL_KEY::URL}, {MODEL_NAME[MODEL_KEY::TYPE], MODEL_KEY::TYPE}, {MODEL_NAME[MODEL_KEY::GROUP], MODEL_KEY::GROUP}, {MODEL_NAME[MODEL_KEY::OWNER], MODEL_KEY::OWNER}, {MODEL_NAME[MODEL_KEY::SUFFIX], MODEL_KEY::SUFFIX}, {MODEL_NAME[MODEL_KEY::NAME], MODEL_KEY::NAME}, {MODEL_NAME[MODEL_KEY::DATE], MODEL_KEY::DATE}, {MODEL_NAME[MODEL_KEY::MODIFIED], MODEL_KEY::MODIFIED}, {MODEL_NAME[MODEL_KEY::MIME], MODEL_KEY::MIME}, {MODEL_NAME[MODEL_KEY::SIZE], MODEL_KEY::SIZE,}, {MODEL_NAME[MODEL_KEY::TAG], MODEL_KEY::TAG}, {MODEL_NAME[MODEL_KEY::PERMISSIONS], MODEL_KEY::PERMISSIONS}, {MODEL_NAME[MODEL_KEY::THUMBNAIL], MODEL_KEY::THUMBNAIL}, {MODEL_NAME[MODEL_KEY::THUMBNAIL_1], MODEL_KEY::THUMBNAIL_1}, {MODEL_NAME[MODEL_KEY::THUMBNAIL_2], MODEL_KEY::THUMBNAIL_2}, {MODEL_NAME[MODEL_KEY::THUMBNAIL_3], MODEL_KEY::THUMBNAIL_3}, {MODEL_NAME[MODEL_KEY::ICONSIZE], MODEL_KEY::ICONSIZE}, {MODEL_NAME[MODEL_KEY::HIDDEN], MODEL_KEY::HIDDEN}, {MODEL_NAME[MODEL_KEY::DETAILVIEW], MODEL_KEY::DETAILVIEW}, {MODEL_NAME[MODEL_KEY::SHOWTERMINAL], MODEL_KEY::SHOWTERMINAL}, {MODEL_NAME[MODEL_KEY::SHOWTHUMBNAIL], MODEL_KEY::SHOWTHUMBNAIL}, {MODEL_NAME[MODEL_KEY::COUNT], MODEL_KEY::COUNT}, {MODEL_NAME[MODEL_KEY::SORTBY], MODEL_KEY::SORTBY}, {MODEL_NAME[MODEL_KEY::USER], MODEL_KEY::USER}, {MODEL_NAME[MODEL_KEY::PASSWORD], MODEL_KEY::PASSWORD}, {MODEL_NAME[MODEL_KEY::SERVER], MODEL_KEY::SERVER}, {MODEL_NAME[MODEL_KEY::VIEWTYPE], MODEL_KEY::VIEWTYPE}, {MODEL_NAME[MODEL_KEY::ADDDATE], MODEL_KEY::ADDDATE}, {MODEL_NAME[MODEL_KEY::FAV], MODEL_KEY::FAV}, {MODEL_NAME[MODEL_KEY::COLOR], MODEL_KEY::COLOR}, {MODEL_NAME[MODEL_KEY::RATE], MODEL_KEY::RATE}, {MODEL_NAME[MODEL_KEY::FORMAT], MODEL_KEY::FORMAT}, {MODEL_NAME[MODEL_KEY::PLACE], MODEL_KEY::PLACE}, {MODEL_NAME[MODEL_KEY::LOCATION], MODEL_KEY::LOCATION}, {MODEL_NAME[MODEL_KEY::ALBUM], MODEL_KEY::ALBUM}, {MODEL_NAME[MODEL_KEY::ARTIST], MODEL_KEY::ARTIST}, {MODEL_NAME[MODEL_KEY::DURATION], MODEL_KEY::DURATION}, {MODEL_NAME[MODEL_KEY::TRACK], MODEL_KEY::TRACK}, {MODEL_NAME[MODEL_KEY::GENRE], MODEL_KEY::GENRE}, {MODEL_NAME[MODEL_KEY::LYRICS], MODEL_KEY::LYRICS}, {MODEL_NAME[MODEL_KEY::RELEASEDATE], MODEL_KEY::RELEASEDATE}, {MODEL_NAME[MODEL_KEY::FORMAT], MODEL_KEY::FORMAT}, {MODEL_NAME[MODEL_KEY::WIKI], MODEL_KEY::WIKI}, {MODEL_NAME[MODEL_KEY::SOURCETYPE], MODEL_KEY::SOURCETYPE}, {MODEL_NAME[MODEL_KEY::ARTWORK], MODEL_KEY::ARTWORK}, {MODEL_NAME[MODEL_KEY::NOTE], MODEL_KEY::NOTE}, {MODEL_NAME[MODEL_KEY::MOOD], MODEL_KEY::MOOD}, {MODEL_NAME[MODEL_KEY::COMMENT], MODEL_KEY::COMMENT}, {MODEL_NAME[MODEL_KEY::CONTEXT], MODEL_KEY::CONTEXT}, {MODEL_NAME[MODEL_KEY::SOURCE], MODEL_KEY::SOURCE}, {MODEL_NAME[MODEL_KEY::TITLE], MODEL_KEY::TITLE}, {MODEL_NAME[MODEL_KEY::ID], MODEL_KEY::ID}, {MODEL_NAME[MODEL_KEY::LICENSE], MODEL_KEY::LICENSE}, {MODEL_NAME[MODEL_KEY::DESCRIPTION], MODEL_KEY::DESCRIPTION}, {MODEL_NAME[MODEL_KEY::BOOKMARK], MODEL_KEY::BOOKMARK}, {MODEL_NAME[MODEL_KEY::ACCOUNT], MODEL_KEY::ACCOUNT}, {MODEL_NAME[MODEL_KEY::VERSION], MODEL_KEY::VERSION}, {MODEL_NAME[MODEL_KEY::DOMAIN], MODEL_KEY::DOMAIN}, /** ccdav keys **/ {MODEL_NAME[MODEL_KEY::N], MODEL_KEY::N}, {MODEL_NAME[MODEL_KEY::IM], MODEL_KEY::IM}, {MODEL_NAME[MODEL_KEY::PHOTO], MODEL_KEY::PHOTO}, {MODEL_NAME[MODEL_KEY::GENDER], MODEL_KEY::GENDER}, {MODEL_NAME[MODEL_KEY::ADR], MODEL_KEY::ADR}, {MODEL_NAME[MODEL_KEY::ADR_2], MODEL_KEY::ADR_2}, {MODEL_NAME[MODEL_KEY::ADR_3], MODEL_KEY::ADR_3}, {MODEL_NAME[MODEL_KEY::EMAIL], MODEL_KEY::EMAIL}, {MODEL_NAME[MODEL_KEY::EMAIL_2], MODEL_KEY::EMAIL_2}, {MODEL_NAME[MODEL_KEY::EMAIL_3], MODEL_KEY::EMAIL_3}, {MODEL_NAME[MODEL_KEY::LANG], MODEL_KEY::LANG}, {MODEL_NAME[MODEL_KEY::NICKNAME], MODEL_KEY::NICKNAME}, {MODEL_NAME[MODEL_KEY::ORG], MODEL_KEY::ORG}, {MODEL_NAME[MODEL_KEY::PROFILE], MODEL_KEY::PROFILE}, {MODEL_NAME[MODEL_KEY::TZ], MODEL_KEY::TZ}, {MODEL_NAME[MODEL_KEY::TEL], MODEL_KEY::TEL}, {MODEL_NAME[MODEL_KEY::TEL_2], MODEL_KEY::TEL_2}, {MODEL_NAME[MODEL_KEY::TEL_3], MODEL_KEY::TEL_3}, {MODEL_NAME[MODEL_KEY::CITY], MODEL_KEY::CITY}, {MODEL_NAME[MODEL_KEY::STATE], MODEL_KEY::STATE}, {MODEL_NAME[MODEL_KEY::COUNTRY], MODEL_KEY::COUNTRY} }; typedef QHash MODEL; typedef QList MODEL_LIST; enum PATHTYPE_KEY : uint_fast8_t { - PLACES_PATH, - DRIVES_PATH, - BOOKMARKS_PATH, - TAGS_PATH, - APPS_PATH, - TRASH_PATH, - SEARCH_PATH, - CLOUD_PATH + PLACES_PATH = KFilePlacesModel::GroupType::PlacesType, + REMOTE_PATH = KFilePlacesModel::GroupType::RemoteType, + DRIVES_PATH = KFilePlacesModel::GroupType::DevicesType, + REMOVABLE_PATH = KFilePlacesModel::GroupType::RemovableDevicesType, + TAGS_PATH = KFilePlacesModel::GroupType::TagsType, + UNKOWN_TYPE = KFilePlacesModel::GroupType::UnknownType, + APPS_PATH = 9, + TRASH_PATH = 10, + SEARCH_PATH = 11, + CLOUD_PATH = 12 }; static const QHash PATHTYPE_NAME = { {PATHTYPE_KEY::PLACES_PATH, "Places"}, {PATHTYPE_KEY::DRIVES_PATH, "Drives"}, - {PATHTYPE_KEY::BOOKMARKS_PATH, "Bookmarks"}, {PATHTYPE_KEY::APPS_PATH, "Apps"}, + {PATHTYPE_KEY::REMOTE_PATH, "Remote"}, + {PATHTYPE_KEY::REMOVABLE_PATH, "Removable"}, + {PATHTYPE_KEY::UNKOWN_TYPE, "Unkown"}, {PATHTYPE_KEY::TRASH_PATH, "Trash"}, {PATHTYPE_KEY::TAGS_PATH, "Tags"}, {PATHTYPE_KEY::SEARCH_PATH, "Search"}, {PATHTYPE_KEY::CLOUD_PATH, "Cloud"} }; const QString DataPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); const QString CloudCachePath = FMH::DataPath+"/Cloud/"; #if defined(Q_OS_ANDROID) const QString PicturesPath = PATHS::PicturesPath; const QString DownloadsPath = PATHS::DownloadsPath; const QString DocumentsPath = PATHS::DocumentsPath; const QString HomePath = PATHS::HomePath; const QString MusicPath = PATHS::MusicPath; const QString VideosPath = PATHS::VideosPath; const QStringList defaultPaths = { HomePath, DocumentsPath, PicturesPath, MusicPath, VideosPath, DownloadsPath }; const QMap folderIcon { {PicturesPath, "folder-pictures"}, {DownloadsPath, "folder-download"}, {DocumentsPath, "folder-documents"}, {HomePath, "user-home"}, {MusicPath, "folder-music"}, {VideosPath, "folder-videos"}, }; #else const QString PicturesPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); const QString DownloadsPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); const QString DocumentsPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); const QString HomePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); const QString MusicPath = QStandardPaths::writableLocation(QStandardPaths::MusicLocation); const QString VideosPath = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); const QString DesktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); const QString AppsPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); const QString RootPath = "/"; const QStringList defaultPaths = { HomePath, DesktopPath, DocumentsPath, PicturesPath, MusicPath, VideosPath, DownloadsPath, RootPath }; const QMap folderIcon { {PicturesPath, "folder-pictures"}, {DownloadsPath, "folder-download"}, {DocumentsPath, "folder-documents"}, {HomePath, "user-home"}, {MusicPath, "folder-music"}, {VideosPath, "folder-videos"}, {DesktopPath, "user-desktop"}, {AppsPath, "system-run"}, {RootPath, "folder-root"} }; #endif inline bool fileExists(const QString &url) { QFileInfo path(url); if (path.exists()) return true; else return false; } inline QVariantMap dirConf(const QString &path) { if(!FMH::fileExists(path)) return QVariantMap(); QString icon, iconsize, hidden, detailview, showthumbnail, showterminal; uint count = 0, sortby = FMH::MODEL_KEY::MODIFIED, viewType = 0; bool foldersFirst = false; #ifdef Q_OS_ANDROID QSettings file(path, QSettings::Format::NativeFormat); file.beginGroup(QString("Desktop Entry")); icon = file.value("Icon").toString(); file.endGroup(); file.beginGroup(QString("Settings")); hidden = file.value("HiddenFilesShown").toString(); file.endGroup(); file.beginGroup(QString("MAUIFM")); iconsize = file.value("IconSize").toString(); detailview = file.value("DetailView").toString(); showthumbnail = file.value("ShowThumbnail").toString(); showterminal = file.value("ShowTerminal").toString(); count = file.value("Count").toInt(); sortby = file.value("SortBy").toInt(); foldersFirst = file.value("FoldersFirst").toBool(); viewType = file.value("ViewType").toInt(); file.endGroup(); #else KConfig file(path); icon = file.entryMap(QString("Desktop Entry"))["Icon"]; hidden = file.entryMap(QString("Settings"))["HiddenFilesShown"]; iconsize = file.entryMap(QString("MAUIFM"))["IconSize"]; detailview = file.entryMap(QString("MAUIFM"))["DetailView"]; showthumbnail = file.entryMap(QString("MAUIFM"))["ShowThumbnail"]; showterminal = file.entryMap(QString("MAUIFM"))["ShowTerminal"]; count = file.entryMap(QString("MAUIFM"))["Count"].toInt(); sortby = file.entryMap(QString("MAUIFM"))["SortBy"].toInt(); foldersFirst = file.entryMap(QString("MAUIFM"))["FoldersFirst"] == "true" ? true : false; viewType = file.entryMap(QString("MAUIFM"))["ViewType"].toInt(); #endif auto res = QVariantMap({ {FMH::MODEL_NAME[FMH::MODEL_KEY::ICON], icon.isEmpty() ? "folder" : icon}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ICONSIZE], iconsize}, {FMH::MODEL_NAME[FMH::MODEL_KEY::COUNT], count}, {FMH::MODEL_NAME[FMH::MODEL_KEY::SHOWTERMINAL], showterminal.isEmpty() ? "false" : showterminal}, {FMH::MODEL_NAME[FMH::MODEL_KEY::SHOWTHUMBNAIL], showthumbnail.isEmpty() ? "false" : showthumbnail}, {FMH::MODEL_NAME[FMH::MODEL_KEY::DETAILVIEW], detailview.isEmpty() ? "false" : detailview}, {FMH::MODEL_NAME[FMH::MODEL_KEY::HIDDEN], hidden.isEmpty() ? false : (hidden == "true" ? true : false)}, {FMH::MODEL_NAME[FMH::MODEL_KEY::SORTBY], sortby}, {FMH::MODEL_NAME[FMH::MODEL_KEY::FOLDERSFIRST], foldersFirst}, {FMH::MODEL_NAME[FMH::MODEL_KEY::VIEWTYPE], viewType} }); return res; } inline void setDirConf(const QString &path, const QString &group, const QString &key, const QVariant &value) { #ifdef Q_OS_ANDROID QSettings file(path, QSettings::Format::IniFormat); file.beginGroup(group); file.setValue(key, value); file.endGroup(); file.sync(); #else KConfig file(path); auto kgroup = file.group(group); kgroup.writeEntry(key, value); #endif } inline QString getIconName(const QString &path) { if(QFileInfo(path).isDir()) { if(folderIcon.contains(path)) return folderIcon[path]; else { auto icon = FMH::dirConf(QString(path+"/%1").arg(".directory"))[FMH::MODEL_NAME[FMH::MODEL_KEY::ICON]].toString(); return icon.isEmpty() ? "folder" : icon; } }else { #if defined(Q_OS_ANDROID) QMimeDatabase mime; auto type = mime.mimeTypeForFile(path); return type.iconName(); #else KFileItem mime(path); return mime.iconName(); #endif } } inline QString getMime(const QString &path) { QMimeDatabase mimedb; auto mime = mimedb.mimeTypeForFile(path).name(); return mime; } enum class TABLE : uint8_t { BOOKMARKS, CLOUDS }; static const QMap TABLEMAP = { {TABLE::BOOKMARKS, "bookmarks"}, {TABLE::CLOUDS, "clouds"} }; typedef QMap DB; const QString FMPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)+"/maui/fm/"; const QString DBName = "fm.db"; inline QVariantMap getDirInfo(const QString &path, const QString &type = QString()) { QFileInfo file (path); if(!file.exists()) return QVariantMap(); QVariantMap data = { {FMH::MODEL_NAME[FMH::MODEL_KEY::ICON], FMH::getIconName(path)}, {FMH::MODEL_NAME[FMH::MODEL_KEY::LABEL], file.baseName()}, {FMH::MODEL_NAME[FMH::MODEL_KEY::PATH], path}, {FMH::MODEL_NAME[FMH::MODEL_KEY::TYPE], type} }; return data; } inline FMH::MODEL getFileInfoModel(const QString &path) { QFileInfo file(path); if(!file.exists()) return FMH::MODEL(); auto mime = FMH::getMime(path); // QLocale locale; FMH::MODEL res = { {FMH::MODEL_KEY::GROUP, file.group()}, {FMH::MODEL_KEY::OWNER, file.owner()}, {FMH::MODEL_KEY::SUFFIX, file.completeSuffix()}, {FMH::MODEL_KEY::LABEL, /*file.isDir() ? file.baseName() :*/ path == FMH::HomePath ? QStringLiteral("Home") : file.fileName()}, {FMH::MODEL_KEY::NAME, file.fileName()}, {FMH::MODEL_KEY::DATE, file.birthTime().toString(Qt::TextDate)}, {FMH::MODEL_KEY::MODIFIED, file.lastModified().toString(Qt::TextDate)}, {FMH::MODEL_KEY::MIME, mime }, {FMH::MODEL_KEY::ICON, FMH::getIconName(path)}, {FMH::MODEL_KEY::SIZE, QString::number(file.size()) /*locale.formattedDataSize(file.size())*/}, {FMH::MODEL_KEY::PATH, path}, {FMH::MODEL_KEY::THUMBNAIL, path}, {FMH::MODEL_KEY::COUNT, file.isDir() ? QString::number(QDir(path).count() - 2) : "0"} }; return res; } inline QVariantMap getFileInfo(const QString &path) { QFileInfo file(path); if(!file.exists()) return QVariantMap(); auto data = FMH::getFileInfoModel(path); QVariantMap res; for(auto key : data.keys()) res.insert(FMH::MODEL_NAME[key], data[key]); return res; } #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif #ifdef STATIC_MAUIKIT class Downloader : public QObject #else class MAUIKIT_EXPORT Downloader : public QObject #endif { Q_OBJECT public: explicit Downloader(QObject *parent = 0) : QObject(parent) { this->manager = new QNetworkAccessManager; } virtual ~Downloader() { qDebug()<< "DELETEING DOWNLOADER"; this->manager->deleteLater(); } void setFile(const QString &fileURL, const QString &fileName = QString()) { QString filePath = fileURL; if(fileName.isEmpty() || fileURL.isEmpty()) return; QNetworkRequest request; request.setUrl(QUrl(fileURL)); reply = manager->get(request); file = new QFile; file->setFileName(fileName); file->open(QIODevice::WriteOnly); connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(onDownloadProgress(qint64,qint64))); connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onFinished(QNetworkReply*))); connect(reply,SIGNAL(readyRead()),this,SLOT(onReadyRead())); connect(reply,SIGNAL(finished()),this,SLOT(onReplyFinished())); } void getArray(const QString &fileURL, const QMap &headers = {}) { if(fileURL.isEmpty()) return; QNetworkRequest request; request.setUrl(QUrl(fileURL)); if(!headers.isEmpty()) { for(auto key: headers.keys()) request.setRawHeader(key.toLocal8Bit(), headers[key].toLocal8Bit()); } reply = manager->get(request); connect(reply, &QNetworkReply::readyRead, [this]() { switch(reply->error()) { case QNetworkReply::NoError: { this->array = reply->readAll(); break; } default: { qDebug() << reply->errorString(); emit this->warning(reply->errorString()); }; } }); connect(reply, &QNetworkReply::finished, [=]() { qDebug() << "Array reply is now finished"; emit this->dataReady(this->array); emit this->done(); }); } private: QNetworkAccessManager *manager; QNetworkReply *reply; QFile *file; QByteArray array; signals: void progress(int percent); void downloadReady(); void fileSaved(QString path); void warning(QString warning); void dataReady(QByteArray array); void done(); private slots: void onDownloadProgress(qint64 bytesRead, qint64 bytesTotal) { emit this->progress((bytesRead * bytesTotal) / 100); } void onFinished(QNetworkReply* reply) { switch(reply->error()) { case QNetworkReply::NoError: { qDebug("file is downloaded successfully."); emit this->downloadReady(); break; } default: { emit this->warning(reply->errorString()); }; } if(file->isOpen()) { file->close(); emit this->fileSaved(file->fileName()); file->deleteLater(); } } void onReadyRead() { file->write(reply->readAll()); // emit this->fileSaved(file->fileName()); } void onReplyFinished() { if(file->isOpen()) { file->close(); // emit this->fileSaved(file->fileName()); file->deleteLater(); } emit done(); } }; } #endif // FMH_H diff --git a/src/fm/fmlist.cpp b/src/fm/fmlist.cpp index f91e1d7..0c330c4 100644 --- a/src/fm/fmlist.cpp +++ b/src/fm/fmlist.cpp @@ -1,870 +1,868 @@ /* * * Copyright (C) 2018 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 "fmlist.h" #include #include "fm.h" #include "utils.h" #include #include #include #include #include #include FMList::FMList(QObject *parent) : QObject(parent) { this->fm = new FM(this); connect(this->fm, &FM::cloudServerContentReady, [this](const FMH::MODEL_LIST &list, const QString &url) { if(this->path == url) { this->pre(); this->list = list; this->pathEmpty = this->list.isEmpty(); emit this->pathEmptyChanged(); this->pos(); this->setContentReady(true); } }); connect(this->fm, &FM::warningMessage, [this](const QString &message) { emit this->warning(message); }); connect(this->fm, &FM::loadProgress, [this](const int &percent) { emit this->progress(percent); }); this->watcher = new QFileSystemWatcher(this); connect(this->watcher, &QFileSystemWatcher::directoryChanged, [this](const QString &path) { Q_UNUSED(path); this->reset(); }); connect(this->fm, &FM::newItem, [this] (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); 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) { if(!this->watcher->directories().isEmpty() && clear) this->watcher->removePaths(this->watcher->directories()); if(path.isEmpty() || !FMH::fileExists(path)) return; this->watcher->addPath(path); } void FMList::setList() { this->setContentReady(true); switch(this->pathType) { case FMList::PATHTYPE::PLACES_PATH: this->list.clear(); this->setContentReady(false); this->getPathContent(); return; //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); 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; case FMList::PATHTYPE::TRASH_PATH: case FMList::PATHTYPE::DRIVES_PATH: - case FMList::PATHTYPE::BOOKMARKS_PATH: this->list = FMH::MODEL_LIST(); 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; } case FMList::PATHTYPE::TRASH_PATH: case FMList::PATHTYPE::DRIVES_PATH: - case FMList::PATHTYPE::BOOKMARKS_PATH: break; } if(this->saveDirProps) { auto conf = FMH::dirConf(this->path+"/.directory"); this->sort = static_cast(conf[FMH::MODEL_NAME[FMH::MODEL_KEY::SORTBY]].toInt()); this->viewType = static_cast(conf[FMH::MODEL_NAME[FMH::MODEL_KEY::VIEWTYPE]].toInt()); }else { this->sort = static_cast(UTIL::loadSettings("SortBy", "SETTINGS", this->sort).toInt()); this->viewType = static_cast(UTIL::loadSettings("ViewType", "SETTINGS", this->viewType).toInt()); } emit this->sortByChanged(); emit this->viewTypeChanged(); emit this->hiddenChanged(); emit this->previewChanged(); 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::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; if(path.startsWith(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::SEARCH_PATH]+"/")) { this->pathExists = true; this->pathType = FMList::PATHTYPE::SEARCH_PATH; - this->isBookmark = false; +// this->isBookmark = false; emit this->pathExistsChanged(); emit this->pathTypeChanged(); emit this->isBookmarkChanged(); this->watchPath(QString()); }else if(path.startsWith(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::CLOUD_PATH]+"/")) { this->pathExists = true; this->pathType = FMList::PATHTYPE::CLOUD_PATH; - this->isBookmark = false; +// this->isBookmark = false; emit this->pathExistsChanged(); emit this->pathTypeChanged(); emit this->isBookmarkChanged(); this->watchPath(QString()); }else if(path.startsWith(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::APPS_PATH]+"/")) { this->pathExists = true; this->pathType = FMList::PATHTYPE::APPS_PATH; - this->isBookmark = false; +// this->isBookmark = false; emit this->pathExistsChanged(); emit this->pathTypeChanged(); emit this->isBookmarkChanged(); this->watchPath(QString()); }else if(path.startsWith(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::TAGS_PATH]+"/")) { this->pathExists = true; - this->isBookmark = false; +// this->isBookmark = false; this->pathType = FMList::PATHTYPE::TAGS_PATH; emit this->pathExistsChanged(); emit this->pathTypeChanged(); emit this->isBookmarkChanged(); this->watchPath(QString()); }else { this->watchPath(this->path); - this->isBookmark = this->fm->isBookmark(this->path); +// this->isBookmark = this->fm->isBookmark(this->path); this->pathExists = FMH::fileExists(this->path); this->pathType = FMList::PATHTYPE::PLACES_PATH; emit this->pathExistsChanged(); emit this->pathTypeChanged(); emit this->isBookmarkChanged(); } emit this->pathChanged(); } 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(); QVariantMap res; const auto model = this->list.at(index); for(auto key : model.keys()) res.insert(FMH::MODEL_NAME[key], model[key]); return res; } 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_NAME[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::test() { this->fm->sync->upload("", ""); } 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); // } } QString FMList::getParentPath() { switch(this->pathType) { case FMList::PATHTYPE::PLACES_PATH: return FM::parentDir(this->path); 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::getIsBookmark() const { return this->isBookmark; } void FMList::setIsBookmark(const bool& value) { if(this->isBookmark == value) return; if(this->pathType != FMList::PATHTYPE::PLACES_PATH) return; this->isBookmark = value; if(value) this->fm->bookmark(this->path); else this->fm->removeBookmark(this->path); emit this->isBookmarkChanged(); } bool FMList::getFoldersFirst() const { return this->foldersFirst; } void FMList::setFoldersFirst(const bool &value) { if(this->foldersFirst == value) return; this->pre(); this->foldersFirst = value; if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) FMH::setDirConf(this->path+"/.directory", "MAUIFM", "FoldersFirst", this->foldersFirst); else UTIL::saveSettings("FoldersFirst", this->foldersFirst, "SETTINGS"); emit this->foldersFirstChanged(); this->sortList(); this->pos(); } void FMList::setSaveDirProps(const bool& value) { if(this->saveDirProps == value) return; this->saveDirProps = value; UTIL::saveSettings("SaveDirProps", this->saveDirProps, "SETTINGS"); emit this->saveDirPropsChanged(); } bool FMList::getSaveDirProps() const { return this->saveDirProps; } void FMList::setContentReady(const bool& value) { this->contentReady = value; emit this->contentReadyChanged(); } bool FMList::getContentReady() const { return this->contentReady; } FMList::VIEW_TYPE FMList::getViewType() const { return this->viewType; } void FMList::setViewType(const FMList::VIEW_TYPE& value) { if(this->viewType == value) return; this->viewType = value; if(this->trackChanges && this->saveDirProps) FMH::setDirConf(this->path+"/.directory", "MAUIFM", "ViewType", this->viewType); else UTIL::saveSettings("ViewType", this->viewType, "SETTINGS"); emit this->viewTypeChanged(); } void FMList::search(const QString& query, const QString &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) { 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([=]() -> PathContent { PathContent res; res.path = path; FMH::MODEL_LIST content; if (FM::isDir(path)) { QDir::Filters dirFilter; dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); if(hidden) dirFilter = dirFilter | QDir::Hidden | QDir::System; QDirIterator it (path, filters, dirFilter, QDirIterator::Subdirectories); while (it.hasNext()) { auto url = it.next(); auto info = it.fileInfo(); if(info.completeBaseName().contains(query, Qt::CaseInsensitive)) content << FMH::getFileInfoModel(url); } } res.content = content; return res; }); watcher->setFuture(t1); } void FMList::getPathContent() { qDebug()<< "Getting async path contents"; QFutureWatcher *watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, [=]() { if(this->pathType != FMList::PATHTYPE::PLACES_PATH) return; const auto res = watcher->future().result(); if(res.path != this->path) return; emit this->preListChanged(); this->list = res.content; this->pathEmpty = this->list.isEmpty() && FM::fileExists(this->path); emit this->pathEmptyChanged(); this->sortList(); emit this->postListChanged(); this->setContentReady(true); watcher->deleteLater(); }); QFuture t1 = QtConcurrent::run([=]() -> PathContent { PathContent res; res.path = this->path; res.content = FM::getPathContent(this->path, this->hidden, this->onlyDirs, this->filters); return res; }); watcher->setFuture(t1); } int FMList::getCloudDepth() const { return this->cloudDepth; } void FMList::setCloudDepth(const int& value) { if(this->cloudDepth == value) return; this->cloudDepth = value; emit this->cloudDepthChanged(); this->reset(); } diff --git a/src/fm/fmlist.h b/src/fm/fmlist.h index 9281ebe..98010d5 100644 --- a/src/fm/fmlist.h +++ b/src/fm/fmlist.h @@ -1,255 +1,256 @@ /* * * 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" struct PathContent { QString path; FMH::MODEL_LIST content; }; class FM; class QFileSystemWatcher; class FMList : public QObject { Q_OBJECT Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged()) Q_PROPERTY(bool hidden READ getHidden WRITE setHidden NOTIFY hiddenChanged()) Q_PROPERTY(bool onlyDirs READ getOnlyDirs WRITE setOnlyDirs NOTIFY onlyDirsChanged()) Q_PROPERTY(bool preview READ getPreview WRITE setPreview NOTIFY previewChanged()) Q_PROPERTY(FMList::VIEW_TYPE viewType READ getViewType WRITE setViewType NOTIFY viewTypeChanged()) Q_PROPERTY(int cloudDepth READ getCloudDepth WRITE setCloudDepth NOTIFY cloudDepthChanged()) Q_PROPERTY(bool isBookmark READ getIsBookmark WRITE setIsBookmark NOTIFY isBookmarkChanged()) 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, + REMOTE_PATH = FMH::PATHTYPE_KEY::REMOTE_PATH, DRIVES_PATH = FMH::PATHTYPE_KEY::DRIVES_PATH, - BOOKMARKS_PATH = FMH::PATHTYPE_KEY::BOOKMARKS_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; FMList::SORTBY getSortBy() const; void setSortBy(const FMList::SORTBY &key); QString getPath() const; void setPath(const QString &path); 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 getIsBookmark() const; void setIsBookmark(const bool &value); bool getFoldersFirst() const; void setFoldersFirst(const bool &value); bool getSaveDirProps() const; void setSaveDirProps(const bool &value); bool getContentReady() const; void setContentReady(const bool &value); VIEW_TYPE getViewType() const; void setViewType(const VIEW_TYPE &value); int getCloudDepth() const; void setCloudDepth(const int &value); private: FM *fm; QFileSystemWatcher *watcher; void pre(); void pos(); void reset(); void setList(); void sortList(); void watchPath(const QString &path, const bool &clear = true); void search(const QString &query, const QString &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); void getPathContent(); FMH::MODEL_LIST list = {{}}; QString path = QString(); QStringList filters = {}; bool onlyDirs = false; bool hidden = false; bool preview = false; bool pathExists = false; bool pathEmpty = true; bool trackChanges = true; bool isBookmark = false; bool foldersFirst = false; bool saveDirProps = false; bool contentReady = false; int cloudDepth = 1; QString searchPath; VIEW_TYPE viewType = VIEW_TYPE::ICON_VIEW; FMList::SORTBY sort = FMList::SORTBY::MODIFIED; FMList::FILTER filterType = FMList::FILTER::NONE; FMList::PATHTYPE pathType = FMList::PATHTYPE::PLACES_PATH; QStringList prevHistory = {}; QStringList postHistory = {}; public slots: QVariantMap get(const int &index) const; void refresh(); void createDir(const QString &name); void copyInto(const QVariantList &files); void cutInto(const QVariantList &files); void test(); signals: void pathChanged(); void pathTypeChanged(); void filtersChanged(); void filterTypeChanged(); void hiddenChanged(); void previewChanged(); void onlyDirsChanged(); void sortByChanged(); void trackChangesChanged(); void isBookmarkChanged(); void foldersFirstChanged(); void saveDirPropsChanged(); void contentReadyChanged(); void viewTypeChanged(); void cloudDepthChanged(); void pathEmptyChanged(); void pathExistsChanged(); void preItemAppended(); void postItemAppended(); void preItemRemoved(int index); void postItemRemoved(); void updateModel(int index, QVector roles); void preListChanged(); void postListChanged(); void warning(QString message); void progress(int percent); void searchResultReady(); }; #endif // FMLIST_H diff --git a/src/fm/placeslist.cpp b/src/fm/placeslist.cpp index 5b6458c..9b00194 100644 --- a/src/fm/placeslist.cpp +++ b/src/fm/placeslist.cpp @@ -1,195 +1,219 @@ /* * * Copyright (C) 2018 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 "placeslist.h" #include "fm.h" - +#include #include #include #include -PlacesList::PlacesList(QObject *parent) : QObject(parent) +PlacesList::PlacesList(QObject *parent) : QObject(parent), model(new KFilePlacesModel(this)) { this->fm = new FM(this); this->watcher = new QFileSystemWatcher(this); connect(watcher, &QFileSystemWatcher::directoryChanged, [this](const QString &path) { if(this->count.contains(path)) { // QEventLoop loop; // QTimer timer; // connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); // // timer.setSingleShot(true); // timer.setInterval(1000); auto oldCount = this->count[path]; const auto index = this->indexOf(path); // timer.start(); // loop.exec(); // timer.stop(); auto newCount = FM::getPathContent(path, true, false).size(); auto count = newCount - oldCount; this->list[index][FMH::MODEL_KEY::COUNT] = QString::number(count); emit this->updateModel(index, {FMH::MODEL_KEY::COUNT}); } }); connect(fm, &FM::bookmarkInserted, this, &PlacesList::reset); connect(fm, &FM::bookmarkRemoved, this, &PlacesList::reset); connect(fm, &FM::cloudAccountInserted, this, &PlacesList::reset); connect(fm, &FM::cloudAccountRemoved, this, &PlacesList::reset); connect(this, &PlacesList::groupsChanged, this, &PlacesList::reset); this->setList(); } void PlacesList::watchPath(const QString& path) { if(path.isEmpty() || !FMH::fileExists(path)) return; this->watcher->addPath(path); } PlacesList::~PlacesList() { } FMH::MODEL_LIST PlacesList::items() const { return this->list; } +static FMH::MODEL_LIST getGroup(const KFilePlacesModel *model,const FMH::PATHTYPE_KEY &type) +{ + const auto group = model->groupIndexes(static_cast(type)); + return std::accumulate(group.begin(), group.end(), FMH::MODEL_LIST(), [&model, &type](FMH::MODEL_LIST &list, const QModelIndex &index) -> FMH::MODEL_LIST + { + list << FMH::MODEL + { + {FMH::MODEL_KEY::PATH, model->url(index).toString().replace("file://", "")}, + {FMH::MODEL_KEY::URL, model->url(index).toString().replace("file://", "")}, + {FMH::MODEL_KEY::ICON, model->icon(index).name()}, + {FMH::MODEL_KEY::LABEL, model->text(index)}, + {FMH::MODEL_KEY::NAME, model->text(index)}, + {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_NAME[type]} + }; + + return list; + + }); +} + void PlacesList::setList() { this->list.clear(); - for(auto group : this->groups) + for(const auto &group : this->groups) switch(group) { case FMH::PATHTYPE_KEY::PLACES_PATH: - this->list << FM::getDefaultPaths(); + this->list << getGroup(this->model, FMH::PATHTYPE_KEY::PLACES_PATH); break; case FMH::PATHTYPE_KEY::APPS_PATH: - this->list << FM::getCustomPaths(); - break; - - case FMH::PATHTYPE_KEY::BOOKMARKS_PATH: - this->list << this->fm->getBookmarks(); + this->list << FM::getAppsPath(); break; case FMH::PATHTYPE_KEY::DRIVES_PATH: - this->list << FM::getDevices(); + this->list << getGroup(this->model, FMH::PATHTYPE_KEY::DRIVES_PATH); + break; + + case FMH::PATHTYPE_KEY::REMOTE_PATH: + this->list << getGroup(this->model, FMH::PATHTYPE_KEY::REMOTE_PATH); + break; + + case FMH::PATHTYPE_KEY::REMOVABLE_PATH: + this->list << getGroup(this->model, FMH::PATHTYPE_KEY::REMOVABLE_PATH); break; case FMH::PATHTYPE_KEY::TAGS_PATH: this->list << this->fm->getTags(); break; case FMH::PATHTYPE_KEY::CLOUD_PATH: this->list << this->fm->getCloudAccounts(); break; } this->setCount(); } void PlacesList::setCount() { this->watcher->removePaths(this->watcher->directories()); for(auto &data : this->list) { auto path = data[FMH::MODEL_KEY::PATH]; if(FM::isDir(path)) { auto count = FM::getPathContent(path, true, false).size(); data.insert(FMH::MODEL_KEY::COUNT, "0"); this->count.insert(path, count); this->watchPath(path); } } } int PlacesList::indexOf(const QString& path) { int i = -1; for(auto data : this->list) { i++; if(data[FMH::MODEL_KEY::PATH] == path) break; } return i; } void PlacesList::reset() { emit this->preListChanged(); this->setList(); emit this->postListChanged(); } QList PlacesList::getGroups() const { return this->groups; } void PlacesList::setGroups(const QList &value) { if(this->groups == value) return; this->groups = value; emit this->groupsChanged(); } QVariantMap PlacesList::get(const int& index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); QVariantMap res; const auto model = this->list.at(index); for(auto key : model.keys()) res.insert(FMH::MODEL_NAME[key], model[key]); return res; } void PlacesList::refresh() { this->reset(); } void PlacesList::clearBadgeCount(const int& index) { this->list[index][FMH::MODEL_KEY::COUNT] = "0"; emit this->updateModel(index, {FMH::MODEL_KEY::COUNT}); } diff --git a/src/fm/placeslist.h b/src/fm/placeslist.h index f9ddbd3..f7c4477 100644 --- a/src/fm/placeslist.h +++ b/src/fm/placeslist.h @@ -1,74 +1,76 @@ /* * * Copyright (C) 2018 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 . */ #ifndef PLACESLIST_H #define PLACESLIST_H #include +#include #include "fmh.h" class QFileSystemWatcher; class FM; class PlacesList : public QObject { Q_OBJECT Q_PROPERTY(QList groups READ getGroups WRITE setGroups NOTIFY groupsChanged()) public: PlacesList(QObject *parent = nullptr); ~PlacesList(); FMH::MODEL_LIST items() const; QList getGroups() const; void setGroups(const QList &value); protected: void setList(); void reset(); public slots: QVariantMap get(const int &index) const; void refresh(); void clearBadgeCount(const int &index); private: FM *fm; FMH::MODEL_LIST list; + KFilePlacesModel *model; QHash count; QList groups; QFileSystemWatcher *watcher; void watchPath(const QString &path); void setCount(); int indexOf(const QString &path); signals: void groupsChanged(); void preItemAppended(); void postItemAppended(); void preItemRemoved(int index); void postItemRemoved(); void updateModel(int index, QVector roles); void preListChanged(); void postListChanged(); }; #endif // PLACESLIST_H