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

0001 /*
0002  * <one line to give the program's name and a brief idea of what it does.>
0003  * Copyright (C) 2018  camilo higuita <milo.h@aol.com>
0004  *
0005  * This program is free software: you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation, either version 3 of the License, or
0008  * (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017  */
0018 
0019 #include "fmlist.h"
0020 #include "fm.h"
0021 #include "tagging.h"
0022 
0023 #ifdef COMPONENT_SYNCING
0024 #include "syncing.h"
0025 #endif
0026 
0027 #include <QFuture>
0028 #include <QThread>
0029 #include <QtConcurrent/QtConcurrentRun>
0030 #include <QtConcurrent>
0031 
0032 #include <QClipboard>
0033 #include <QGuiApplication>
0034 
0035 #include <KLocalizedString>
0036 
0037 FMList::FMList(QObject *parent)
0038     : MauiList(parent)
0039     , fm(new FM(this))
0040 {
0041     qRegisterMetaType<FMList *>("const FMList*"); // this is needed for QML to know of FMList in the search method
0042     connect(this->fm, &FM::cloudServerContentReady, [this](FMStatic::PATH_CONTENT res) {
0043         if (this->path == res.path) {
0044             this->assignList(res.content);
0045         }
0046     });
0047 
0048     connect(this->fm, &FM::pathContentReady, [this](QUrl) {
0049         Q_EMIT this->preListChanged();
0050         this->sortList();
0051         this->setStatus({PathStatus::STATUS_CODE::READY, this->list.isEmpty() ? i18n("Nothing here!") : QStringLiteral(""), this->list.isEmpty() ? i18n("This place seems to be empty") : QStringLiteral(""), this->list.isEmpty() ? QStringLiteral("folder-add") : QStringLiteral(""), this->list.isEmpty(), true});
0052         Q_EMIT this->postListChanged();
0053         Q_EMIT this->countChanged();
0054     });
0055 
0056     connect(this->fm, &FM::pathContentItemsChanged, [this](QVector<QPair<FMH::MODEL, FMH::MODEL>> res) {
0057         for (const auto &item : qAsConst(res)) {
0058             const auto index = this->indexOf(FMH::MODEL_KEY::PATH, item.first[FMH::MODEL_KEY::PATH]);
0059 
0060             if (index >= this->list.size() || index < 0)
0061                 return;
0062 
0063             this->list[index] = item.second;
0064             Q_EMIT this->updateModel(index, FMH::modelRoles(item.second));
0065         }
0066     });
0067 
0068     connect(this->fm, &FM::pathContentItemsReady, [this](FMStatic::PATH_CONTENT res) {
0069         if (res.path != this->path)
0070             return;
0071 
0072         this->appendToList(res.content);
0073     });
0074 
0075     connect(this->fm, &FM::pathContentItemsRemoved, [this](FMStatic::PATH_CONTENT res) {
0076         if (res.path != this->path)
0077             return;
0078 
0079         if (!FMH::fileExists(res.path)) {
0080             this->setStatus({PathStatus::STATUS_CODE::ERROR, i18n("Error"), i18n("This URL cannot be listed"), QStringLiteral("documentinfo"), true, false});
0081             return;
0082         }
0083 
0084         for (const auto &item : qAsConst(res.content)) {
0085             const auto index = this->indexOf(FMH::MODEL_KEY::PATH, item[FMH::MODEL_KEY::PATH]);
0086             qDebug() << "SUPOSSED TO REMOVED THIS FORM THE LIST" << index << this->list.count() << item[FMH::MODEL_KEY::PATH];
0087 
0088             this->remove(index);
0089         }
0090 
0091         this->setStatus({PathStatus::STATUS_CODE::READY, this->list.isEmpty() ? i18n("Nothing here!") : QStringLiteral(""), this->list.isEmpty() ? i18n("This place seems to be empty") : QStringLiteral(""), this->list.isEmpty() ? QStringLiteral("folder-add") : QStringLiteral(""), this->list.isEmpty(), true});
0092     });
0093 
0094     connect(this->fm, &FM::warningMessage, [this](const QString &message) {
0095         Q_EMIT this->warning(message);
0096     });
0097 
0098     connect(this->fm, &FM::loadProgress, [this](const int &percent) {
0099         Q_EMIT this->progress(percent);
0100     });
0101 
0102     connect(this->fm, &FM::pathContentChanged, [this](const QUrl &path) {
0103         qDebug() << "FOLDER PATH CHANGED" << path;
0104         if (path != this->path)
0105             return;
0106         this->sortList();
0107     });
0108 
0109     connect(this->fm, &FM::newItem, [this](const FMH::MODEL &item, const QUrl &url) {
0110         if (this->path == url) {
0111             Q_EMIT this->preItemAppended();
0112             this->list << item;
0113             Q_EMIT this->postItemAppended();
0114             Q_EMIT this->countChanged();
0115         }
0116     });
0117     
0118     connect(Tagging::getInstance(), &Tagging::urlTagged, [this](QString, QString tag)
0119     {
0120         if(this->getPathType() == FMList::PATHTYPE::TAGS_PATH)
0121         {
0122             const auto url = this->path.toString();
0123             if(url.endsWith(tag))
0124             {
0125                 this->refresh();
0126             }
0127         }
0128     });
0129     
0130     connect(Tagging::getInstance(), &Tagging::tagged, [this](QVariantMap)
0131     {
0132         if(this->pathType == PATHTYPE::TAGS_PATH)
0133         {
0134             this->refresh();
0135         }
0136     });
0137     
0138     connect(Tagging::getInstance(), &Tagging::tagRemoved, [this](QString)
0139     {
0140         if(this->pathType == PATHTYPE::TAGS_PATH)
0141         {
0142             this->refresh();
0143         }
0144     });
0145 }
0146 
0147 void FMList::assignList(const FMH::MODEL_LIST &list)
0148 {
0149     Q_EMIT this->preListChanged();
0150     this->list = list;
0151     this->sortList();
0152     this->setStatus({PathStatus::STATUS_CODE::READY, this->list.isEmpty() ? i18n("Nothing here!") : QStringLiteral(""), this->list.isEmpty() ? i18n("This place seems to be empty") : QStringLiteral(""), this->list.isEmpty() ? QStringLiteral("folder-add") : QStringLiteral(""), this->list.isEmpty(), true});
0153     Q_EMIT this->postListChanged();
0154     Q_EMIT this->countChanged();
0155 }
0156 
0157 void FMList::appendToList(const FMH::MODEL_LIST &list)
0158 {
0159     Q_EMIT this->preItemsAppended(list.size());
0160     this->list << list;
0161     Q_EMIT this->postItemAppended();
0162     Q_EMIT this->countChanged();
0163 }
0164 
0165 void FMList::clear()
0166 {
0167     Q_EMIT this->preListChanged();
0168     this->list.clear();
0169     Q_EMIT this->postListChanged();
0170     Q_EMIT this->countChanged();
0171 }
0172 
0173 FMH::MODEL_LIST FMList::getTagContent(const QString &tag, const QStringList &filters)
0174 {   
0175     if (tag.isEmpty()) {
0176         return Tagging::getInstance()->getTags();
0177     } else {
0178         FMH::MODEL_LIST content;
0179         const auto urls = Tagging::getInstance()->getTagUrls(tag, filters, false);
0180         for (const auto &url : urls) {
0181             content << FMStatic::getFileInfoModel(url);
0182         }
0183         
0184         return content;
0185     }
0186 }
0187 
0188 void FMList::setList()
0189 {
0190     qDebug() << "PATHTYPE FOR URL" << pathType << this->path.toString() << this->filters << this;
0191     
0192     if(this->path.isEmpty() || !m_autoLoad)
0193     {
0194         return;
0195     }
0196     
0197     this->clear();
0198 
0199     switch (this->pathType)
0200     {
0201     case FMList::PATHTYPE::TAGS_PATH:
0202         this->assignList(getTagContent(this->path.fileName(), QStringList() << this->filters << FMStatic::FILTER_LIST[static_cast<FMStatic::FILTER_TYPE>(this->filterType)]));
0203         break; // SYNC
0204 
0205     case FMList::PATHTYPE::CLOUD_PATH:
0206         this->fm->getCloudServerContent(this->path, this->filters, this->cloudDepth);
0207         break; // ASYNC
0208 
0209     default: {
0210         const bool exists = this->path.isLocalFile() ? FMH::fileExists(this->path) : true;
0211         if (!exists)
0212             this->setStatus({PathStatus::STATUS_CODE::ERROR, i18n("Error"), i18n("This URL cannot be listed"), QStringLiteral("documentinfo"), this->list.isEmpty(), exists});
0213         else {
0214             this->fm->getPathContent(this->path, this->hidden, this->onlyDirs, QStringList() << this->filters << FMStatic::FILTER_LIST[static_cast<FMStatic::FILTER_TYPE>(this->filterType)]);
0215         }
0216         break; // ASYNC
0217     }
0218     }
0219 }
0220 
0221 void FMList::reset()
0222 {
0223     this->setList();
0224 }
0225 
0226 const FMH::MODEL_LIST &FMList::items() const
0227 {
0228     return this->list;
0229 }
0230 
0231 FMList::SORTBY FMList::getSortBy() const
0232 {
0233     return this->sort;
0234 }
0235 
0236 void FMList::setSortBy(const FMList::SORTBY &key)
0237 {
0238     if (this->sort == key)
0239         return;
0240 
0241     this->sort = key;
0242     Q_EMIT this->sortByChanged();
0243 }
0244 
0245 void FMList::sortList()
0246 {
0247     const FMH::MODEL_KEY key = static_cast<FMH::MODEL_KEY>(this->sort);
0248     auto it = this->list.begin();
0249     
0250     const auto sortFunc = [key](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool
0251     {
0252         switch (key) {
0253         case FMH::MODEL_KEY::SIZE: {
0254             if (e1[key].toDouble() > e2[key].toDouble())
0255                 return true;
0256             break;
0257         }
0258             
0259         case FMH::MODEL_KEY::ADDDATE:
0260         case FMH::MODEL_KEY::MODIFIED:
0261         case FMH::MODEL_KEY::DATE: {
0262             auto currentTime = QDateTime::currentDateTime();
0263 
0264             auto date1 = QDateTime::fromString(e1[key], Qt::TextDate);
0265             auto date2 = QDateTime::fromString(e2[key], Qt::TextDate);
0266 
0267             if (date1.secsTo(currentTime) < date2.secsTo(currentTime))
0268                 return true;
0269 
0270             break;
0271         }
0272             
0273         case FMH::MODEL_KEY::MIME:
0274         case FMH::MODEL_KEY::LABEL: {
0275             const auto str1 = QString(e1[key]).toLower();
0276             const auto str2 = QString(e2[key]).toLower();
0277 
0278             if (str1 < str2)
0279                 return true;
0280             break;
0281         }
0282             
0283         default:
0284             if (e1[key] < e2[key])
0285                 return true;
0286         }
0287         
0288         return false;
0289     };
0290 
0291     if (this->foldersFirst) {
0292         
0293         it = std::partition(this->list.begin(),
0294                             this->list.end(),
0295                             [](const FMH::MODEL &e1) -> bool {
0296             return e1[FMH::MODEL_KEY::MIME] == QStringLiteral("inode/directory");
0297         });
0298 
0299         if(this->list.begin() != it)
0300         {
0301             std::sort(this->list.begin(), it, sortFunc);
0302         }
0303     }
0304 
0305     if(it != this->list.end())
0306     {
0307         std::sort(it, this->list.end(), sortFunc);
0308     }
0309 }
0310 
0311 QString FMList::getPathName() const
0312 {
0313     return this->pathName;
0314 }
0315 
0316 QString FMList::getPath() const
0317 {
0318     return this->path.toString();
0319 }
0320 
0321 void FMList::setPath(const QString &path)
0322 {
0323     QUrl path_ = QUrl::fromUserInput(path.simplified(), QStringLiteral("/"), QUrl::AssumeLocalFile).adjusted(QUrl::PreferLocalFile | QUrl::StripTrailingSlash | QUrl::NormalizePathSegments);
0324 
0325     if (this->path == path_)
0326         return;
0327 
0328     this->path = path_;
0329     m_navHistory.appendPath(this->path);
0330 
0331     this->setStatus({PathStatus::STATUS_CODE::LOADING, i18n("Loading content"), i18n("Almost ready!"), QStringLiteral("view-refresh"), true, false});
0332 
0333     const auto __scheme = this->path.scheme();
0334     this->pathName = QDir(this->path.toLocalFile()).dirName();
0335 
0336     if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::CLOUD_PATH]) {
0337         this->pathType = FMList::PATHTYPE::CLOUD_PATH;
0338 
0339     } else if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::APPS_PATH]) {
0340         this->pathType = FMList::PATHTYPE::APPS_PATH;
0341 
0342     } else if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::TAGS_PATH]) {
0343         this->pathType = FMList::PATHTYPE::TAGS_PATH;
0344         this->pathName = this->path.path();
0345 
0346     } else if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::TRASH_PATH]) {
0347         this->pathType = FMList::PATHTYPE::TRASH_PATH;
0348         this->pathName = QStringLiteral("Trash");
0349 
0350     } else if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::PLACES_PATH]) {
0351         this->pathType = FMList::PATHTYPE::PLACES_PATH;
0352 
0353     } else if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::MTP_PATH]) {
0354         this->pathType = FMList::PATHTYPE::MTP_PATH;
0355 
0356     } else if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::FISH_PATH]) {
0357         this->pathType = FMList::PATHTYPE::FISH_PATH;
0358 
0359     } else if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::REMOTE_PATH]) {
0360         this->pathType = FMList::PATHTYPE::REMOTE_PATH;
0361 
0362     } else if (__scheme == FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::DRIVES_PATH]) {
0363         this->pathType = FMList::PATHTYPE::DRIVES_PATH;
0364     } else {
0365         this->pathType = FMList::PATHTYPE::OTHER_PATH;
0366     }
0367 
0368     Q_EMIT this->pathNameChanged();
0369     Q_EMIT this->pathTypeChanged();
0370     Q_EMIT this->pathChanged();
0371 }
0372 
0373 FMList::PATHTYPE FMList::getPathType() const
0374 {
0375     return this->pathType;
0376 }
0377 
0378 QStringList FMList::getFilters() const
0379 {
0380     return this->filters;
0381 }
0382 
0383 void FMList::setFilters(const QStringList &filters)
0384 {
0385     if (this->filters == filters)
0386         return;
0387 
0388     this->filters = filters;
0389 
0390     Q_EMIT this->filtersChanged();
0391 }
0392 
0393 void FMList::resetFilters()
0394 {
0395     this->setFilters(QStringList());
0396 }
0397 
0398 FMList::FILTER FMList::getFilterType() const
0399 {
0400     return this->filterType;
0401 }
0402 
0403 void FMList::setFilterType(const FMList::FILTER &type)
0404 {
0405     if (this->filterType == type)
0406         return;
0407 
0408     this->filterType = type;
0409 
0410     Q_EMIT this->filterTypeChanged();
0411 }
0412 
0413 void FMList::resetFilterType()
0414 {
0415     this->setFilterType(FMList::FILTER::NONE);
0416 }
0417 
0418 bool FMList::getHidden() const
0419 {
0420     return this->hidden;
0421 }
0422 
0423 void FMList::setHidden(const bool &state)
0424 {
0425     if (this->hidden == state)
0426         return;
0427 
0428     this->hidden = state;
0429     Q_EMIT this->hiddenChanged();
0430 }
0431 
0432 bool FMList::getOnlyDirs() const
0433 {
0434     return this->onlyDirs;
0435 }
0436 
0437 void FMList::setOnlyDirs(const bool &state)
0438 {
0439     if (this->onlyDirs == state)
0440         return;
0441 
0442     this->onlyDirs = state;
0443 
0444     Q_EMIT this->onlyDirsChanged();
0445 }
0446 
0447 void FMList::refresh()
0448 {
0449     Q_EMIT this->pathChanged();
0450 }
0451 
0452 void FMList::createDir(const QString &name)
0453 {
0454     if(m_readOnly)
0455         return;
0456     
0457     if (this->pathType == FMList::PATHTYPE::CLOUD_PATH) {
0458 #ifdef COMPONENT_SYNCING
0459         this->fm->createCloudDir(QString(this->path.toString()).replace(FMStatic::PATHTYPE_SCHEME[FMStatic::PATHTYPE_KEY::CLOUD_PATH] + "/" + this->fm->sync->getUser(), ""), name);
0460 #endif
0461     } else {
0462         FMStatic::createDir(this->path, name);
0463     }
0464 }
0465 
0466 void FMList::createFile(const QString& name)
0467 {
0468     if(m_readOnly)
0469         return;
0470     
0471     FMStatic::createFile(this->path, name);
0472 }
0473 
0474 void FMList::renameFile(const QString& url, const QString& newName)
0475 {
0476     if(m_readOnly)
0477         return;
0478     
0479     FMStatic::rename(QUrl(url), newName);
0480 }
0481 
0482 void FMList::moveToTrash(const QStringList& urls)
0483 {
0484     if(m_readOnly)
0485         return;
0486     
0487     FMStatic::moveToTrash(QUrl::fromStringList(urls));
0488 }
0489 
0490 void FMList::removeFiles(const QStringList& urls)
0491 {
0492     if(m_readOnly)
0493         return;
0494     
0495     FMStatic::removeFiles(QUrl::fromStringList(urls));
0496 }
0497 
0498 void FMList::createSymlink(const QString& url)
0499 {
0500     if(m_readOnly)
0501         return;
0502     
0503     FMStatic::createSymlink(QUrl(url), this->path);
0504 }
0505 
0506 bool FMList::saveImageFile(const QImage& image)
0507 {
0508     QString fileName = QString(QStringLiteral("%1/pasted_image-0.%2")).arg(path.toLocalFile(), QStringLiteral("png"));
0509 
0510     int idx = 1;
0511     while ( QFile::exists( fileName ) )
0512     {
0513         fileName = QString(QStringLiteral("%1/pasted_image-%2.%3")).arg(path.toLocalFile(), QString::number(idx), QStringLiteral("png"));
0514         idx++;
0515     }
0516     
0517     return image.save(fileName);
0518 }
0519 
0520 bool FMList::saveTextFile(const QString& data, const QString &format)
0521 {
0522     QString fileName = QString(QStringLiteral("%1/pasted_text-0.%2")).arg(path.toLocalFile(), format);
0523 
0524     int idx = 1;
0525     while ( QFile::exists( fileName ) )
0526     {
0527         fileName = QString(QStringLiteral("%1/pasted_text-%2.%3")).arg(path.toLocalFile(), QString::number(idx), format);
0528         idx++;
0529     }
0530     
0531     QFile file(fileName);
0532     
0533     if (file.open(QIODevice::ReadWrite))
0534     {
0535         QTextStream out(&file);
0536         out << data;
0537         file.close();
0538         return true;
0539     }
0540 
0541     return false;
0542 }
0543 
0544 void FMList::paste()
0545 {  
0546     if(m_readOnly)
0547         return;
0548     
0549     const QClipboard *clipboard = QGuiApplication::clipboard();
0550     const QMimeData *mimeData = clipboard->mimeData();
0551     
0552     if(!mimeData)
0553     {
0554         qWarning() << "Could not get mime data from the clipboard";
0555         return;
0556     }
0557     
0558     if (mimeData->hasImage())
0559     {
0560         saveImageFile(qvariant_cast<QImage>(mimeData->imageData()));
0561     } else if (mimeData->hasUrls())
0562     {
0563         const QByteArray a = mimeData->data(QStringLiteral("application/x-kde-cutselection"));
0564         const bool cut =  (!a.isEmpty() && a.at(0) == '1');
0565 
0566         if(cut)
0567         {
0568             cutInto(QUrl::toStringList(mimeData->urls()));
0569             // mimeData->clear();
0570         }else
0571         {
0572             copyInto(QUrl::toStringList(mimeData->urls()));
0573         }
0574 
0575     } else if (mimeData->hasText())
0576     {
0577         saveTextFile(mimeData->text(), QStringLiteral("txt"));
0578     } else
0579     {
0580         qWarning() << "Unexpected mime type from clipboard content for performing a paste";
0581     }
0582 }
0583 
0584 bool FMList::clipboardHasContent() const
0585 {
0586     const QClipboard *clipboard = QGuiApplication::clipboard();
0587     const QMimeData *mimeData = clipboard->mimeData();
0588     
0589     if(!mimeData)
0590     {
0591         qWarning() << "Could not get mime data from the clipboard";
0592         return false;
0593     }
0594     
0595     return mimeData->hasUrls() || mimeData->hasImage() || mimeData->hasText();
0596 }
0597 
0598 
0599 void FMList::copyInto(const QStringList &urls)
0600 {
0601     if(m_readOnly)
0602         return;
0603     
0604     this->fm->copy(QUrl::fromStringList(urls), this->path);
0605 }
0606 
0607 void FMList::cutInto(const QStringList &urls)
0608 {
0609     if(m_readOnly)
0610         return;
0611     
0612     this->fm->cut(QUrl::fromStringList(urls), this->path);
0613 }
0614 
0615 void FMList::setDirIcon(const int &index, const QString &iconName)
0616 {
0617     if (index >= this->list.size() || index < 0)
0618         return;
0619 
0620     const auto path = QUrl(this->list.at(index)[FMH::MODEL_KEY::PATH]);
0621 
0622     if (!FMStatic::isDir(path))
0623         return;
0624 
0625     FMStatic::setDirConf(QUrl(path.toString() + QStringLiteral("/.directory")), QStringLiteral("Desktop Entry"), QStringLiteral("Icon"), iconName);
0626 
0627     this->list[index][FMH::MODEL_KEY::ICON] = iconName;
0628     Q_EMIT this->updateModel(index, QVector<int> {FMH::MODEL_KEY::ICON});
0629 }
0630 
0631 const QUrl FMList::getParentPath()
0632 {
0633     switch (this->pathType)
0634     {
0635     case FMList::PATHTYPE::PLACES_PATH:
0636         return FMStatic::parentDir(this->path);
0637     default:
0638         return this->previousPath();
0639     }
0640 }
0641 
0642 const QUrl FMList::posteriorPath()
0643 {
0644     const auto url = m_navHistory.getPosteriorPath();
0645 
0646     if (url.isEmpty())
0647         return this->path;
0648 
0649     return url;
0650 }
0651 
0652 const QUrl FMList::previousPath()
0653 {
0654     const auto url = m_navHistory.getPreviousPath();
0655 
0656     if (url.isEmpty())
0657         return this->path;
0658 
0659     return url;
0660 }
0661 
0662 bool FMList::getFoldersFirst() const
0663 {
0664     return this->foldersFirst;
0665 }
0666 
0667 void FMList::setFoldersFirst(const bool &value)
0668 {
0669     if (this->foldersFirst == value)
0670         return;
0671 
0672     Q_EMIT this->preListChanged();
0673 
0674     this->foldersFirst = value;
0675 
0676     Q_EMIT this->foldersFirstChanged();
0677 
0678     this->sortList();
0679 
0680     Q_EMIT this->postListChanged();
0681     Q_EMIT this->countChanged();
0682 }
0683 
0684 void FMList::componentComplete()
0685 {
0686     connect(this, &FMList::pathChanged, this, &FMList::setList);
0687     connect(this, &FMList::filtersChanged, this, &FMList::setList);
0688     connect(this, &FMList::filterTypeChanged, this, &FMList::setList);
0689     connect(this, &FMList::hiddenChanged, this, &FMList::setList);
0690     connect(this, &FMList::onlyDirsChanged, this, &FMList::setList);
0691     
0692     connect(this, &FMList::sortByChanged, [this]()
0693     {
0694         if(this->list.size() > 0)
0695         {
0696             Q_EMIT this->preListChanged();
0697             this->sortList();
0698             Q_EMIT this->postListChanged();
0699             Q_EMIT this->countChanged();
0700         }
0701     });
0702 
0703     if(!this->path.isEmpty() && this->path.isValid())
0704     {
0705         this->setList();
0706     }
0707 }
0708 
0709 void FMList::search(const QString &query, bool recursive)
0710 {
0711     if(this->path.isEmpty())
0712     {
0713         this->setStatus({PathStatus::ERROR, i18n("Error"), i18n("No path to perform the search"), QStringLiteral("document-info"), true, false});
0714     }
0715 
0716     qDebug() << "SEARCHING FOR" << query << this->path;
0717 
0718     if (!this->path.isLocalFile() || !recursive)
0719     { //if the path is not local then search will not be performed and instead will be filtered
0720         qWarning() << "URL recived is not a local file. So search will only filter the content" << this->path;
0721         this->filterContent(query, this->path);
0722         return;
0723     }
0724 
0725     QFutureWatcher<FMStatic::PATH_CONTENT> *watcher = new QFutureWatcher<FMStatic::PATH_CONTENT>;
0726     connect(watcher, &QFutureWatcher<FMH::MODEL_LIST>::finished, [=]() {
0727         const auto res = watcher->future().result();
0728 
0729         this->assignList(res.content);
0730         watcher->deleteLater();
0731     });
0732 
0733     QFuture<FMStatic::PATH_CONTENT> t1 = QtConcurrent::run([=]() -> FMStatic::PATH_CONTENT {
0734         FMStatic::PATH_CONTENT res;
0735         res.path = path;
0736         res.content = FMStatic::search(query, this->path, this->hidden, this->onlyDirs, this->filters);
0737         return res;
0738     });
0739     watcher->setFuture(t1);
0740 }
0741 
0742 void FMList::filterContent(const QString &query, const QUrl &path)
0743 {
0744     if (this->list.isEmpty()) {
0745         qDebug() << "Can not filter content. List is empty";
0746         return;
0747     }
0748 
0749     QFutureWatcher<FMStatic::PATH_CONTENT> *watcher = new QFutureWatcher<FMStatic::PATH_CONTENT>;
0750     connect(watcher, &QFutureWatcher<FMH::MODEL_LIST>::finished, [=]() {
0751         const auto res = watcher->future().result();
0752 
0753         this->assignList(res.content);
0754         watcher->deleteLater();
0755     });
0756 
0757     QFuture<FMStatic::PATH_CONTENT> t1 = QtConcurrent::run([=]() -> FMStatic::PATH_CONTENT {
0758         FMH::MODEL_LIST m_content;
0759         FMStatic::PATH_CONTENT res;
0760 
0761         for (const auto &item : qAsConst(this->list))
0762         {
0763             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)) {
0764                 m_content << item;
0765             }
0766         }
0767 
0768         res.path = path;
0769         res.content = m_content;
0770         return res;
0771     });
0772     watcher->setFuture(t1);
0773 }
0774 
0775 int FMList::getCloudDepth() const
0776 {
0777     return this->cloudDepth;
0778 }
0779 
0780 void FMList::setCloudDepth(const int &value)
0781 {
0782     if (this->cloudDepth == value)
0783         return;
0784 
0785     this->cloudDepth = value;
0786 
0787     Q_EMIT this->cloudDepthChanged();
0788 }
0789 
0790 PathStatus FMList::getStatus() const
0791 {
0792     return this->m_status;
0793 }
0794 
0795 void FMList::setStatus(const PathStatus &status)
0796 {
0797     this->m_status = status;
0798     Q_EMIT this->statusChanged();
0799 }
0800 
0801 void FMList::remove(const int &index)
0802 {
0803     if (index >= this->list.size() || index < 0)
0804         return;
0805 
0806     Q_EMIT this->preItemRemoved(index);
0807     this->list.remove(index);
0808     Q_EMIT this->postItemRemoved();
0809     Q_EMIT this->countChanged();
0810 }
0811 
0812 int FMList::indexOfName(const QString& query)
0813 {
0814     const auto it = std::find_if(this->items().constBegin(), this->items().constEnd(), [query](const FMH::MODEL &item) -> bool {
0815         return item[FMH::MODEL_KEY::LABEL].startsWith(query, Qt::CaseInsensitive);
0816     });
0817 
0818     if (it != this->items().constEnd())
0819         return (std::distance(this->items().constBegin(), it));
0820     else
0821         return -1;
0822 }
0823 
0824 bool FMList::getAutoLoad() const
0825 {
0826     return m_autoLoad;
0827 }
0828 
0829 void FMList::setAutoLoad(bool value)
0830 {
0831     if(value == m_autoLoad)
0832     {
0833         return;
0834     }
0835     
0836     m_autoLoad = value;
0837     Q_EMIT autoLoadChanged();
0838 }
0839 
0840 bool FMList::readOnly() const
0841 {
0842     return m_readOnly;
0843 }
0844 
0845 void FMList::setReadOnly(bool value)
0846 {
0847     if(m_readOnly == value)
0848         return;
0849     
0850     m_readOnly = value;
0851     Q_EMIT readOnlyChanged();
0852 }
0853 
0854 int FMList::indexOfFile(const QString& url)
0855 {
0856     const auto it = std::find_if(this->items().constBegin(), this->items().constEnd(), [url](const FMH::MODEL &item) -> bool {
0857         return item[FMH::MODEL_KEY::URL] == url;
0858     });
0859     
0860     if (it != this->items().constEnd())
0861         return (std::distance(this->items().constBegin(), it));
0862     else
0863         return -1;
0864 }
0865 
0866 
0867