diff --git a/src/controls/private/BrowserView.qml b/src/controls/private/BrowserView.qml index f2746cb..a085946 100644 --- a/src/controls/private/BrowserView.qml +++ b/src/controls/private/BrowserView.qml @@ -1,663 +1,667 @@ import QtQuick 2.9 import QtQuick.Controls 2.9 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Page { id: control property url path onPathChanged: if(control.currentView) control.currentView.currentIndex = 0 property Maui.FMList currentFMList property Maui.BaseModel currentFMModel property alias currentView : viewLoader.item property int viewType property string filter height: _browserList.height width: _browserList.width function setCurrentFMList() { control.currentFMList = currentView.currentFMList control.currentFMModel = currentView.currentFMModel currentView.forceActiveFocus() } Menu { id: _dropMenu property string urls property url target enabled: Maui.FM.getFileInfo(target).isdir == "true" && !urls.includes(target.toString()) MenuItem { text: qsTr("Copy here") onTriggered: { const urls = _dropMenu.urls.split(",") for(var i in urls) Maui.FM.copy(urls[i], _dropMenu.target, false) } } MenuItem { text: qsTr("Move here") onTriggered: { const urls = _dropMenu.urls.split(",") for(var i in urls) Maui.FM.cut(urls[i], _dropMenu.target) } } MenuItem { text: qsTr("Link here") onTriggered: { const urls = _dropMenu.urls.split(",") for(var i in urls) Maui.FM.createSymlink(_dropMenu.source[i], urls.target) } } } Loader { id: viewLoader anchors.fill: parent focus: true - sourceComponent: listViewBrowser + sourceComponent: switch(control.viewType) + { + case Maui.FMList.ICON_VIEW: return gridViewBrowser + case Maui.FMList.LIST_VIEW: return listViewBrowser + case Maui.FMList.MILLERS_VIEW: return millerViewBrowser + } onLoaded: setCurrentFMList() } Maui.FMList { id: _commonFMList path: control.path onSortByChanged: if(group) groupBy() onlyDirs: settings.onlyDirs filterType: settings.filterType filters: settings.filters sortBy: settings.sortBy } Component { id: listViewBrowser Maui.ListBrowser { id: _listViewBrowser property alias currentFMList : _browserModel.list property alias currentFMModel : _browserModel topMargin: Maui.Style.contentMargins showPreviewThumbnails: settings.showThumbnails keepEmblemOverlay: settings.selectionMode showDetailsInfo: true BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize model: Maui.BaseModel { id: _browserModel list: _commonFMList filter: control.filter recursiveFilteringEnabled: true sortCaseSensitivity: Qt.CaseInsensitive filterCaseSensitivity: Qt.CaseInsensitive } section.delegate: Maui.LabelDelegate { id: delegate width: parent.width height: Maui.Style.toolBarHeightAlt label: String(section).toUpperCase() labelTxt.font.pointSize: Maui.Style.fontSizes.big isSection: true } delegate: Maui.ListBrowserDelegate { id: delegate width: parent.width height: _listViewBrowser.itemSize + Maui.Style.space.big leftPadding: Maui.Style.space.small rightPadding: leftPadding padding: 0 showDetailsInfo: _listViewBrowser.showDetailsInfo folderSize : _listViewBrowser.itemSize showTooltip: true showEmblem: _listViewBrowser.showEmblem keepEmblemOverlay : _listViewBrowser.keepEmblemOverlay showThumbnails: _listViewBrowser.showPreviewThumbnails rightEmblem: _listViewBrowser.rightEmblem isSelected: selectionBar ? selectionBar.contains(model.path) : false leftEmblem: isSelected ? "list-remove" : "list-add" draggable: true Maui.Badge { iconName: "link" anchors.left: parent.left anchors.bottom: parent.bottom visible: (model.issymlink == true) || (model.issymlink == "true") } Connections { target: selectionBar onUriRemoved: { if(uri === model.path) delegate.isSelected = false } onUriAdded: { if(uri === model.path) delegate.isSelected = true } onCleared: delegate.isSelected = false } Connections { target: delegate onClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemClicked(index) } onDoubleClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemDoubleClicked(index) } onPressAndHold: { _listViewBrowser.currentIndex = index _listViewBrowser.itemRightClicked(index) } onRightClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemRightClicked(index) } onRightEmblemClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.rightEmblemClicked(index) } onLeftEmblemClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.leftEmblemClicked(index) } onContentDropped: { _dropMenu.urls = drop.urls.join(",") _dropMenu.target = model.path _dropMenu.popup() } } } } } Component { id: gridViewBrowser Maui.GridBrowser { id: _gridViewBrowser property alias currentFMList : _browserModel.list property alias currentFMModel : _browserModel itemSize : thumbnailsSize + Maui.Style.fontSizes.default cellHeight: itemSize * 1.5 keepEmblemOverlay: settings.selectionMode showPreviewThumbnails: settings.showThumbnails - supportsRefreshing: true - + BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize model: Maui.BaseModel { id: _browserModel list: _commonFMList filter: control.filter recursiveFilteringEnabled: true sortCaseSensitivity: Qt.CaseInsensitive filterCaseSensitivity: Qt.CaseInsensitive } delegate: Maui.GridBrowserDelegate { id: delegate folderSize: height * 0.5 height: _gridViewBrowser.cellHeight width: _gridViewBrowser.cellWidth padding: Maui.Style.space.tiny showTooltip: true showEmblem: _gridViewBrowser.showEmblem keepEmblemOverlay: _gridViewBrowser.keepEmblemOverlay showThumbnails: _gridViewBrowser.showPreviewThumbnails rightEmblem: _gridViewBrowser.rightEmblem isSelected: selectionBar ? selectionBar.contains(model.path) : false leftEmblem: isSelected ? "list-remove" : "list-add" draggable: true Maui.Badge { iconName: "link" anchors.left: parent.left anchors.bottom: parent.bottom anchors.bottomMargin: Maui.Style.space.big visible: (model.issymlink == true) || (model.issymlink == "true") } Connections { target: selectionBar onUriRemoved: { if(uri === model.path) delegate.isSelected = false } onUriAdded: { if(uri === model.path) delegate.isSelected = true } onCleared: delegate.isSelected = false } Connections { target: delegate onClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemClicked(index) } onDoubleClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemDoubleClicked(index) } onPressAndHold: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemRightClicked(index) } onRightClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemRightClicked(index) } onRightEmblemClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.rightEmblemClicked(index) } onLeftEmblemClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.leftEmblemClicked(index) } onContentDropped: { _dropMenu.urls = drop.urls.join(",") _dropMenu.target = model.path _dropMenu.popup() } } } } } Component { id: millerViewBrowser Item { id: _millerControl property Maui.FMList currentFMList property Maui.BaseModel currentFMModel property int currentIndex signal itemClicked(int index) signal itemDoubleClicked(int index) signal itemRightClicked(int index) signal keyPress(var event) signal rightEmblemClicked(int index) signal leftEmblemClicked(int index) signal areaClicked(var mouse) signal areaRightClicked() ListView { id: _millerColumns anchors.fill: parent boundsBehavior: !Maui.Handy.isTouch? Flickable.StopAtBounds : Flickable.OvershootBounds keyNavigationEnabled: true interactive: Maui.Handy.isTouch orientation: ListView.Horizontal snapMode: ListView.SnapToItem ScrollBar.horizontal: ScrollBar { id: _scrollBar snapMode: ScrollBar.SnapAlways policy: ScrollBar.AlwaysOn contentItem: Rectangle { implicitWidth: _scrollBar.interactive ? 13 : 4 implicitHeight: _scrollBar.interactive ? 13 : 4 color: "#333" opacity: _scrollBar.pressed ? 0.7 : _scrollBar.interactive && _scrollBar.hovered ? 0.5 : 0.2 radius: 0 } background: Rectangle { implicitWidth: _scrollBar.interactive ? 16 : 4 implicitHeight: _scrollBar.interactive ? 16 : 4 color: "#0e000000" opacity: 0.0 visible: _scrollBar.interactive radius: 0 } } onCurrentItemChanged: { _millerControl.currentFMList = currentItem.currentFMList _millerControl.currentFMModel = currentItem.currentFMModel control.setCurrentFMList() currentItem.forceActiveFocus() } onCountChanged: { _millerColumns.currentIndex = _millerColumns.count-1 _millerColumns.positionViewAtEnd() } Maui.PathList { id: _millerList path: control.path onPathChanged: { _millerColumns.currentIndex = _millerColumns.count-1 _millerColumns.positionViewAtEnd() } } model: Maui.BaseModel { id: _millerModel list: _millerList } delegate: Item { property alias currentFMList : _millersFMList property alias currentFMModel : _millersFMModel property int _index : index width: Math.min(Kirigami.Units.gridUnit * 22, control.width) height: parent.height focus: true function forceActiveFocus() { _millerListView.forceActiveFocus() } Kirigami.Separator { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right width: 1 z: 999 } Maui.FMList { id: _millersFMList path: model.path onlyDirs: settings.onlyDirs filterType: settings.filterType filters: settings.filters sortBy: settings.sortBy } Maui.ListBrowser { id: _millerListView anchors.fill: parent topMargin: Maui.Style.contentMargins showPreviewThumbnails: settings.showThumbnails keepEmblemOverlay: settings.selectionMode showDetailsInfo: true onKeyPress: _millerControl.keyPress(event) currentIndex : 0 onCurrentIndexChanged: _millerControl.currentIndex = currentIndex BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize section.delegate: Maui.LabelDelegate { id: delegate width: parent.width height: Maui.Style.toolBarHeightAlt label: String(section).toUpperCase() labelTxt.font.pointSize: Maui.Style.fontSizes.big isSection: true } onAreaClicked: { _millerColumns.currentIndex = _index _millerControl.areaClicked(mouse) } onAreaRightClicked: { _millerColumns.currentIndex = _index _millerControl.areaRightClicked() } model: Maui.BaseModel { id: _millersFMModel list: _millersFMList filter: control.filter recursiveFilteringEnabled: true sortCaseSensitivity: Qt.CaseInsensitive filterCaseSensitivity: Qt.CaseInsensitive } delegate: Maui.ListBrowserDelegate { id: delegate width: parent.width height: _millerListView.itemSize + Maui.Style.space.big leftPadding: Maui.Style.space.small rightPadding: leftPadding padding: 0 showDetailsInfo: _millerListView.showDetailsInfo folderSize : _millerListView.itemSize showTooltip: true showEmblem: _millerListView.showEmblem keepEmblemOverlay : _millerListView.keepEmblemOverlay showThumbnails: _millerListView.showPreviewThumbnails rightEmblem: _millerListView.rightEmblem isSelected: selectionBar ? selectionBar.contains(model.path) : false leftEmblem: isSelected ? "list-remove" : "list-add" draggable: true Maui.Badge { iconName: "link" anchors.left: parent.left anchors.bottom: parent.bottom visible: (model.issymlink == true) || (model.issymlink == "true") } Connections { target: selectionBar onUriRemoved: { if(uri === model.path) delegate.isSelected = false } onUriAdded: { if(uri === model.path) delegate.isSelected = true } onCleared: delegate.isSelected = false } Connections { target: delegate onClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemClicked(index) } onDoubleClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemDoubleClicked(index) } onPressAndHold: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemRightClicked(index) } onRightClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemRightClicked(index) } onRightEmblemClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.rightEmblemClicked(index) } onLeftEmblemClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.leftEmblemClicked(index) } onContentDropped: { _dropMenu.urls = drop.urls.join(",") _dropMenu.target = model.path _dropMenu.popup() } } } } } } } } } diff --git a/src/fm/fm.cpp b/src/fm/fm.cpp index 08c452c..bfac460 100644 --- a/src/fm/fm.cpp +++ b/src/fm/fm.cpp @@ -1,511 +1,531 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fm.h" #ifdef COMPONENT_TAGGING #include "tagging.h" #endif #ifdef COMPONENT_SYNCING #include "syncing.h" #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #elif defined Q_OS_LINUX #include "mauikde.h" #include #include #include #include #include #include #include #include #endif + +QDirLister::QDirLister(QObject* parent) : QObject(parent) +{} + +bool QDirLister::openUrl(QUrl url) +{ + qDebug() << "GET FILES <<" << m_nameFilters.split(" "); + FMH::MODEL_LIST content; + + if (FMStatic::isDir(url)) + { + QDir::Filters dirFilter; + + dirFilter = (m_dirOnly ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : + QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); + + if(m_showDotFiles) + dirFilter = dirFilter | QDir::Hidden | QDir::System; + + QDirIterator it (url.toLocalFile(), m_nameFilters.isEmpty() ? QStringList() : m_nameFilters.split(" "), dirFilter, QDirIterator::NoIteratorFlags); + while (it.hasNext()) + { + const auto item = FMH::getFileInfoModel(QUrl::fromLocalFile(it.next())); + content << item; + + emit itemReady(item, url); + } + } else return false; + + emit itemsReady(content, url); + return true; +} + +void QDirLister::setDirOnlyMode(bool value) +{ + m_dirOnly = value; +} + +void QDirLister::setShowingDotFiles(bool value) +{ + m_showDotFiles = value; +} + +void QDirLister::setNameFilter(QString filters) +{ + m_nameFilters = filters; +} + + FM::FM(QObject *parent) : QObject(parent) #ifdef COMPONENT_SYNCING ,sync(new Syncing(this)) #endif #ifdef COMPONENT_TAGGING ,tag(Tagging::getInstance()) #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) -,dirLister(new KCoreDirLister(this)) +,dirLister( new KCoreDirLister(this)) +#else +,dirLister( new QDirLister) #endif -{ - +{ #ifdef Q_OS_ANDROID MAUIAndroid::checkRunTimePermissions({"android.permission.WRITE_EXTERNAL_STORAGE"}); #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) this->dirLister->setAutoUpdate(true); const static auto packItem = [](const KFileItem &kfile) -> FMH::MODEL { return FMH::MODEL{ {FMH::MODEL_KEY::LABEL, kfile.name()}, {FMH::MODEL_KEY::NAME, kfile.name()}, {FMH::MODEL_KEY::DATE, kfile.time(KFileItem::FileTimes::CreationTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::MODIFIED, kfile.time(KFileItem::FileTimes::ModificationTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::LAST_READ, kfile.time(KFileItem::FileTimes::AccessTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::PATH, kfile.mostLocalUrl().toString()}, {FMH::MODEL_KEY::THUMBNAIL, kfile.localPath()}, {FMH::MODEL_KEY::SYMLINK, kfile.linkDest()}, {FMH::MODEL_KEY::IS_SYMLINK, QVariant(kfile.isLink()).toString()}, {FMH::MODEL_KEY::HIDDEN, QVariant(kfile.isHidden()).toString()}, {FMH::MODEL_KEY::IS_DIR, QVariant(kfile.isDir()).toString()}, {FMH::MODEL_KEY::IS_FILE, QVariant(kfile.isFile()).toString()}, {FMH::MODEL_KEY::WRITABLE, QVariant(kfile.isWritable()).toString()}, {FMH::MODEL_KEY::READABLE, QVariant(kfile.isReadable()).toString()}, {FMH::MODEL_KEY::EXECUTABLE, QVariant(kfile.isDesktopFile()).toString()}, {FMH::MODEL_KEY::MIME, kfile.mimetype()}, {FMH::MODEL_KEY::GROUP, kfile.group()}, {FMH::MODEL_KEY::ICON, kfile.iconName()}, {FMH::MODEL_KEY::SIZE, QString::number(kfile.size())}, {FMH::MODEL_KEY::THUMBNAIL, kfile.mostLocalUrl().toString()}, {FMH::MODEL_KEY::OWNER, kfile.user()}, // {FMH::MODEL_KEY::FAVORITE, QVariant(this->urlTagExists(kfile.mostLocalUrl().toString(), "fav")).toString()}, {FMH::MODEL_KEY::COUNT, kfile.isLocalFile() && kfile.isDir() ? QString::number(QDir(kfile.localPath()).count() - 2) : "0"} }; }; const static auto packItems = [](const KFileItemList &items) -> FMH::MODEL_LIST { return std::accumulate(items.constBegin(), items.constEnd(), FMH::MODEL_LIST(), [](FMH::MODEL_LIST &res, const KFileItem &item) ->FMH::MODEL_LIST { res << packItem(item); return res; }); }; - connect(dirLister, static_cast(&KCoreDirLister::completed), [&](QUrl url) + connect(dirLister, static_cast(&KCoreDirLister::completed), this, [&](QUrl url) { qDebug()<< "PATH CONTENT READY" << url; emit this->pathContentReady(url); }); - connect(dirLister, static_cast(&KCoreDirLister::itemsAdded), [&](QUrl dirUrl, KFileItemList items) + connect(dirLister, static_cast(&KCoreDirLister::itemsAdded), this, [&](QUrl dirUrl, KFileItemList items) { qDebug()<< "MORE ITEMS WERE ADDED"; emit this->pathContentItemsReady({dirUrl, packItems(items)}); }); // connect(dirLister, static_cast(&KCoreDirLister::newItems), [&](KFileItemList items) // { // qDebug()<< "MORE NEW ITEMS WERE ADDED"; // for(const auto &item : items) // qDebug()<< "MORE <<" << item.url(); // // emit this->pathContentChanged(dirLister->url()); // }); - connect(dirLister, static_cast(&KCoreDirLister::itemsDeleted), [&](KFileItemList items) + connect(dirLister, static_cast(&KCoreDirLister::itemsDeleted), this, [&](KFileItemList items) { qDebug()<< "ITEMS WERE DELETED"; emit this->pathContentItemsRemoved({dirLister->url(), packItems(items)}); }); - connect(dirLister, static_cast > &items)>(&KCoreDirLister::refreshItems), [&](QList< QPair< KFileItem, KFileItem > > items) + connect(dirLister, static_cast > &items)>(&KCoreDirLister::refreshItems), this, [&](QList< QPair< KFileItem, KFileItem > > items) { qDebug()<< "ITEMS WERE REFRESHED"; const auto res = std::accumulate(items.constBegin(), items.constEnd(), QVector>(), [](QVector> &list, const QPair &pair) -> QVector> { list << QPair{packItem(pair.first), packItem(pair.second)}; return list; }); - emit this->pathContentItemsChanged(res); - }); - #endif - + emit this->pathContentItemsChanged(res); + }); + #else + connect(dirLister, &QDirLister::itemReady, this, [&](FMH::MODEL item, QUrl url) + { + emit this->pathContentItemsReady(FMH::PATH_CONTENT {url, {item}}); + }); + + connect(dirLister, &QDirLister::itemsReady, this, [&](FMH::MODEL_LIST, QUrl url) + { + emit this->pathContentReady(url); + }); + #endif + #ifdef COMPONENT_SYNCING connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QUrl &url) { emit this->cloudServerContentReady(list, url); }); connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QUrl &url, const Syncing::SIGNAL_TYPE &signalType) { switch(signalType) { case Syncing::SIGNAL_TYPE::OPEN: FMStatic::openUrl(item[FMH::MODEL_KEY::PATH]); break; case Syncing::SIGNAL_TYPE::DOWNLOAD: emit this->cloudItemReady(item, url); break; case Syncing::SIGNAL_TYPE::COPY: { QVariantMap data; for(auto key : item.keys()) data.insert(FMH::MODEL_NAME[key], item[key]); // this->copy(QVariantList {data}, this->sync->getCopyTo()); break; } default: return; } }); connect(this->sync, &Syncing::error, [this](const QString &message) { emit this->warningMessage(message); }); connect(this->sync, &Syncing::progress, [this](const int &percent) { emit this->loadProgress(percent); }); connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QUrl &url) { emit this->newItem(dir, url); }); connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QUrl &url) { emit this->newItem(item, url); }); #endif } void FM::getPathContent(const QUrl& path, const bool &hidden, const bool &onlyDirs, const QStringList& filters, const QDirIterator::IteratorFlags &iteratorFlags) { qDebug()<< "Getting async path contents"; - - #if defined Q_OS_ANDROID || defined Q_OS_WIN32 - QFutureWatcher *watcher = new QFutureWatcher; - connect(watcher, &QFutureWatcher::finished, [this, watcher]() - { - const auto res = watcher->future().result(); - emit this->pathContentItemsReady(res); - emit this->pathContentReady(res.path); - watcher->deleteLater(); - }); - - QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT - { - FMH::PATH_CONTENT res; - res.path = path; - - FMH::MODEL_LIST content; - - if (FMStatic::isDir(path)) - { - QDir::Filters dirFilter; - - dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : - QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); - - if(hidden) - dirFilter = dirFilter | QDir::Hidden | QDir::System; - - QDirIterator it (path.toLocalFile(), filters, dirFilter, iteratorFlags); - while (it.hasNext()) - content << FMH::getFileInfoModel(QUrl::fromLocalFile(it.next())); - } - - res.content = content; - return res; - }); - watcher->setFuture(t1); - #else - + this->dirLister->setShowingDotFiles(hidden); this->dirLister->setDirOnlyMode(onlyDirs); this->dirLister->setNameFilter(filters.join(" ")); if(this->dirLister->openUrl(path)) qDebug()<< "GETTING PATH CONTENT" << path; - - #endif - + } FMH::MODEL_LIST FM::getAppsPath() { #if defined Q_OS_ANDROID || defined Q_OS_WIN32 return FMH::MODEL_LIST(); #else return FMH::MODEL_LIST { FMH::MODEL { {FMH::MODEL_KEY::ICON, "system-run"}, {FMH::MODEL_KEY::LABEL, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::APPS_PATH]}, {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::APPS_PATH]}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]} } }; #endif } FMH::MODEL_LIST FM::getTags(const int &limit) { Q_UNUSED(limit); FMH::MODEL_LIST data; #ifdef COMPONENT_TAGGING if(this->tag) { for(const auto &tag : this->tag->getAllTags(false)) { QVariantMap item = tag.toMap(); const auto label = item.value(TAG::KEYMAP[TAG::KEYS::TAG]).toString(); data << FMH::MODEL { {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::TAGS_PATH]+label}, {FMH::MODEL_KEY::ICON, "tag"}, {FMH::MODEL_KEY::MODIFIED, QDateTime::fromString(item.value(TAG::KEYMAP[TAG::KEYS::ADD_DATE]).toString(), Qt::TextDate).toString()}, {FMH::MODEL_KEY::IS_DIR, "true"}, {FMH::MODEL_KEY::LABEL, label}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::TAGS_PATH]} }; } } #endif return data; } bool FM::getCloudServerContent(const QUrl &path, const QStringList &filters, const int &depth) { #ifdef COMPONENT_SYNCING const auto __list = path.toString().replace("cloud:///", "/").split("/"); if(__list.isEmpty() || __list.size() < 2) { qWarning()<< "Could not parse username to get cloud server content"; return false; } auto user = __list[1]; // auto data = this->get(QString("select * from clouds where user = '%1'").arg(user)); QVariantList data; if(data.isEmpty()) return false; auto map = data.first().toMap(); user = map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString(); auto server = map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString(); auto password = map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString(); this->sync->setCredentials(server, user, password); this->sync->listContent(path, filters, depth); return true; #else return false; #endif } void FM::createCloudDir(const QString &path, const QString &name) { #ifdef COMPONENT_SYNCING this->sync->createDir(path, name); #endif } void FM::openCloudItem(const QVariantMap &item) { #ifdef COMPONENT_SYNCING FMH::MODEL data; for(const auto &key : item.keys()) data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::OPEN); #endif } void FM::getCloudItem(const QVariantMap &item) { #ifdef COMPONENT_SYNCING this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::DOWNLOAD); #endif } QString FM::resolveUserCloudCachePath(const QString &server, const QString &user) { return FMH::CloudCachePath+"opendesktop/"+user; } QString FM::resolveLocalCloudPath(const QString& path) { #ifdef COMPONENT_SYNCING return QString(path).replace(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+this->sync->getUser(), ""); #else return QString(); #endif } static bool doNameFilter(const QString &name, const QStringList &filters) { for(const auto &filter : std::accumulate(filters.constBegin(), filters.constEnd(), QVector {}, [](QVector &res, const QString &filter) -> QVector { res.append(QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard)); return res; })) { if(filter.exactMatch(name)) { return true; } } return false; } FMH::MODEL_LIST FM::getTagContent(const QString &tag, const QStringList &filters) { FMH::MODEL_LIST content; #ifdef COMPONENT_TAGGING if(tag.isEmpty()) { return this->getTags(); }else { for(const auto &data : this->tag->getUrls(tag, false, [filters](QVariantMap &item) -> bool { return filters.isEmpty() ? true : doNameFilter(FMH::mapValue(item, FMH::MODEL_KEY::URL), filters); })) { const auto url = QUrl(data.toMap()[TAG::KEYMAP[TAG::KEYS::URL]].toString()); if(url.isLocalFile() && !FMH::fileExists(url)) continue; content << FMH::getFileInfoModel(url); } } #endif return content; } FMH::MODEL_LIST FM::getUrlTags(const QUrl &url) { FMH::MODEL_LIST content; #ifdef COMPONENT_TAGGING content = FMH::toModelList(this->tag->getUrlTags(url.toString(), false)); #endif return content; } bool FM::urlTagExists(const QUrl& url, const QString tag) { #ifdef COMPONENT_TAGGING return this->tag->urlTagExists(url.toString(), tag, false); #endif } bool FM::addTagToUrl(const QString tag, const QUrl& url) { #ifdef COMPONENT_TAGGING return this->tag->tagUrl(url.toString(), tag); #endif } bool FM::removeTagToUrl(const QString tag, const QUrl& url) { #ifdef COMPONENT_TAGGING return this->tag->removeUrlTag(url.toString(), tag); #endif } bool FM::cut(const QList &urls, const QUrl &where) { for(const auto &url : urls) { if(FMStatic::isCloud(url.toString())) { #ifdef COMPONENT_SYNCING this->sync->setCopyTo(where.toString()); // this->sync->resolveFile(url, Syncing::SIGNAL_TYPE::COPY); #endif }else { FMStatic::cut(url, where); } } return true; } bool FM::copy(const QList &urls, const QUrl &where) { QStringList cloudPaths; for(const auto &url : urls) { if(FMStatic::isDir(url)) { FMStatic::copy(url, where.toString()+"/"+QFileInfo(url.toLocalFile()).fileName(), false); }else if(FMStatic::isCloud(url)) { #ifdef COMPONENT_SYNCING this->sync->setCopyTo(where.toString()); // this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); #endif }else { if(FMStatic::isCloud(where)) cloudPaths << url.toString(); else FMStatic::copy(url, where.toString()+"/"+FMH::getFileInfoModel(url)[FMH::MODEL_KEY::LABEL], false); } } #ifdef COMPONENT_SYNCING if(!cloudPaths.isEmpty()) { qDebug()<<"UPLOAD QUEUE" << cloudPaths; const auto firstPath = cloudPaths.takeLast(); this->sync->setUploadQueue(cloudPaths); if(where.toString().split("/").last().contains(".")) { QStringList whereList = where.toString().split("/"); whereList.removeLast(); auto whereDir = whereList.join("/"); qDebug()<< "Trying ot copy to cloud" << where << whereDir; this->sync->upload(this->resolveLocalCloudPath(whereDir), firstPath); } else this->sync->upload(this->resolveLocalCloudPath(where.toString()), firstPath); } #endif return true; } diff --git a/src/fm/fm.h b/src/fm/fm.h index 62cadc1..0377a3c 100644 --- a/src/fm/fm.h +++ b/src/fm/fm.h @@ -1,93 +1,118 @@ #ifndef FM_H #define FM_H #include #include #include #include #include #include #include "fmh.h" #include "fmstatic.h" #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) class KCoreDirLister; #endif +class QDirLister : public QObject +{ + Q_OBJECT +public: + explicit QDirLister(QObject *parent = nullptr); + +public slots: + bool openUrl(QUrl url); + void setNameFilter(QString filters); + void setDirOnlyMode(bool value); + void setShowingDotFiles(bool value); + +signals: + void itemsReady(FMH::MODEL_LIST items, QUrl url); + void itemReady(FMH::MODEL item, QUrl url); + +private: + QString m_nameFilters; + QUrl m_url; + bool m_dirOnly = false; + bool m_showDotFiles = false; +}; + class Syncing; class Tagging; #ifdef STATIC_MAUIKIT class FM : public QObject #else class MAUIKIT_EXPORT FM : public QObject #endif { Q_OBJECT public: Syncing *sync; FM(QObject *parent = nullptr); FMH::MODEL_LIST getTags(const int &limit = 5); FMH::MODEL_LIST getTagContent(const QString &tag, const QStringList &filters = {}); FMH::MODEL_LIST getUrlTags(const QUrl &url); bool urlTagExists(const QUrl& url, const QString tag); bool addTagToUrl(const QString tag, const QUrl &url); bool removeTagToUrl(const QString tag, const QUrl &url); /** Syncing **/ bool getCloudServerContent(const QUrl &server, const QStringList &filters= QStringList(), const int &depth = 0); Q_INVOKABLE void createCloudDir(const QString &path, const QString &name); void getPathContent(const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags); QString resolveLocalCloudPath(const QString &path); static FMH::MODEL_LIST getAppsPath(); static QString resolveUserCloudCachePath(const QString &server, const QString &user); private: #ifdef COMPONENT_TAGGING Tagging *tag; - #endif - - #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) - KCoreDirLister *dirLister; - #endif + #endif + + #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + KCoreDirLister *dirLister; + #else + QDirLister *dirLister; + #endif signals: void cloudServerContentReady(FMH::MODEL_LIST list, const QUrl &url); void cloudItemReady(FMH::MODEL item, QUrl path); //when a item is downloaded and ready void pathContentReady(QUrl path); void pathContentItemsReady(FMH::PATH_CONTENT list); void pathContentChanged(QUrl path); void pathContentItemsChanged(QVector> items); void pathContentItemsRemoved(FMH::PATH_CONTENT list); void warningMessage(QString message); void loadProgress(int percent); void dirCreated(FMH::MODEL dir); void newItem(FMH::MODEL item, QUrl path); // when a new item is created public slots: void openCloudItem(const QVariantMap &item); void getCloudItem(const QVariantMap &item); /* ACTIONS */ bool copy(const QList &urls, const QUrl &where); bool cut(const QList &urls, const QUrl &where); friend class FMStatic; }; #endif // FM_H diff --git a/src/fm/fmlist.cpp b/src/fm/fmlist.cpp index 14645d6..60d3aa6 100644 --- a/src/fm/fmlist.cpp +++ b/src/fm/fmlist.cpp @@ -1,869 +1,867 @@ /* * * Copyright (C) 2018 camilo higuita * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "fmlist.h" #include "fm.h" #include "utils.h" #include #include #ifdef COMPONENT_SYNCING #include "syncing.h" #endif #if defined Q_OS_LINUX && !defined Q_OS_ANDROID #include #endif #include #include #include #include FMList::FMList(QObject *parent) : MauiList(parent), fm(new FM(this)), watcher(new QFileSystemWatcher(this)) { connect(this->fm, &FM::cloudServerContentReady, [&](const FMH::MODEL_LIST &list, const QUrl &url) { if(this->path == url) { this->assignList(list); } }); connect(this->fm, &FM::pathContentReady, [&](QUrl path) { emit this->preListChanged(); - this->sortList(); + this->sortList(); this->setStatus({STATUS_CODE::READY, this->list.isEmpty() ? "Nothing here!" : "", this->list.isEmpty() ? "This place seems to be empty" : "",this->list.isEmpty() ? "folder-add" : "", this->list.isEmpty(), true}); emit this->postListChanged(); }); connect(this->fm, &FM::pathContentItemsChanged, [&](QVector> res) { for(const auto &item : res) { const auto index = this->indexOf(FMH::MODEL_KEY::PATH, item.first[FMH::MODEL_KEY::PATH]); if(index > this->list.size() || index < 0) return; this->list[index] = item.second; this->updateModel(index, FMH::modelRoles(item.second)); } }); connect(this->fm, &FM::pathContentItemsReady, [&](FMH::PATH_CONTENT res) { this->appendToList(res.content); }); connect(this->fm, &FM::pathContentItemsRemoved, [&](FMH::PATH_CONTENT res) { if(res.path != this->path) return; for(const auto &item : res.content) { const auto index = this->indexOf(FMH::MODEL_KEY::PATH, item[FMH::MODEL_KEY::PATH]); qDebug() << "SUPOSSED TO REMOVED THIS FORM THE LIST" << index << item[FMH::MODEL_KEY::PATH] << this->list[index]; ; this->remove(index); } }); connect(this->fm, &FM::warningMessage, [&](const QString &message) { emit this->warning(message); }); connect(this->fm, &FM::loadProgress, [&](const int &percent) { emit this->progress(percent); }); // with kio based on android it watches the directory itself, so better relay on that #ifdef Q_OS_ANDROID connect(this->watcher, &QFileSystemWatcher::directoryChanged, [&](const QString &path) { qDebug()<< "FOLDER PATH CHANGED" << path; this->reset(); }); #else connect(this->fm, &FM::pathContentChanged, [&](const QUrl &path) { qDebug()<< "FOLDER PATH CHANGED" << path; if(path != this->path) return; this->sortList(); }); #endif connect(this->fm, &FM::newItem, [&] (const FMH::MODEL &item, const QUrl &url) { if(this->path == url) { emit this->preItemAppended(); this->list << item; emit this->postItemAppended(); } }); const auto value = UTIL::loadSettings("SaveDirProps", "SETTINGS", this->saveDirProps).toBool(); this->setSaveDirProps(value); connect(this, &FMList::pathChanged, this, &FMList::reset); } void FMList::watchPath(const QString& path, const bool& clear) { #ifdef Q_OS_ANDROID if(!this->watcher->directories().isEmpty() && clear) this->watcher->removePaths(this->watcher->directories()); if(path.isEmpty() || !FMH::fileExists(path) || !QUrl(path).isLocalFile()) return; this->watcher->addPath(QString(path).replace("file://", "")); qDebug()<< "WATCHING PATHS" << this->watcher->directories(); #else Q_UNUSED(path) Q_UNUSED(clear) #endif } void FMList::assignList(const FMH::MODEL_LIST& list) { emit this->preListChanged(); this->list =list; this->sortList(); this->count = static_cast(this->list.size()); emit this->countChanged(); this->setStatus({STATUS_CODE::READY, this->list.isEmpty() ? "Nothing here!" : "", this->list.isEmpty() ? "This place seems to be empty" : "",this->list.isEmpty() ? "folder-add" : "", this->list.isEmpty(), true}); emit this->postListChanged(); } void FMList::appendToList(const FMH::MODEL_LIST& list) { for(const auto &item : list) { emit this->preItemAppended(); this->list << item; this->count = static_cast(this->list.size()); emit this->countChanged(); emit this->postItemAppended(); } } void FMList::clear() { emit this->preListChanged(); this->list.clear(); emit this->postListChanged(); } void FMList::setList() { qDebug()<< "PATHTYPE FOR URL"<< pathType << this->path.toString() << this->filters << this; switch(this->pathType) { case FMList::PATHTYPE::SEARCH_PATH: this->search(this->path.fileName(), this->searchPath, this->hidden, this->onlyDirs, this->filters); break; //ASYNC case FMList::PATHTYPE::TAGS_PATH: this->assignList(this->fm->getTagContent(this->path.fileName(), QStringList() <filters << FMH::FILTER_LIST[static_cast(this->filterType)])); break; //SYNC case FMList::PATHTYPE::CLOUD_PATH: this->fm->getCloudServerContent(this->path.toString(), this->filters, this->cloudDepth); break; //ASYNC default: { this->clear(); const bool exists = this->path.isLocalFile() ? FMH::fileExists(this->path) : true; if(!exists) this->setStatus({STATUS_CODE::ERROR, "Error", "This URL cannot be listed", "documentinfo", this->list.isEmpty(), exists}); else{ this->fm->getPathContent(this->path, this->hidden, this->onlyDirs, QStringList() <filters << FMH::FILTER_LIST[static_cast(this->filterType)]); } break;//ASYNC } } } void FMList::reset() { if(this->saveDirProps) { auto conf = FMH::dirConf(this->path.toString()+"/.directory"); this->sort = static_cast(conf[FMH::MODEL_NAME[FMH::MODEL_KEY::SORTBY]].toInt()); this->hidden = conf[FMH::MODEL_NAME[FMH::MODEL_KEY::HIDDEN]].toBool(); this->foldersFirst = conf[FMH::MODEL_NAME[FMH::MODEL_KEY::FOLDERSFIRST]].toBool(); }else { this->hidden = UTIL::loadSettings("HiddenFilesShown", "SETTINGS", this->hidden).toBool(); this->foldersFirst = UTIL::loadSettings("FoldersFirst", "SETTINGS", this->foldersFirst).toBool(); this->sort = static_cast(UTIL::loadSettings("SortBy", "SETTINGS", this->sort).toInt()); } emit this->sortByChanged(); emit this->hiddenChanged(); emit this->foldersFirstChanged(); this->setList(); } 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; emit this->preListChanged(); this->sort = key; this->sortList(); if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) FMH::setDirConf(this->path.toString()+"/.directory", "MAUIFM", "SortBy", this->sort); else UTIL::saveSettings("SortBy", this->sort, "SETTINGS"); emit this->sortByChanged(); emit this->postListChanged(); } void FMList::sortList() { const 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(const auto &item : this->list) if(item[FMH::MODEL_KEY::MIME] == "inode/directory") index++; else break; std::sort(this->list.begin(),this->list.begin() + index, [&key](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool { switch(key) { case FMH::MODEL_KEY::SIZE: { if(e1[key].toDouble() > e2[key].toDouble()) return true; break; } case FMH::MODEL_KEY::MODIFIED: case FMH::MODEL_KEY::DATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[key], Qt::TextDate); auto date2 = QDateTime::fromString(e2[key], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::LABEL: { const auto str1 = QString(e1[key]).toLower(); const auto str2 = QString(e2[key]).toLower(); if(str1 < str2) return true; break; } default: if(e1[key] < e2[key]) return true; } return false; }); } std::sort(this->list.begin() + index, this->list.end(), [key](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool - { - const auto role = key; - - switch(role) + { + switch(key) { case FMH::MODEL_KEY::MIME: - if(e1[role] == "inode/directory") + if(e1[key] == "inode/directory") return true; break; case FMH::MODEL_KEY::SIZE: { - if(e1[role].toDouble() > e2[role].toDouble()) + if(e1[key].toDouble() > e2[key].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); + auto date1 = QDateTime::fromString(e1[key], Qt::TextDate); + auto date2 = QDateTime::fromString(e2[key], 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(); + const auto str1 = QString(e1[key]).toLower(); + const auto str2 = QString(e2[key]).toLower(); if(str1 < str2) return true; break; } default: - if(e1[role] < e2[role]) + if(e1[key] < e2[key]) return true; } return false; }); } QString FMList::getPathName() const { return this->pathName; } QUrl FMList::getPath() const { return this->path; } void FMList::setPath(const QUrl &path) { if(this->path == path) return; this->searchPath = this->path; this->path = path; NavHistory.appendPath(this->path); this->setStatus({STATUS_CODE::LOADING, "Loading content", "Almost ready!", "view-refresh", true, false}); const auto __scheme = this->path.scheme(); this->pathName = this->path.fileName(); if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::SEARCH_PATH]) { this->pathType = FMList::PATHTYPE::SEARCH_PATH; this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]) { this->pathType = FMList::PATHTYPE::CLOUD_PATH; this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::APPS_PATH]) { this->pathType = FMList::PATHTYPE::APPS_PATH; this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::TAGS_PATH]) { this->pathType = FMList::PATHTYPE::TAGS_PATH; this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::TRASH_PATH]) { this->pathType = FMList::PATHTYPE::TRASH_PATH; this->pathName = "Trash"; this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::PLACES_PATH]) { this->watchPath(this->path.toString()); this->pathType = FMList::PATHTYPE::PLACES_PATH; this->pathName = FMH::getDirInfoModel(this->path)[FMH::MODEL_KEY::LABEL]; }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::MTP_PATH]) { this->pathType = FMList::PATHTYPE::MTP_PATH; }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::FISH_PATH] ) { this->pathType = FMList::PATHTYPE::FISH_PATH; }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::REMOTE_PATH] ) { this->pathType = FMList::PATHTYPE::REMOTE_PATH; }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::DRIVES_PATH] ) { this->pathType = FMList::PATHTYPE::DRIVES_PATH; }else { this->pathType = FMList::PATHTYPE::OTHER_PATH; } emit this->pathNameChanged(); emit this->pathTypeChanged(); 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) { if(this->filterType == type) return; this->filterType = type; 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.toString()+"/.directory", "Settings", "HiddenFilesShown", this->hidden); else UTIL::saveSettings("HiddenFilesShown", this->hidden, "SETTINGS"); emit this->hiddenChanged(); this->reset(); } 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(); return FMH::toMap(this->list.at(this->mappedIndex(index))); } void FMList::refresh() { emit this->pathChanged(); } void FMList::createDir(const QString& name) { if(this->pathType == FMList::PATHTYPE::CLOUD_PATH) { #ifdef COMPONENT_SYNCING this->fm->createCloudDir(QString(this->path.toString()).replace(FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]+"/"+this->fm->sync->getUser(), ""), name); #endif }else { FMStatic::createDir(this->path, name); } } void FMList::copyInto(const QStringList& urls) { this->fm->copy(QUrl::fromStringList(urls), this->path); } void FMList::cutInto(const QStringList& urls) { this->fm->cut(QUrl::fromStringList(urls), this->path); // else if(this->pathType == FMList::PATHTYPE::CLOUD_PATH) // { // this->fm->createCloudDir(QString(this->path).replace(FMH::PATHTYPE_NAME[FMList::PATHTYPE::CLOUD_PATH]+"/"+this->fm->sync->getUser(), ""), name); // } } void FMList::setDirIcon(const int &index, const QString &iconName) { if(index >= this->list.size() || index < 0) return; const auto index_ = this->mappedIndex(index); const auto path = QUrl(this->list.at(index_)[FMH::MODEL_KEY::PATH]); if(!FMStatic::isDir(path)) return; FMH::setDirConf(path.toString()+"/.directory", "Desktop Entry", "Icon", iconName); this->list[index_][FMH::MODEL_KEY::ICON] = iconName; emit this->updateModel(index_, QVector {FMH::MODEL_KEY::ICON}); } const QUrl FMList::getParentPath() { switch(this->pathType) { case FMList::PATHTYPE::PLACES_PATH: return FMStatic::parentDir(this->path).toString(); default: return this->getPreviousPath(); } } QList FMList::getPosteriorPathHistory() { return QList (); // todo : implement signal } QList FMList::getPreviousPathHistory() { return QList (); // todo : implement signal } const QUrl FMList::getPosteriorPath() { const auto url = NavHistory.getPosteriorPath(); if(url.isEmpty()) return this->path; return url; } const QUrl FMList::getPreviousPath() { const auto url = NavHistory.getPreviousPath(); if(url.isEmpty()) return this->path; return url; } bool FMList::getTrackChanges() const { return this->trackChanges; } void FMList::setTrackChanges(const bool& value) { if(this->trackChanges == value) return; this->trackChanges = value; emit this->trackChangesChanged(); } bool FMList::getFoldersFirst() const { return this->foldersFirst; } void FMList::setFoldersFirst(const bool &value) { if(this->foldersFirst == value) return; emit this->preListChanged(); this->foldersFirst = value; if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) FMH::setDirConf(this->path.toString()+"/.directory", "MAUIFM", "FoldersFirst", this->foldersFirst); else UTIL::saveSettings("FoldersFirst", this->foldersFirst, "SETTINGS"); emit this->foldersFirstChanged(); this->sortList(); emit this->postListChanged(); } 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::search(const QString& query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) { qDebug()<< "SEARCHING FOR" << query << path; if(!path.isLocalFile()) { qWarning() << "URL recived is not a local file. So search will only filter the content" << path; this->filterContent(query, path, hidden, onlyDirs, filters); return; } QFutureWatcher *watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, [=]() { if(this->pathType != FMList::PATHTYPE::SEARCH_PATH) return; const auto res = watcher->future().result(); if(res.path != this->searchPath.toString()) return; this->assignList(res.content); emit this->searchResultReady(); watcher->deleteLater(); }); QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT { FMH::PATH_CONTENT res; res.path = path.toString(); res.content = FMStatic::search(query, path, hidden, onlyDirs, filters); return res; }); watcher->setFuture(t1); } void FMList::filterContent(const QString &query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) { if(this->list.isEmpty()) { qDebug() << "Can not filter content. List is empty"; return; } QFutureWatcher *watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, [=]() { if(this->pathType != FMList::PATHTYPE::SEARCH_PATH) return; const auto res = watcher->future().result(); if(res.path != this->searchPath.toString()) return; this->assignList(res.content); emit this->searchResultReady(); watcher->deleteLater(); }); QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT { FMH::MODEL_LIST m_content; FMH::PATH_CONTENT res; for(const auto &item : this->list) { if(item[FMH::MODEL_KEY::LABEL].contains(query, Qt::CaseInsensitive) || item[FMH::MODEL_KEY::SUFFIX].contains(query, Qt::CaseInsensitive) || item[FMH::MODEL_KEY::MIME].contains(query, Qt::CaseInsensitive)) { if(onlyDirs && item[FMH::MODEL_KEY::IS_DIR] == "true") { m_content << item; continue; } m_content << item; } } res.path = path.toString(); res.content = m_content; return res; }); watcher->setFuture(t1); } int FMList::getCloudDepth() const { return this->cloudDepth; } void FMList::setCloudDepth(const int& value) { if(this->cloudDepth == value) return; this->cloudDepth = value; emit this->cloudDepthChanged(); this->reset(); } uint FMList::getCount() const { return this->count; } PathStatus FMList::getStatus() const { return this->m_status; } void FMList::setStatus(const PathStatus &status) { this->m_status = status; emit this->statusChanged(); } bool FMList::itemIsFav(const QUrl &path) { return FMStatic::isFav(path); } bool FMList::favItem(const QUrl &path) { return FMStatic::toggleFav(path); } void FMList::deleteFile(const int& index) { if(index > this->list.size() || index < 0) return; FMStatic::removeFile(this->list[this->mappedIndex(index)][FMH::MODEL_KEY::PATH]); this->remove(index); } void FMList::moveFileToTrash(const int& index) { if(index > this->list.size() || index < 0) return; FMStatic::moveToTrash(this->list[this->mappedIndex(index)][FMH::MODEL_KEY::PATH]); this->remove(index); } void FMList::remove(const int& index) { if(index > this->list.size() || index < 0) return; const auto index_ = this->mappedIndex(index); emit this->preItemRemoved(index_); const auto item = this->list.takeAt(index_); this->count = static_cast(this->list.size()); emit this->countChanged(); emit this->postItemRemoved(); }