MauiKit File Browsing

fm.cpp
1/*
2 * Copyright 2018 Camilo Higuita <milo.h@aol.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include "fm.h"
21
22#ifdef COMPONENT_SYNCING
23#include "syncing.h"
24#endif
25
26#include <QDateTime>
27#include <QFileInfo>
28#include <QLocale>
29#include <QRegularExpression>
30#include <QUrl>
31#include <QDebug>
32
33#ifdef KIO_AVAILABLE
34#include <KCoreDirLister>
35#include <KFileItem>
36#include <KFilePlacesModel>
37#include <KIO/CopyJob>
38#include <KIO/DeleteJob>
39#include <KIO/MkdirJob>
40#include <KIO/SimpleJob>
41#include <QIcon>
42#else
43
44#include "fileloader.h"
45#include <QFileSystemWatcher>
46
47QDirLister::QDirLister(QObject *parent)
48 : QObject(parent)
49 , m_loader(new FMH::FileLoader)
50 , m_watcher(new QFileSystemWatcher(this))
51{
52 m_loader->setBatchCount(20);
53 m_loader->informer = &FMStatic::getFileInfoModel;
54 connect(m_loader, &FMH::FileLoader::itemsReady, [this](FMH::MODEL_LIST items, QList<QUrl> urls) {
55 Q_EMIT this->itemsReady(items, urls.first());
56 });
57
58 connect(m_loader, &FMH::FileLoader::itemReady, [this](FMH::MODEL item, QList<QUrl> urls) {
59 this->m_list << item;
60 this->m_watcher->addPath(QUrl(item[FMH::MODEL_KEY::URL]).toLocalFile());
61 Q_EMIT this->itemReady(item, urls.first());
62 });
63
65 Q_EMIT this->completed(urls.first());
66 });
67
68 connect(this->m_watcher, &QFileSystemWatcher::directoryChanged, [&](const QString &path) {
69 if (path == this->m_url.toLocalFile()) {
70 this->reviewChanges();
71 }
72 });
73
74 connect(this->m_watcher, &QFileSystemWatcher::fileChanged, [&](const QString &path) {
75 const auto fileUrl = QUrl::fromLocalFile(path);
76 if (this->includes(fileUrl)) {
77 if (FMH::fileExists(fileUrl)) {
78 Q_EMIT this->refreshItems({{this->m_list.at(this->indexOf(FMH::MODEL_KEY::URL, fileUrl.toString())), FMStatic::getFileInfoModel(fileUrl)}}, this->m_url);
79 }
80 }
81 });
82}
83
84void QDirLister::reviewChanges()
85{
86 if (this->m_checking)
87 return;
88
89 this->m_checking = true;
90 auto checkLoader = new FMH::FileLoader;
92
93 qDebug() << "Doign the check" << m_checking;
94
95 FMH::MODEL_LIST removedItems;
96 const auto mlist = this->m_list; // use a copy to not affect the list indexes on the iterations
97 for (const auto &item : std::as_const(mlist)) {
98 const auto fileUrl = QUrl(item[FMH::MODEL_KEY::URL]);
99
100 if (!FMH::fileExists(fileUrl)) {
101 const auto index = this->indexOf(FMH::MODEL_KEY::URL, fileUrl.toString());
102
103 if (index < this->m_list.count() && index >= 0) {
104 removedItems << item;
105 this->m_list.remove(index);
106 this->m_watcher->removePath(fileUrl.toLocalFile());
107 }
108 }
109 }
110
111 if (!removedItems.isEmpty())
112 Q_EMIT this->itemsDeleted(removedItems, this->m_url);
113
114 connect(checkLoader, &FMH::FileLoader::itemsReady, [=](FMH::MODEL_LIST items, QList<QUrl> urls) {
115 if (urls.first() == this->m_url) {
116 FMH::MODEL_LIST newItems;
117 for (const auto &item : std::as_const(items)) {
118 const auto fileUrl = QUrl(item[FMH::MODEL_KEY::URL]);
119 if (!this->includes(fileUrl)) {
120 newItems << item;
121
122 this->m_list << item;
123 this->m_watcher->addPath(fileUrl.toLocalFile());
124 }
125 }
126
127 if (!newItems.isEmpty())
128 Q_EMIT this->itemsAdded(newItems, this->m_url);
129 }
130
131 checkLoader->deleteLater();
132 this->m_checking = false;
133 });
134
136 checkLoader->deleteLater();
137 this->m_checking = false;
138 });
139
141
142 if (m_showDotFiles)
143 dirFilter = dirFilter | QDir::Hidden | QDir::System;
144
145 checkLoader->requestPath({this->m_url}, false, m_nameFilters.isEmpty() ? QStringList() : m_nameFilters.split(QStringLiteral(" ")), dirFilter);
146}
147
148bool QDirLister::includes(const QUrl &url)
149{
150 return this->indexOf(FMH::MODEL_KEY::URL, url.toString()) >= 0;
151}
152
153int QDirLister::indexOf(const FMH::MODEL_KEY &key, const QString &value) const
154{
155 const auto items = this->m_list;
156 const auto it = std::find_if(items.constBegin(), items.constEnd(), [&](const FMH::MODEL &item) -> bool {
157 return item[key] == value;
158 });
159
160 if (it != items.constEnd())
161 return std::distance(items.constBegin(), it);
162 else
163 return -1;
164}
165
166bool QDirLister::openUrl(const QUrl &url)
167{
168 // if(this->m_url == url)
169 // return false;
170
171 qDebug() << "open URL" << url;
172 this->m_url = url;
173 this->m_list.clear();
174 this->m_watcher->removePaths(QStringList() << this->m_watcher->directories() << this->m_watcher->files());
175
176 if (FMStatic::isDir(this->m_url)) {
177 this->m_watcher->addPath(this->m_url.toLocalFile());
178
180
181 dirFilter.setFlag(QDir::Hidden, m_showDotFiles);
182 dirFilter.setFlag(QDir::Files, !m_dirOnly);
183
184 m_loader->requestPath({this->m_url}, false, m_nameFilters.isEmpty() ? QStringList() : m_nameFilters.split(QStringLiteral(" ")), dirFilter);
185
186 } else
187 return false;
188
189 return true;
190}
191
192void QDirLister::setDirOnlyMode(bool value)
193{
194 m_dirOnly = value;
195}
196
197void QDirLister::setShowingDotFiles(bool value)
198{
199 m_showDotFiles = value;
200}
201
202void QDirLister::setShowHiddenFiles(bool value)
203{
204 setShowingDotFiles(value);
205}
206
207void QDirLister::setNameFilter(QString filters)
208{
209 m_nameFilters = filters;
210}
211#endif
212
214 : QObject(parent)
215#ifdef COMPONENT_SYNCING
216 , sync(new Syncing(this))
217#endif
218#ifdef KIO_AVAILABLE
219 , dirLister(new KCoreDirLister(this))
220#else
221 , dirLister(new QDirLister(this))
222#endif
223{
224
225#ifdef KIO_AVAILABLE
226 this->dirLister->setDelayedMimeTypes(true);
227 this->dirLister->setAutoUpdate(true);
228
229 const static auto packItems = [](const KFileItemList &items) -> FMH::MODEL_LIST {
230 return std::accumulate(items.constBegin(), items.constEnd(), FMH::MODEL_LIST(), [](FMH::MODEL_LIST &res, const KFileItem &item) -> FMH::MODEL_LIST {
231 res << FMStatic::getFileInfo(item);
232 return res;
233 });
234 };
235
236 connect(dirLister, static_cast<void (KCoreDirLister::*)(const QUrl &)>(&KCoreDirLister::listingDirCompleted), this, [&](QUrl url) {
237 qDebug() << "PATH CONTENT READY" << url;
238 Q_EMIT this->pathContentReady(url);
239 });
240
241 connect(dirLister, static_cast<void (KCoreDirLister::*)(const QUrl &)>(&KCoreDirLister::listingDirCanceled), this, [&](QUrl url) {
242 qDebug() << "PATH CONTENT READY" << url;
243 Q_EMIT this->pathContentReady(url);
244 });
245
246 connect(dirLister, static_cast<void (KCoreDirLister::*)(const QUrl &, const KFileItemList &items)>(&KCoreDirLister::itemsAdded), this, [&](QUrl dirUrl, KFileItemList items) {
247 qDebug() << "MORE ITEMS WERE ADDED";
248 Q_EMIT this->pathContentItemsReady({dirUrl, packItems(items)});
249 });
250
251// connect(dirLister, static_cast<void (KCoreDirLister::*)(const KFileItemList &items)>(&KCoreDirLister::newItems), [&](KFileItemList items)
252// {
253// qDebug()<< "MORE NEW ITEMS WERE ADDED";
254// for(const auto &item : items)
255// qDebug()<< "MORE <<" << item.url();
256//
257// Q_EMIT this->pathContentChanged(dirLister->url());
258// });
259
260 connect(dirLister, static_cast<void (KCoreDirLister::*)(const KFileItemList &items)>(&KCoreDirLister::itemsDeleted), this, [&](KFileItemList items) {
261 qDebug() << "ITEMS WERE DELETED";
262 Q_EMIT this->pathContentItemsRemoved({dirLister->url(), packItems(items)});
263 });
264
265 connect(dirLister, static_cast<void (KCoreDirLister::*)(const QList<QPair<KFileItem, KFileItem>> &items)>(&KCoreDirLister::refreshItems), this, [&](QList<QPair<KFileItem, KFileItem>> items) {
266 qDebug() << "ITEMS WERE REFRESHED";
267
268 const auto res = std::accumulate(
269 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>> {
270 list << QPair<FMH::MODEL, FMH::MODEL> {FMStatic::getFileInfo(pair.first), FMStatic::getFileInfo(pair.second)};
271 return list;
272 });
273
275 });
276#else
277 connect(dirLister, &QDirLister::itemsReady, this, [&](FMH::MODEL_LIST items, QUrl url) {
278 Q_EMIT this->pathContentItemsReady({url, items});
279 });
280
281 connect(dirLister, &QDirLister::completed, this, [&](QUrl url) {
282 Q_EMIT this->pathContentReady(url);
283 });
284
285 connect(dirLister, &QDirLister::refreshItems, this, [&](QVector<QPair<FMH::MODEL, FMH::MODEL>> items, QUrl) {
286 qDebug() << "ITEMS WERE REFRESHED";
287 Q_EMIT this->pathContentItemsChanged(items);
288 });
289
290 connect(dirLister, &QDirLister::itemsAdded, this, [&](FMH::MODEL_LIST items, QUrl url) {
291 qDebug() << "MORE ITEMS WERE ADDED";
292 Q_EMIT this->pathContentItemsReady({url, items});
293 Q_EMIT this->pathContentReady(url); //Q_EMIT this to force to sort on fmlist
294 });
295
296 connect(dirLister, &QDirLister::itemsDeleted, this, [&](FMH::MODEL_LIST items, QUrl url) {
297 qDebug() << "ITEMS WERE DELETED";
298 Q_EMIT this->pathContentItemsRemoved({url, items});
299 });
300
301#endif
302
303#ifdef COMPONENT_SYNCING
304 connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QUrl &url) {
305 Q_EMIT this->cloudServerContentReady({url, list});
306 });
307
308 connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QUrl &url, const Syncing::SIGNAL_TYPE &signalType) {
309 switch (signalType) {
310 case Syncing::SIGNAL_TYPE::OPEN:
311 FMStatic::openUrl(item[FMH::MODEL_KEY::PATH]);
312 break;
313
314 case Syncing::SIGNAL_TYPE::DOWNLOAD:
315 Q_EMIT this->cloudItemReady(item, url);
316 break;
317
318 case Syncing::SIGNAL_TYPE::COPY: {
319 QVariantMap data;
320 const auto keys = item.keys();
321 for (auto key : keys)
322 data.insert(FMH::MODEL_NAME[key], item[key]);
323
324 // this->copy(QVariantList {data}, this->sync->getCopyTo());
325 break;
326 }
327 default:
328 return;
329 }
330 });
331
332 connect(this->sync, &Syncing::error, [this](const QString &message) {
333 Q_EMIT this->warningMessage(message);
334 });
335
336 connect(this->sync, &Syncing::progress, [this](const int &percent) {
337 Q_EMIT this->loadProgress(percent);
338 });
339
340 connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QUrl &url) {
341 Q_EMIT this->newItem(dir, url);
342 });
343
344 connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QUrl &url) {
345 Q_EMIT this->newItem(item, url);
346 });
347#endif
348}
349
350void FM::getPathContent(const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters, const QDirIterator::IteratorFlags &iteratorFlags)
351{
352 qDebug() << "Getting async path contents";
353 Q_UNUSED(iteratorFlags)
354
355 this->dirLister->setShowHiddenFiles(hidden);
356 this->dirLister->setDirOnlyMode(onlyDirs);
357 this->dirLister->setNameFilter(filters.join(QStringLiteral(" ")));
358
359 if (this->dirLister->openUrl(path))
360 qDebug() << "GETTING PATH CONTENT" << path;
361}
362
363bool FM::getCloudServerContent(const QUrl &path, const QStringList &filters, const int &depth)
364{
365 Q_UNUSED(path)
366 Q_UNUSED(filters)
367 Q_UNUSED(depth)
368
369#ifdef COMPONENT_SYNCING
370 const auto __list = path.toString().replace("cloud:///", "/").split("/");
371
372 if (__list.isEmpty() || __list.size() < 2) {
373 qWarning() << "Could not parse username to get cloud server content";
374 return false;
375 }
376
377 auto user = __list[1];
378 // auto data = this->get(QString("select * from clouds where user = '%1'").arg(user));
379 QVariantList data;
380 if (data.isEmpty())
381 return false;
382
383 auto map = data.first().toMap();
384
385 user = map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString();
386 auto server = map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString();
387 auto password = map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString();
388 this->sync->setCredentials(server, user, password);
389
390 this->sync->listContent(path, filters, depth);
391 return true;
392#else
393 return false;
394#endif
395}
396
397void FM::createCloudDir(const QString &path, const QString &name)
398{
399 Q_UNUSED(path)
400 Q_UNUSED(name)
401
402#ifdef COMPONENT_SYNCING
403 this->sync->createDir(path, name);
404#endif
405}
406
407void FM::openCloudItem(const QVariantMap &item)
408{
409 Q_UNUSED(item)
410
411#ifdef COMPONENT_SYNCING
412 this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::OPEN);
413#endif
414}
415
416void FM::getCloudItem(const QVariantMap &item)
417{
418 Q_UNUSED(item)
419#ifdef COMPONENT_SYNCING
420 this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::DOWNLOAD);
421#endif
422}
423
425{
426 Q_UNUSED(server)
427 return FMStatic::CloudCachePath + QStringLiteral("opendesktop/") + user;
428}
429
431{
432 Q_UNUSED(path)
433#ifdef COMPONENT_SYNCING
434 return QString(path).replace(FMStatic::PATHTYPE_URI[FMStatic::PATHTYPE_KEY::CLOUD_PATH] + this->sync->getUser(), "");
435#else
436 return QString();
437#endif
438}
439
440bool FM::cut(const QList<QUrl> &urls, const QUrl &where)
441{
442 return FMStatic::cut(urls, where);
443}
444
445bool FM::copy(const QList<QUrl> &urls, const QUrl &where)
446{
447 // QStringList cloudPaths;
448
449 return FMStatic::copy(urls, where);
450
451#ifdef COMPONENT_SYNCING
452 // if(!cloudPaths.isEmpty())
453 // {
454 // qDebug()<<"UPLOAD QUEUE" << cloudPaths;
455 // const auto firstPath = cloudPaths.takeLast();
456 // this->sync->setUploadQueue(cloudPaths);
457 //
458 // if(where.toString().split("/").last().contains("."))
459 // {
460 // QStringList whereList = where.toString().split("/");
461 // whereList.removeLast();
462 // auto whereDir = whereList.join("/");
463 // qDebug()<< "Trying ot copy to cloud" << where << whereDir;
464 //
465 // this->sync->upload(this->resolveLocalCloudPath(whereDir), firstPath);
466 // } else
467 // this->sync->upload(this->resolveLocalCloudPath(where.toString()), firstPath);
468 // }
469#endif
470}
The FileLoader class asynchronously loads batches of files from a given list of local directories or ...
Definition fileloader.h:76
static std::function< FMH::MODEL(const QUrl &url)> informer
A callback function which structures the retrieved file URLs, with the required information.
Definition fileloader.h:116
void finished(FMH::MODEL_LIST items, QList< QUrl > urls)
Emitted once the operation has completely finished retrieving all the existing files or reached the l...
void requestPath(const QList< QUrl > &urls, const bool &recursive, const QStringList &nameFilters={}, const QDir::Filters &filters=QDir::Files, const uint &limit=99999)
Sends the request to start iterating throughout all the given location URLs, and with the given param...
void itemReady(FMH::MODEL item, QList< QUrl > urls)
Emitted for every single item that becomes available.
void itemsReady(FMH::MODEL_LIST items, QList< QUrl > urls)
Emitted when the batch of file items is ready.
static bool cut(const QList< QUrl > &urls, const QUrl &where)
Perform a move/cut of a list of files to a destination.
Definition fmstatic.cpp:256
static const QHash< PATHTYPE_KEY, QString > PATHTYPE_URI
Similar to PATHTYPE_SCHEME, but mapped with the complete scheme.
Definition fmstatic.h:369
static void openUrl(const QUrl &url)
Given a URL it tries to open it using the default application associated to it.
Definition fmstatic.cpp:406
static const FMH::MODEL getFileInfoModel(const QUrl &path)
getFileInfoModel
Definition fmstatic.cpp:560
static bool copy(const QList< QUrl > &urls, const QUrl &destinationDir)
Perform a copy of the files to the given destination.
Definition fmstatic.cpp:216
static const QString CloudCachePath
Standard Cloud Cache location path
Definition fmstatic.h:398
static bool isDir(const QUrl &path)
Whether a local file URL is a directory.
Definition fmstatic.cpp:139
@ CLOUD_PATH
A remote cloud server path.
Definition fmstatic.h:301
bool copy(const QList< QUrl > &urls, const QUrl &where)
Copy a set of file URLs to a new destination.
Definition fm.cpp:445
void getPathContent(const QUrl &path, const bool &hidden=false, const bool &onlyDirs=false, const QStringList &filters=QStringList(), const QDirIterator::IteratorFlags &iteratorFlags=QDirIterator::NoIteratorFlags)
Given a path URL retrieve the contents information packaged as a model.
Definition fm.cpp:350
FM(QObject *parent=nullptr)
Creates the instance.
Definition fm.cpp:213
void pathContentItemsRemoved(FMStatic::PATH_CONTENT list)
Emitted when a set of entries in the current location have been removed.
bool cut(const QList< QUrl > &urls, const QUrl &where)
Cut a set of file URLs to a new destination.
Definition fm.cpp:440
void getCloudItem(const QVariantMap &item)
Download a remote server entry.
Definition fm.cpp:416
QString resolveLocalCloudPath(const QString &path)
Given a remote server address URL, resolve it to the local cache URL.
Definition fm.cpp:430
void pathContentReady(QUrl path)
Emitted once the contents of the current location are ready and the listing has finished.
void pathContentItemsChanged(QVector< QPair< FMH::MODEL, FMH::MODEL > > items)
Emitted when the current location entries have changed.
void pathContentItemsReady(FMStatic::PATH_CONTENT list)
Emitted when a set of entries for the current location are ready.
void openCloudItem(const QVariantMap &item)
Open a given remote item in an external application.
Definition fm.cpp:407
static QString resolveUserCloudCachePath(const QString &server, const QString &user)
Given the server address and the user name, resolve a local path for the cache of the files.
Definition fm.cpp:424
Q_INVOKABLE void createCloudDir(const QString &path, const QString &name)
Creates a directory in the server.
Definition fm.cpp:397
bool getCloudServerContent(const QUrl &server, const QStringList &filters=QStringList(), const int &depth=0)
Given a server URL address retrieve its contents.
Definition fm.cpp:363
void listingDirCompleted(const QUrl &dirUrl)
void refreshItems(const QList< QPair< KFileItem, KFileItem > > &items)
void itemsDeleted(const KFileItemList &items)
void listingDirCanceled(const QUrl &dirUrl)
void itemsAdded(const QUrl &directoryUrl, const KFileItemList &items)
The Syncing class.
Definition syncing.h:18
void uploadReady(FMH::MODEL item, QUrl url)
uploadReady
void progress(int percent)
progress
void error(QString message)
error
void listReady(FMH::MODEL_LIST data, QUrl url)
listReady
void itemReady(FMH::MODEL item, QUrl url, Syncing::SIGNAL_TYPE &signalType)
itemReady
void dirCreated(FMH::MODEL item, QUrl url)
dirCreated
bool fileExists(const QUrl &path)
static const QHash< MODEL_KEY, QString > MODEL_NAME
const FMH::MODEL toModel(const QVariantMap &map)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
bool addPath(const QString &path)
QStringList directories() const const
void directoryChanged(const QString &path)
void fileChanged(const QString &path)
bool removePath(const QString &path)
QStringList removePaths(const QStringList &paths)
QList< Key > keys() const const
void clear()
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
T & first()
bool isEmpty() const const
void remove(qsizetype i, qsizetype n)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool isEmpty() const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString join(QChar separator) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)
QString toLocalFile() const const
QString toString(FormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:11:22 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.