Warning, file /maui/mauikit-filebrowsing/src/code/fm.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *   Copyright 2018 Camilo Higuita <milo.h@aol.com>
0003  *
0004  *   This program is free software; you can redistribute it and/or modify
0005  *   it under the terms of the GNU Library General Public License as
0006  *   published by the Free Software Foundation; either version 2, or
0007  *   (at your option) any later version.
0008  *
0009  *   This program is distributed in the hope that it will be useful,
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *   GNU General Public License for more details
0013  *
0014  *   You should have received a copy of the GNU Library General Public
0015  *   License along with this program; if not, write to the
0016  *   Free Software Foundation, Inc.,
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0018  */
0019 
0020 #include "fm.h"
0021 
0022 #ifdef COMPONENT_SYNCING
0023 #include "syncing.h"
0024 #endif
0025 
0026 #include <QDateTime>
0027 #include <QFileInfo>
0028 #include <QLocale>
0029 #include <QRegularExpression>
0030 #include <QUrl>
0031 #include <QDebug>
0032 
0033 #ifdef KIO_AVAILABLE
0034 #include <KCoreDirLister>
0035 #include <KFileItem>
0036 #include <KFilePlacesModel>
0037 #include <KIO/CopyJob>
0038 #include <KIO/DeleteJob>
0039 #include <KIO/MkdirJob>
0040 #include <KIO/SimpleJob>
0041 #include <QIcon>
0042 #else
0043 
0044 #include "fileloader.h"
0045 #include <QFileSystemWatcher>
0046 
0047 QDirLister::QDirLister(QObject *parent)
0048     : QObject(parent)
0049     , m_loader(new FMH::FileLoader)
0050     , m_watcher(new QFileSystemWatcher(this))
0051 {
0052     m_loader->setBatchCount(20);
0053     m_loader->informer = &FMStatic::getFileInfoModel;
0054     connect(m_loader, &FMH::FileLoader::itemsReady, [this](FMH::MODEL_LIST items, QList<QUrl> urls) {
0055         Q_EMIT this->itemsReady(items, urls.first());
0056     });
0057 
0058     connect(m_loader, &FMH::FileLoader::itemReady, [this](FMH::MODEL item, QList<QUrl> urls) {
0059         this->m_list << item;
0060         this->m_watcher->addPath(QUrl(item[FMH::MODEL_KEY::URL]).toLocalFile());
0061         Q_EMIT this->itemReady(item, urls.first());
0062     });
0063 
0064     connect(m_loader, &FMH::FileLoader::finished, [this](FMH::MODEL_LIST, QList<QUrl> urls) {
0065         Q_EMIT this->completed(urls.first());
0066     });
0067 
0068     connect(this->m_watcher, &QFileSystemWatcher::directoryChanged, [&](const QString &path) {
0069         if (path == this->m_url.toLocalFile()) {
0070             this->reviewChanges();
0071         }
0072     });
0073 
0074     connect(this->m_watcher, &QFileSystemWatcher::fileChanged, [&](const QString &path) {
0075         const auto fileUrl = QUrl::fromLocalFile(path);
0076         if (this->includes(fileUrl)) {
0077             if (FMH::fileExists(fileUrl)) {
0078                 Q_EMIT this->refreshItems({{this->m_list.at(this->indexOf(FMH::MODEL_KEY::URL, fileUrl.toString())), FMStatic::getFileInfoModel(fileUrl)}}, this->m_url);
0079             }
0080         }
0081     });
0082 }
0083 
0084 void QDirLister::reviewChanges()
0085 {
0086     if (this->m_checking)
0087         return;
0088 
0089     this->m_checking = true;
0090     auto checkLoader = new FMH::FileLoader;
0091     checkLoader->informer = &FMStatic::getFileInfoModel;
0092 
0093     qDebug() << "Doign the check" << m_checking;
0094 
0095     FMH::MODEL_LIST removedItems;
0096     const auto mlist = this->m_list; // use a copy to not affect the list indexes on the iterations
0097     for (const auto &item : qAsConst(mlist)) {
0098         const auto fileUrl = QUrl(item[FMH::MODEL_KEY::URL]);
0099 
0100         if (!FMH::fileExists(fileUrl)) {
0101             const auto index = this->indexOf(FMH::MODEL_KEY::URL, fileUrl.toString());
0102 
0103             if (index < this->m_list.count() && index >= 0) {
0104                 removedItems << item;
0105                 this->m_list.remove(index);
0106                 this->m_watcher->removePath(fileUrl.toLocalFile());
0107             }
0108         }
0109     }
0110 
0111     if (!removedItems.isEmpty())
0112         Q_EMIT this->itemsDeleted(removedItems, this->m_url);
0113 
0114     connect(checkLoader, &FMH::FileLoader::itemsReady, [=](FMH::MODEL_LIST items, QList<QUrl> urls) {
0115         if (urls.first() == this->m_url) {
0116             FMH::MODEL_LIST newItems;
0117             for (const auto &item : qAsConst(items)) {
0118                 const auto fileUrl = QUrl(item[FMH::MODEL_KEY::URL]);
0119                 if (!this->includes(fileUrl)) {
0120                     newItems << item;
0121 
0122                     this->m_list << item;
0123                     this->m_watcher->addPath(fileUrl.toLocalFile());
0124                 }
0125             }
0126 
0127             if (!newItems.isEmpty())
0128                 Q_EMIT this->itemsAdded(newItems, this->m_url);
0129         }
0130 
0131         checkLoader->deleteLater();
0132         this->m_checking = false;
0133     });
0134 
0135     connect(checkLoader, &FMH::FileLoader::finished, [=](FMH::MODEL_LIST, QList<QUrl>) {
0136         checkLoader->deleteLater();
0137         this->m_checking = false;
0138     });
0139 
0140     QDir::Filters dirFilter = (m_dirOnly ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot);
0141 
0142     if (m_showDotFiles)
0143         dirFilter = dirFilter | QDir::Hidden | QDir::System;
0144 
0145     checkLoader->requestPath({this->m_url}, false, m_nameFilters.isEmpty() ? QStringList() : m_nameFilters.split(QStringLiteral(" ")), dirFilter);
0146 }
0147 
0148 bool QDirLister::includes(const QUrl &url)
0149 {
0150     return this->indexOf(FMH::MODEL_KEY::URL, url.toString()) >= 0;
0151 }
0152 
0153 int QDirLister::indexOf(const FMH::MODEL_KEY &key, const QString &value) const
0154 {
0155     const auto items = this->m_list;
0156     const auto it = std::find_if(items.constBegin(), items.constEnd(), [&](const FMH::MODEL &item) -> bool {
0157         return item[key] == value;
0158     });
0159 
0160     if (it != items.constEnd())
0161         return std::distance(items.constBegin(), it);
0162     else
0163         return -1;
0164 }
0165 
0166 bool QDirLister::openUrl(const QUrl &url)
0167 {
0168     //    if(this->m_url == url)
0169     //        return false;
0170 
0171     qDebug() << "open URL" << url;
0172     this->m_url = url;
0173     this->m_list.clear();
0174     this->m_watcher->removePaths(QStringList() << this->m_watcher->directories() << this->m_watcher->files());
0175 
0176     if (FMStatic::isDir(this->m_url)) {
0177         this->m_watcher->addPath(this->m_url.toLocalFile());
0178 
0179         QDir::Filters dirFilter = (m_dirOnly ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot);
0180 
0181         if (m_showDotFiles)
0182         {
0183             dirFilter = dirFilter | QDir::Hidden;
0184         }
0185 
0186         m_loader->requestPath({this->m_url}, false, m_nameFilters.isEmpty() ? QStringList() : m_nameFilters.split(QStringLiteral(" ")), dirFilter);
0187 
0188     } else
0189         return false;
0190 
0191     return true;
0192 }
0193 
0194 void QDirLister::setDirOnlyMode(bool value)
0195 {
0196     m_dirOnly = value;
0197 }
0198 
0199 void QDirLister::setShowingDotFiles(bool value)
0200 {
0201     m_showDotFiles = value;
0202 }
0203 
0204 void QDirLister::setNameFilter(QString filters)
0205 {
0206     m_nameFilters = filters;
0207 }
0208 #endif
0209 
0210 FM::FM(QObject *parent)
0211     : QObject(parent)
0212 #ifdef COMPONENT_SYNCING
0213     , sync(new Syncing(this))
0214 #endif
0215 #ifdef KIO_AVAILABLE
0216     , dirLister(new KCoreDirLister(this))
0217 #else
0218     , dirLister(new QDirLister(this))
0219 #endif
0220 {
0221 
0222 #ifdef KIO_AVAILABLE
0223     this->dirLister->setDelayedMimeTypes(true);
0224     this->dirLister->setAutoUpdate(true);
0225 
0226     const static auto packItems = [](const KFileItemList &items) -> FMH::MODEL_LIST {
0227         return std::accumulate(items.constBegin(), items.constEnd(), FMH::MODEL_LIST(), [](FMH::MODEL_LIST &res, const KFileItem &item) -> FMH::MODEL_LIST {
0228             res << FMStatic::getFileInfo(item);
0229             return res;
0230         });
0231     };
0232 
0233     connect(dirLister, static_cast<void (KCoreDirLister::*)(const QUrl &)>(&KCoreDirLister::listingDirCompleted), this, [&](QUrl url) {
0234         qDebug() << "PATH CONTENT READY" << url;
0235         Q_EMIT this->pathContentReady(url);
0236     });
0237     
0238     connect(dirLister, static_cast<void (KCoreDirLister::*)(const QUrl &)>(&KCoreDirLister::listingDirCanceled), this, [&](QUrl url) {
0239         qDebug() << "PATH CONTENT READY" << url;
0240         Q_EMIT this->pathContentReady(url);
0241     });
0242 
0243     connect(dirLister, static_cast<void (KCoreDirLister::*)(const QUrl &, const KFileItemList &items)>(&KCoreDirLister::itemsAdded), this, [&](QUrl dirUrl, KFileItemList items) {
0244         qDebug() << "MORE ITEMS WERE ADDED";
0245         Q_EMIT this->pathContentItemsReady({dirUrl, packItems(items)});
0246     });
0247 
0248 //        connect(dirLister, static_cast<void (KCoreDirLister::*)(const KFileItemList &items)>(&KCoreDirLister::newItems), [&](KFileItemList items)
0249 //        {
0250 //            qDebug()<< "MORE NEW ITEMS WERE ADDED";
0251 //            for(const auto &item : items)
0252 //                qDebug()<< "MORE <<" << item.url();
0253 //     
0254 //            Q_EMIT this->pathContentChanged(dirLister->url());
0255 //        });
0256 
0257     connect(dirLister, static_cast<void (KCoreDirLister::*)(const KFileItemList &items)>(&KCoreDirLister::itemsDeleted), this, [&](KFileItemList items) {
0258         qDebug() << "ITEMS WERE DELETED";
0259         Q_EMIT this->pathContentItemsRemoved({dirLister->url(), packItems(items)});
0260     });
0261 
0262     connect(dirLister, static_cast<void (KCoreDirLister::*)(const QList<QPair<KFileItem, KFileItem>> &items)>(&KCoreDirLister::refreshItems), this, [&](QList<QPair<KFileItem, KFileItem>> items) {
0263         qDebug() << "ITEMS WERE REFRESHED";
0264 
0265         const auto res = std::accumulate(
0266             items.constBegin(), items.constEnd(), QVector<QPair<FMH::MODEL, FMH::MODEL>>(), [](QVector<QPair<FMH::MODEL, FMH::MODEL>> &list, const QPair<KFileItem, KFileItem> &pair) -> QVector<QPair<FMH::MODEL, FMH::MODEL>> {
0267                 list << QPair<FMH::MODEL, FMH::MODEL> {FMStatic::getFileInfo(pair.first), FMStatic::getFileInfo(pair.second)};
0268                 return list;
0269             });
0270 
0271         Q_EMIT this->pathContentItemsChanged(res);
0272     });
0273 #else
0274     connect(dirLister, &QDirLister::itemsReady, this, [&](FMH::MODEL_LIST items, QUrl url) {
0275         Q_EMIT this->pathContentItemsReady({url, items});
0276     });
0277 
0278     connect(dirLister, &QDirLister::completed, this, [&](QUrl url) {
0279         Q_EMIT this->pathContentReady(url);
0280     });
0281 
0282     connect(dirLister, &QDirLister::refreshItems, this, [&](QVector<QPair<FMH::MODEL, FMH::MODEL>> items, QUrl) {
0283         qDebug() << "ITEMS WERE REFRESHED";
0284         Q_EMIT this->pathContentItemsChanged(items);
0285     }); 
0286 
0287     connect(dirLister, &QDirLister::itemsAdded, this, [&](FMH::MODEL_LIST items, QUrl url) {
0288         qDebug() << "MORE ITEMS WERE ADDED";
0289         Q_EMIT this->pathContentItemsReady({url, items});
0290         Q_EMIT this->pathContentReady(url); //Q_EMIT this to force to sort on fmlist
0291     });
0292 
0293     connect(dirLister, &QDirLister::itemsDeleted, this, [&](FMH::MODEL_LIST items, QUrl url) {
0294         qDebug() << "ITEMS WERE DELETED";
0295         Q_EMIT this->pathContentItemsRemoved({url, items});
0296     });
0297 
0298 #endif
0299 
0300 #ifdef COMPONENT_SYNCING
0301     connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QUrl &url) {
0302         Q_EMIT this->cloudServerContentReady({url, list});
0303     });
0304 
0305     connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QUrl &url, const Syncing::SIGNAL_TYPE &signalType) {
0306         switch (signalType) {
0307         case Syncing::SIGNAL_TYPE::OPEN:
0308             FMStatic::openUrl(item[FMH::MODEL_KEY::PATH]);
0309             break;
0310 
0311         case Syncing::SIGNAL_TYPE::DOWNLOAD:
0312             Q_EMIT this->cloudItemReady(item, url);
0313             break;
0314 
0315         case Syncing::SIGNAL_TYPE::COPY: {
0316             QVariantMap data;
0317             const auto keys = item.keys();
0318             for (auto key : keys)
0319                 data.insert(FMH::MODEL_NAME[key], item[key]);
0320 
0321             //                         this->copy(QVariantList {data}, this->sync->getCopyTo());
0322             break;
0323         }
0324         default:
0325             return;
0326         }
0327     });
0328 
0329     connect(this->sync, &Syncing::error, [this](const QString &message) {
0330         Q_EMIT this->warningMessage(message);
0331     });
0332 
0333     connect(this->sync, &Syncing::progress, [this](const int &percent) {
0334         Q_EMIT this->loadProgress(percent);
0335     });
0336 
0337     connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QUrl &url) {
0338         Q_EMIT this->newItem(dir, url);
0339     });
0340 
0341     connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QUrl &url) {
0342         Q_EMIT this->newItem(item, url);
0343     });
0344 #endif
0345 }
0346 
0347 void FM::getPathContent(const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters, const QDirIterator::IteratorFlags &iteratorFlags)
0348 {
0349     qDebug() << "Getting async path contents";
0350     Q_UNUSED(iteratorFlags)
0351 
0352 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0353     this->dirLister->setShowingDotFiles(hidden);
0354 #else
0355     this->dirLister->setShowHiddenFiles(hidden);
0356 #endif
0357     this->dirLister->setDirOnlyMode(onlyDirs);
0358     this->dirLister->setNameFilter(filters.join(QStringLiteral(" ")));
0359 
0360     if (this->dirLister->openUrl(path))
0361         qDebug() << "GETTING PATH CONTENT" << path;
0362 }
0363 
0364 bool FM::getCloudServerContent(const QUrl &path, const QStringList &filters, const int &depth)
0365 {
0366     Q_UNUSED(path)
0367     Q_UNUSED(filters)    
0368     Q_UNUSED(depth)
0369     
0370     
0371 #ifdef COMPONENT_SYNCING
0372     const auto __list = path.toString().replace("cloud:///", "/").split("/");
0373 
0374     if (__list.isEmpty() || __list.size() < 2) {
0375         qWarning() << "Could not parse username to get cloud server content";
0376         return false;
0377     }
0378 
0379     auto user = __list[1];
0380     //        auto data = this->get(QString("select * from clouds where user = '%1'").arg(user));
0381     QVariantList data;
0382     if (data.isEmpty())
0383         return false;
0384 
0385     auto map = data.first().toMap();
0386 
0387     user = map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString();
0388     auto server = map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString();
0389     auto password = map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString();
0390     this->sync->setCredentials(server, user, password);
0391 
0392     this->sync->listContent(path, filters, depth);
0393     return true;
0394 #else
0395     return false;
0396 #endif
0397 }
0398 
0399 void FM::createCloudDir(const QString &path, const QString &name)
0400 {
0401     Q_UNUSED(path)
0402     Q_UNUSED(name)
0403     
0404 #ifdef COMPONENT_SYNCING
0405     this->sync->createDir(path, name);
0406 #endif
0407 }
0408 
0409 void FM::openCloudItem(const QVariantMap &item)
0410 {
0411     Q_UNUSED(item)
0412     
0413 #ifdef COMPONENT_SYNCING
0414     this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::OPEN);
0415 #endif
0416 }
0417 
0418 void FM::getCloudItem(const QVariantMap &item)
0419 {
0420     Q_UNUSED(item)    
0421 #ifdef COMPONENT_SYNCING
0422     this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::DOWNLOAD);
0423 #endif
0424 }
0425 
0426 QString FM::resolveUserCloudCachePath(const QString &server, const QString &user)
0427 {
0428     Q_UNUSED(server)
0429     return FMStatic::CloudCachePath + QStringLiteral("opendesktop/") + user;
0430 }
0431 
0432 QString FM::resolveLocalCloudPath(const QString &path)
0433 {
0434     Q_UNUSED(path)
0435 #ifdef COMPONENT_SYNCING
0436     return QString(path).replace(FMStatic::PATHTYPE_URI[FMStatic::PATHTYPE_KEY::CLOUD_PATH] + this->sync->getUser(), "");
0437 #else
0438     return QString();
0439 #endif
0440 }
0441 
0442 bool FM::cut(const QList<QUrl> &urls, const QUrl &where)
0443 {
0444     return FMStatic::cut(urls, where);
0445 }
0446 
0447 bool FM::copy(const QList<QUrl> &urls, const QUrl &where)
0448 {
0449     //  QStringList cloudPaths;
0450 
0451     return FMStatic::copy(urls, where);
0452 
0453 #ifdef COMPONENT_SYNCING
0454     //  if(!cloudPaths.isEmpty())
0455     //  {
0456     //      qDebug()<<"UPLOAD QUEUE" << cloudPaths;
0457     //      const auto firstPath = cloudPaths.takeLast();
0458     //      this->sync->setUploadQueue(cloudPaths);
0459     //
0460     //      if(where.toString().split("/").last().contains("."))
0461     //      {
0462     //          QStringList whereList = where.toString().split("/");
0463     //          whereList.removeLast();
0464     //          auto whereDir = whereList.join("/");
0465     //          qDebug()<< "Trying ot copy to cloud" << where << whereDir;
0466     //
0467     //          this->sync->upload(this->resolveLocalCloudPath(whereDir), firstPath);
0468     //      } else
0469     //          this->sync->upload(this->resolveLocalCloudPath(where.toString()), firstPath);
0470     //  }
0471 #endif
0472 }