diff --git a/src/fm/fm.cpp b/src/fm/fm.cpp index 8c0e362..f0857bc 100644 --- a/src/fm/fm.cpp +++ b/src/fm/fm.cpp @@ -1,494 +1,507 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fm.h" #ifdef COMPONENT_TAGGING #include "tagging.h" #endif #ifdef COMPONENT_SYNCING #include "syncing.h" #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #elif defined Q_OS_LINUX #include "mauikde.h" #include #include #include #include #include #include #include #include #endif FM::FM(QObject *parent) : QObject(parent) #ifdef COMPONENT_SYNCING ,sync(new Syncing(this)) #endif #ifdef COMPONENT_TAGGING ,tag(Tagging::getInstance()) #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) ,dirLister(new KCoreDirLister(this)) #endif { #ifdef Q_OS_ANDROID MAUIAndroid::checkRunTimePermissions(); #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) this->dirLister->setAutoUpdate(true); connect(dirLister, static_cast(&KCoreDirLister::completed), [&](QUrl url) { qDebug()<< "PATH CONTENT READY" << url; FMH::PATH_CONTENT res; FMH::MODEL_LIST content; for(const auto &kfile : dirLister->items()) { content << FMH::MODEL{ {FMH::MODEL_KEY::LABEL, kfile.name()}, {FMH::MODEL_KEY::NAME, kfile.name()}, {FMH::MODEL_KEY::DATE, kfile.time(KFileItem::FileTimes::CreationTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::MODIFIED, kfile.time(KFileItem::FileTimes::ModificationTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::LAST_READ, kfile.time(KFileItem::FileTimes::AccessTime).toString(Qt::TextDate)}, {FMH::MODEL_KEY::PATH, kfile.mostLocalUrl().toString()}, {FMH::MODEL_KEY::THUMBNAIL, kfile.localPath()}, {FMH::MODEL_KEY::SYMLINK, kfile.linkDest()}, {FMH::MODEL_KEY::IS_SYMLINK, QVariant(kfile.isLink()).toString()}, {FMH::MODEL_KEY::HIDDEN, QVariant(kfile.isHidden()).toString()}, {FMH::MODEL_KEY::IS_DIR, QVariant(kfile.isDir()).toString()}, {FMH::MODEL_KEY::IS_FILE, QVariant(kfile.isFile()).toString()}, {FMH::MODEL_KEY::WRITABLE, QVariant(kfile.isWritable()).toString()}, {FMH::MODEL_KEY::READABLE, QVariant(kfile.isReadable()).toString()}, {FMH::MODEL_KEY::EXECUTABLE, QVariant(kfile.isDesktopFile()).toString()}, {FMH::MODEL_KEY::MIME, kfile.mimetype()}, {FMH::MODEL_KEY::GROUP, kfile.group()}, {FMH::MODEL_KEY::ICON, kfile.iconName()}, {FMH::MODEL_KEY::SIZE, QString::number(kfile.size())}, {FMH::MODEL_KEY::THUMBNAIL, kfile.mostLocalUrl().toString()}, - {FMH::MODEL_KEY::OWNER, kfile.user()}, -// {FMH::MODEL_KEY::FAVORITE, QVariant(this->urlTagExists(kfile.mostLocalUrl().toString(), "fav")).toString()}, - {FMH::MODEL_KEY::COUNT, kfile.isLocalFile() && kfile.isDir() ? QString::number(QDir(kfile.localPath()).count() - 2) : "0"} + {FMH::MODEL_KEY::OWNER, kfile.user()}, + // {FMH::MODEL_KEY::FAVORITE, QVariant(this->urlTagExists(kfile.mostLocalUrl().toString(), "fav")).toString()}, + {FMH::MODEL_KEY::COUNT, kfile.isLocalFile() && kfile.isDir() ? QString::number(QDir(kfile.localPath()).count() - 2) : "0"} }; } res.path = url; res.content = content; emit this->pathContentReady(res); }); connect(dirLister, static_cast(&KCoreDirLister::itemsAdded), [&]() { qDebug()<< "MORE ITEMS WERE ADDED"; emit this->pathContentChanged(dirLister->url()); }); connect(dirLister, static_cast(&KCoreDirLister::newItems), [&]() { qDebug()<< "MORE NEW ITEMS WERE ADDED"; emit this->pathContentChanged(dirLister->url()); }); connect(dirLister, static_cast(&KCoreDirLister::itemsDeleted), [&]() { qDebug()<< "ITEMS WERE DELETED"; dirLister->updateDirectory(dirLister->url()); // emit this->pathContentChanged(dirLister->url()); // changes when dleted items are not that important? }); connect(dirLister, static_cast > &items)>(&KCoreDirLister::refreshItems), [&]() { qDebug()<< "ITEMS WERE REFRESHED"; dirLister->updateDirectory(dirLister->url()); emit this->pathContentChanged(dirLister->url()); }); #endif #ifdef COMPONENT_SYNCING connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QUrl &url) { emit this->cloudServerContentReady(list, url); }); connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QUrl &url, const Syncing::SIGNAL_TYPE &signalType) { switch(signalType) { case Syncing::SIGNAL_TYPE::OPEN: FMStatic::openUrl(item[FMH::MODEL_KEY::PATH]); break; case Syncing::SIGNAL_TYPE::DOWNLOAD: emit this->cloudItemReady(item, url); break; case Syncing::SIGNAL_TYPE::COPY: { QVariantMap data; for(auto key : item.keys()) data.insert(FMH::MODEL_NAME[key], item[key]); -// this->copy(QVariantList {data}, this->sync->getCopyTo()); + // this->copy(QVariantList {data}, this->sync->getCopyTo()); break; } default: return; } }); connect(this->sync, &Syncing::error, [this](const QString &message) { emit this->warningMessage(message); }); connect(this->sync, &Syncing::progress, [this](const int &percent) { emit this->loadProgress(percent); }); connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QUrl &url) { emit this->newItem(dir, url); }); connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QUrl &url) { emit this->newItem(item, url); }); #endif } FM::~FM() {} void FM::getPathContent(const QUrl& path, const bool &hidden, const bool &onlyDirs, const QStringList& filters, const QDirIterator::IteratorFlags &iteratorFlags) { qDebug()<< "Getting async path contents"; #if defined Q_OS_ANDROID || defined Q_OS_WIN32 QFutureWatcher *watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, [this, watcher = std::move(watcher)]() { emit this->pathContentReady(watcher->future().result()); watcher->deleteLater(); }); QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT { FMH::PATH_CONTENT res; res.path = path; FMH::MODEL_LIST content; if (FMStatic::isDir(path)) { QDir::Filters dirFilter; dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); if(hidden) dirFilter = dirFilter | QDir::Hidden | QDir::System; QDirIterator it (path.toLocalFile(), filters, dirFilter, iteratorFlags); while (it.hasNext()) content << FMH::getFileInfoModel(QUrl::fromLocalFile(it.next())); } res.content = content; return res; }); watcher->setFuture(t1); #else this->dirLister->setShowingDotFiles(hidden); this->dirLister->setDirOnlyMode(onlyDirs); - + this->dirLister->setNameFilter(filters.join(" ")); qDebug() << "NAME FILTERS SET" << this->dirLister->nameFilter(); // if(this->dirLister->url() == path) // { // this->dirLister->emitChanges(); // return; // } if(this->dirLister->openUrl(path)) qDebug()<< "GETTING PATH CONTENT" << path; #endif } FMH::MODEL_LIST FM::getAppsPath() { #if defined Q_OS_ANDROID || defined Q_OS_WIN32 return FMH::MODEL_LIST(); #else return FMH::MODEL_LIST { FMH::MODEL { {FMH::MODEL_KEY::ICON, "system-run"}, {FMH::MODEL_KEY::LABEL, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::APPS_PATH]}, {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::APPS_PATH]}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]} } }; #endif } FMH::MODEL_LIST FM::getTags(const int &limit) { Q_UNUSED(limit); FMH::MODEL_LIST data; #ifdef COMPONENT_TAGGING if(this->tag) { for(const auto &tag : this->tag->getAllTags(false)) { - QVariantMap item = tag.toMap(); + 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::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)); + // 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) -{ + void FM::createCloudDir(const QString &path, const QString &name) + { #ifdef COMPONENT_SYNCING - this->sync->createDir(path, name); + this->sync->createDir(path, name); #endif -} + } -void FM::openCloudItem(const QVariantMap &item) -{ + 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()); + 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); + this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::OPEN); #endif -} + } -void FM::getCloudItem(const QVariantMap &item) -{ + void FM::getCloudItem(const QVariantMap &item) + { #ifdef COMPONENT_SYNCING - this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::DOWNLOAD); + 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::resolveUserCloudCachePath(const QString &server, const QString &user) + { + return FMH::CloudCachePath+"opendesktop/"+user; + } -QString FM::resolveLocalCloudPath(const QString& path) -{ + QString FM::resolveLocalCloudPath(const QString& path) + { #ifdef COMPONENT_SYNCING - return QString(path).replace(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+this->sync->getUser(), ""); + return QString(path).replace(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+this->sync->getUser(), ""); #else - return QString(); + return QString(); #endif -} + } -FMH::MODEL_LIST FM::getTagContent(const QString &tag) -{ - FMH::MODEL_LIST content; - #ifdef COMPONENT_TAGGING - if(tag.isEmpty()) - { - return this->getTags(); - - }else - { - for(const auto &data : this->tag->getUrls(tag, false)) - { - const auto url = QUrl(data.toMap()[TAG::KEYMAP[TAG::KEYS::URL]].toString()); - if(url.isLocalFile() && !FMH::fileExists(url)) - continue; - - content << FMH::getFileInfoModel(url); - } - } + static bool doNameFilter(const QString &name, const QStringList &filters) + { + for(const auto &filter : std::accumulate(filters.constBegin(), filters.constEnd(), QVector {}, [](QVector &res, const QString &filter) -> QVector + { res.append(QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard)); return res; })) + { + if(filter.exactMatch(name)) + { + return true; + } + } + return false; + } + + FMH::MODEL_LIST FM::getTagContent(const QString &tag, const QStringList &filters) + { + FMH::MODEL_LIST content; +#ifdef COMPONENT_TAGGING + if(tag.isEmpty()) + { + return this->getTags(); + }else + { + for(const auto &data : this->tag->getUrls(tag, false, [filters](QVariantMap &item) -> bool + { return doNameFilter(FMH::mapValue(item, FMH::MODEL_KEY::URL), filters); })) + { + 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; -} + 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 -} + 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::addTagToUrl(const QString tag, const QUrl& url) -{ + bool FM::urlTagExists(const QUrl& url, const QString tag) + { #ifdef COMPONENT_TAGGING - return this->tag->tagUrl(url.toString(), tag); + return this->tag->urlTagExists(url.toString(), tag, false); #endif -} + } -bool FM::removeTagToUrl(const QString tag, const QUrl& url) -{ - #ifdef COMPONENT_TAGGING - return this->tag->removeUrlTag(url.toString(), tag); - #endif -} + bool FM::addTagToUrl(const QString tag, const QUrl& url) + { +#ifdef COMPONENT_TAGGING + return this->tag->tagUrl(url.toString(), tag); +#endif + } -bool FM::cut(const QList &urls, const QUrl &where) -{ + bool FM::removeTagToUrl(const QString tag, const QUrl& url) + { +#ifdef COMPONENT_TAGGING + return this->tag->removeUrlTag(url.toString(), tag); +#endif + } - for(const auto &url : urls) + bool FM::cut(const QList &urls, const QUrl &where) { - if(FMStatic::isCloud(url.toString())) + + 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); + this->sync->setCopyTo(where.toString()); + // this->sync->resolveFile(url, Syncing::SIGNAL_TYPE::COPY); #endif - }else - { - FMStatic::cut(url, where); + }else + { + FMStatic::cut(url, where); + } } - } - return true; -} + return true; + } -bool FM::copy(const QList &urls, const QUrl &where) -{ - QStringList cloudPaths; - for(const auto &url : urls) + bool FM::copy(const QList &urls, const QUrl &where) { - if(FMStatic::isDir(url)) + QStringList cloudPaths; + for(const auto &url : urls) { - FMStatic::copy(url, where.toString()+"/"+QFileInfo(url.toLocalFile()).fileName(), false); + if(FMStatic::isDir(url)) + { + FMStatic::copy(url, where.toString()+"/"+QFileInfo(url.toLocalFile()).fileName(), false); - }else if(FMStatic::isCloud(url)) - { + }else if(FMStatic::isCloud(url)) + { #ifdef COMPONENT_SYNCING - this->sync->setCopyTo(where.toString()); -// this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); + 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); + }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(".")) + if(!cloudPaths.isEmpty()) { - 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); - } + 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; -} + return true; + } diff --git a/src/fm/fm.h b/src/fm/fm.h index 6662b51..c5359aa 100644 --- a/src/fm/fm.h +++ b/src/fm/fm.h @@ -1,88 +1,88 @@ #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 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); ~FM(); FMH::MODEL_LIST getTags(const int &limit = 5); - FMH::MODEL_LIST getTagContent(const QString &tag); + 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: Tagging *tag; #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) KCoreDirLister *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(FMH::PATH_CONTENT list); void pathContentChanged(QUrl path); void warningMessage(QString message); void loadProgress(int percent); void dirCreated(FMH::MODEL dir); void newItem(FMH::MODEL item, 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 75b6a63..42bb195 100644 --- a/src/fm/fmlist.cpp +++ b/src/fm/fmlist.cpp @@ -1,783 +1,783 @@ /* * * 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, [&](const FMH::PATH_CONTENT &res) { // if(res.path != this->path) // return; this->assignList(res.content); }); 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::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())); + 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: { emit this->preListChanged(); this->list.clear(); emit this->postListChanged(); 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)]); + 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) { case FMH::MODEL_KEY::MIME: if(e1[role] == "inode/directory") return true; break; case FMH::MODEL_KEY::SIZE: { if(e1[role].toDouble() > e2[role].toDouble()) return true; break; } case FMH::MODEL_KEY::MODIFIED: case FMH::MODEL_KEY::DATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::LABEL: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } QString FMList::getPathName() const { return this->pathName; } 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(); const auto model = this->list.at(index); return FMH::toMap(model); } 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 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 this->fm->urlTagExists(path, "fav"); } bool FMList::favItem(const QUrl &path) { if(this->itemIsFav(path)) return this->fm->removeTagToUrl("fav", path); return this->fm->addTagToUrl("fav", path); }