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 }