template < class ResourceType, class LoaderType > static void RegisterLoader ( QMimeType fileType ) { SharedResourceLoaderPtr ldr = LoaderType::Instance (); mResourceLoaders [ fileType.name () ] = ldr; }
QString ImageshackTalker::mimeType(const QString& path) { QMimeDatabase db; QMimeType ptr = db.mimeTypeForUrl(QUrl::fromLocalFile(path)); return ptr.name(); }
/** ***************************************************************************/ vector<shared_ptr<Files::File>> Files::FilesPrivate::indexFiles(const IndexSettings &indexSettings) const { // Get a new index std::vector<shared_ptr<File>> newIndex; std::set<QString> indexedDirs; QMimeDatabase mimeDatabase; std::vector<QRegExp> mimeFilters; for (const QString &re : indexSettings.filters) mimeFilters.emplace_back(re, Qt::CaseInsensitive, QRegExp::Wildcard); // Prepare the iterator properties QDir::Filters filters = QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot; if (indexSettings.indexHidden) filters |= QDir::Hidden; // Anonymous function that implemnents the index recursion std::function<void(const QFileInfo&, vector<IgnoreEntry>)> indexRecursion = [&](const QFileInfo& fileInfo, const vector<IgnoreEntry> &ignoreEntries){ if (abort) return; const QString canonicalPath = fileInfo.canonicalFilePath(); const QMimeType mimetype = mimeDatabase.mimeTypeForFile(canonicalPath); const QString mimeName = mimetype.name(); // If the file matches the index options, index it if ( std::any_of(mimeFilters.begin(), mimeFilters.end(), [&](const QRegExp &re){ return re.exactMatch(mimeName); }) ) newIndex.push_back(std::make_shared<File>(canonicalPath, mimetype)); if (fileInfo.isDir()) { emit q->statusInfo(QString("Indexing %1.").arg(canonicalPath)); // Skip if this dir has already been indexed if ( indexedDirs.find(canonicalPath) != indexedDirs.end() ) return; // Remember that this dir has been indexed to avoid loops indexedDirs.insert(canonicalPath); // Read the ignore file, see http://doc.qt.io/qt-5/qregexp.html#wildcard-matching vector<IgnoreEntry> localIgnoreEntries = ignoreEntries; QFile file(QDir(canonicalPath).filePath(IGNOREFILE)); if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) { QTextStream in(&file); while ( !in.atEnd() ) { QString pattern = QDir::cleanPath(in.readLine()); if ( pattern.isEmpty() || pattern.startsWith("#") ) continue; // Replace ** and * by their regex analogons pattern.replace(QRegularExpression("(?<!\\*)\\*(?!\\*)"), "[^\\/]*"); pattern.replace(QRegularExpression("\\*{2,}"), ".*"); // Determine pattern type PatternType patternType = PatternType::Exclude; if ( pattern.startsWith('!') ) { patternType = PatternType::Include; pattern = pattern.mid(1, -1); } // Respect files beginning with excalmation mark if ( pattern.startsWith("\\!") ) pattern = pattern.mid(1, -1); if ( pattern.startsWith("/") ) { pattern = QString("^%1$").arg(QDir(fileInfo.filePath()).filePath(pattern.mid(1, -1))); localIgnoreEntries.emplace_back(QRegularExpression(pattern), patternType); } else { pattern = QString("%1$").arg(pattern); localIgnoreEntries.emplace_back(QRegularExpression(pattern), patternType); } } file.close(); } // Index all children in the dir QDirIterator dirIterator(canonicalPath, filters, QDirIterator::NoIteratorFlags); while ( dirIterator.hasNext() ) { dirIterator.next(); const QFileInfo & fileInfo = dirIterator.fileInfo(); // Skip if this file depending on ignore patterns PatternType patternType = PatternType::Include; for ( const IgnoreEntry &ignoreEntry : localIgnoreEntries ) if ( ignoreEntry.regex.match(fileInfo.filePath()).hasMatch() ) patternType = ignoreEntry.type; if ( patternType == PatternType::Exclude ) continue; // Skip if this file is a symlink and we should skip symlinks if ( fileInfo.isSymLink() && !indexSettings.followSymlinks ) continue; // Index this file indexRecursion(fileInfo, localIgnoreEntries); } } }; // Start the indexing for ( const QString &rootDir : indexSettings.rootDirs ) { // Index rootdir, ignore ignorefile by default vector<IgnoreEntry> ignores = {IgnoreEntry( QRegularExpression(QString("%1$").arg(IGNOREFILE)), PatternType::Exclude)}; indexRecursion(QFileInfo(rootDir), ignores); if ( abort ) return vector<shared_ptr<Files::File>>(); } // Serialize data QFile file(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)). filePath(QString("%1.txt").arg(q->Core::Extension::id))); if ( file.open(QIODevice::WriteOnly|QIODevice::Text) ) { qDebug() << qPrintable(QString("Serializing files to '%1'").arg(file.fileName())); QTextStream out(&file); for (const shared_ptr<File> &item : newIndex) out << item->path() << endl << item->mimetype().name() << endl; } else qWarning() << qPrintable(QString("Could not write to file '%1': %2").arg(file.fileName(), file.errorString())); return newIndex; }
void KRSearchMod::scanLocalDir(QUrl urlToScan) { QString dir = vfs::ensureTrailingSlash(urlToScan).path(); QT_DIR* d = QT_OPENDIR(dir.toLocal8Bit()); if (!d) return ; QT_DIRENT* dirEnt; while ((dirEnt = QT_READDIR(d)) != NULL) { QString name = QString::fromLocal8Bit(dirEnt->d_name); // we don't scan the ".",".." enteries if (name == "." || name == "..") continue; QT_STATBUF stat_p; QT_LSTAT((dir + name).toLocal8Bit(), &stat_p); QUrl url = QUrl::fromLocalFile(dir + name); QString mime; if (query->searchInArchives() || !query->hasMimeType()) { QMimeDatabase db; QMimeType mt = db.mimeTypeForUrl(url); if (mt.isValid()) mime = mt.name(); } // creating a vfile object for matching with krquery vfile * vf = new vfile(name, (KIO::filesize_t)stat_p.st_size, KRpermHandler::mode2QString(stat_p.st_mode), stat_p.st_mtime, S_ISLNK(stat_p.st_mode), false/*FIXME*/, stat_p.st_uid, stat_p.st_gid, mime, "", stat_p.st_mode); vf->vfile_setUrl(url); if (query->isRecursive()) { if (S_ISLNK(stat_p.st_mode) && query->followLinks()) unScannedUrls.push(QUrl::fromLocalFile(QDir(dir + name).canonicalPath())); else if (S_ISDIR(stat_p.st_mode)) unScannedUrls.push(url); } if (query->searchInArchives()) { if (KRarcHandler::arcSupported(mime)) { QUrl archiveURL = url; bool encrypted; QString realType = arcHandler.getType(encrypted, url.path(), mime); if (!encrypted) { if (realType == "tbz" || realType == "tgz" || realType == "tarz" || realType == "tar" || realType == "tlz") archiveURL.setScheme("tar"); else archiveURL.setScheme("krarc"); unScannedUrls.push(archiveURL); } } } if (query->match(vf)) { // if we got here - we got a winner results.append(dir + name); emit found(name, dir, (KIO::filesize_t) stat_p.st_size, stat_p.st_mtime, KRpermHandler::mode2QString(stat_p.st_mode), stat_p.st_uid, stat_p.st_gid, query->foundText()); } delete vf; if (timer.elapsed() >= EVENT_PROCESS_DELAY) { qApp->processEvents(); timer.start(); if (stopSearch) return; } } // clean up QT_CLOSEDIR(d); }
shared_ptr<ZLMimeType> QtZLFSManager::mimeType(const std::string &path) const { QMimeDatabase database; QMimeType type = database.mimeTypeForFile(QString::fromStdString(path)); return ZLMimeType::get(type.name().toStdString()); }
QString ContentList::getMimetype(QString filePath) { QMimeDatabase db; QMimeType mime = db.mimeTypeForFile(filePath); return mime.name(); }
bool PackageJobThread::installPackage(const QString &src, const QString &dest, OperationType operation) { QDir root(dest); if (!root.exists()) { QDir().mkpath(dest); if (!root.exists()) { d->errorMessage = i18n("Could not create package root directory: %1", dest); d->errorCode = Package::JobError::RootCreationError; //qWarning() << "Could not create package root directory: " << dest; return false; } } QFileInfo fileInfo(src); if (!fileInfo.exists()) { d->errorMessage = i18n("No such file: %1", src); d->errorCode = Package::JobError::PackageFileNotFoundError; return false; } QString path; QTemporaryDir tempdir; bool archivedPackage = false; if (fileInfo.isDir()) { // we have a directory, so let's just install what is in there path = src; // make sure we end in a slash! if (!path.endsWith('/')) { path.append('/'); } } else { KArchive *archive = 0; QMimeDatabase db; QMimeType mimetype = db.mimeTypeForFile(src); if (mimetype.inherits(QStringLiteral("application/zip"))) { archive = new KZip(src); } else if (mimetype.inherits(QStringLiteral("application/x-compressed-tar")) || mimetype.inherits(QStringLiteral("application/x-tar")) || mimetype.inherits(QStringLiteral("application/x-bzip-compressed-tar")) || mimetype.inherits(QStringLiteral("application/x-xz")) || mimetype.inherits(QStringLiteral("application/x-lzma"))) { archive = new KTar(src); } else { //qWarning() << "Could not open package file, unsupported archive format:" << src << mimetype.name(); d->errorMessage = i18n("Could not open package file, unsupported archive format: %1 %2", src, mimetype.name()); d->errorCode = Package::JobError::UnsupportedArchiveFormatError; return false; } if (!archive->open(QIODevice::ReadOnly)) { //qWarning() << "Could not open package file:" << src; delete archive; d->errorMessage = i18n("Could not open package file: %1", src); d->errorCode = Package::JobError::PackageOpenError; return false; } archivedPackage = true; path = tempdir.path() + '/'; d->installPath = path; const KArchiveDirectory *source = archive->directory(); source->copyTo(path); QStringList entries = source->entries(); if (entries.count() == 1) { const KArchiveEntry *entry = source->entry(entries[0]); if (entry->isDirectory()) { path.append(entry->name()).append("/"); } } delete archive; } QDir packageDir(path); QFileInfoList entries = packageDir.entryInfoList(*metaDataFiles); KPluginMetaData meta; if (!entries.isEmpty()) { const QString metadataFilePath = entries.first().filePath(); if (metadataFilePath.endsWith(QLatin1String(".desktop"))) meta = KPluginMetaData(metadataFilePath); else { QFile f(metadataFilePath); if(!f.open(QIODevice::ReadOnly)){ qWarning() << "Couldn't open metadata file" << src << path; d->errorMessage = i18n("Could not open metadata file: %1", src); d->errorCode = Package::JobError::MetadataFileMissingError; return false; } QJsonObject metadataObject = QJsonDocument::fromJson(f.readAll()).object(); meta = KPluginMetaData(metadataObject, QString(), metadataFilePath); } } if (!meta.isValid()) { qDebug() << "No metadata file in package" << src << path; d->errorMessage = i18n("No metadata file in package: %1", src); d->errorCode = Package::JobError::MetadataFileMissingError; return false; } QString pluginName = meta.pluginId(); qDebug() << "pluginname: " << meta.pluginId(); if (pluginName.isEmpty()) { //qWarning() << "Package plugin name not specified"; d->errorMessage = i18n("Package plugin name not specified: %1", src); d->errorCode = Package::JobError::PluginNameMissingError; return false; } // Ensure that package names are safe so package uninstall can't inject // bad characters into the paths used for removal. QRegExp validatePluginName("^[\\w-\\.]+$"); // Only allow letters, numbers, underscore and period. if (!validatePluginName.exactMatch(pluginName)) { //qDebug() << "Package plugin name " << pluginName << "contains invalid characters"; d->errorMessage = i18n("Package plugin name %1 contains invalid characters", pluginName); d->errorCode = Package::JobError::PluginNameInvalidError; return false; } QString targetName = dest; if (targetName[targetName.size() - 1] != '/') { targetName.append('/'); } targetName.append(pluginName); if (QFile::exists(targetName)) { if (operation == Update) { KPluginMetaData oldMeta(targetName + QLatin1String("/metadata.desktop")); if (oldMeta.serviceTypes() != meta.serviceTypes()) { d->errorMessage = i18n("The new package has a different type from the old version already installed.", meta.version(), meta.pluginId(), oldMeta.version()); d->errorCode = Package::JobError::UpdatePackageTypeMismatchError; } else if (isVersionNewer(oldMeta.version(), meta.version())) { const bool ok = uninstallPackage(targetName); if (!ok) { d->errorMessage = i18n("Impossible to remove the old installation of %1 located at %2. error: %3", pluginName, targetName, d->errorMessage); d->errorCode = Package::JobError::OldVersionRemovalError; } } else { d->errorMessage = i18n("Not installing version %1 of %2. Version %3 already installed.", meta.version(), meta.pluginId(), oldMeta.version()); d->errorCode = Package::JobError::NewerVersionAlreadyInstalledError; } } else { d->errorMessage = i18n("%1 already exists", targetName); d->errorCode = Package::JobError::PackageAlreadyInstalledError; } if (d->errorCode != KJob::NoError) { d->installPath = targetName; return false; } } //install dependencies const QStringList dependencies = KPluginMetaData::readStringList(meta.rawData(), QStringLiteral("X-KPackage-Dependencies")); for(const QString &dep : dependencies) { QUrl depUrl(dep); if (!installDependency(depUrl)) { d->errorMessage = i18n("Could not install dependency: %1", dep); d->errorCode = Package::JobError::PackageCopyError; return false; } } if (archivedPackage) { // it's in a temp dir, so just move it over. const bool ok = copyFolder(path, targetName); removeFolder(path); if (!ok) { //qWarning() << "Could not move package to destination:" << targetName; d->errorMessage = i18n("Could not move package to destination: %1", targetName); d->errorCode = Package::JobError::PackageMoveError; return false; } } else { // it's a directory containing the stuff, so copy the contents rather // than move them const bool ok = copyFolder(path, targetName); if (!ok) { //qWarning() << "Could not copy package to destination:" << targetName; d->errorMessage = i18n("Could not copy package to destination: %1", targetName); d->errorCode = Package::JobError::PackageCopyError; return false; } } if (archivedPackage) { // no need to remove the temp dir (which has been successfully moved if it's an archive) tempdir.setAutoRemove(false); } indexDirectory(dest, QStringLiteral("kpluginindex.json")); d->installPath = targetName; //qWarning() << "Not updating kbuildsycoca4, since that will go away. Do it yourself for now if needed."; return true; }
void KateProjectTreeViewContextMenu::exec(const QString &filename, const QPoint &pos, QWidget *parent) { /** * create context menu */ QMenu menu; QAction *copyAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy Filename")); /** * handle "open with" * find correct mimetype to query for possible applications */ QMenu *openWithMenu = menu.addMenu(i18n("Open With")); QMimeType mimeType = QMimeDatabase().mimeTypeForFile(filename); KService::List offers = KMimeTypeTrader::self()->query(mimeType.name(), QStringLiteral("Application")); /** * for each one, insert a menu item... */ for (KService::List::Iterator it = offers.begin(); it != offers.end(); ++it) { KService::Ptr service = *it; if (service->name() == QStringLiteral("Kate")) { continue; // omit Kate } QAction *action = openWithMenu->addAction(QIcon::fromTheme(service->icon()), service->name()); action->setData(service->entryPath()); } /** * perhaps disable menu, if no entries! */ openWithMenu->setEnabled(!openWithMenu->isEmpty()); KMoreToolsMenuFactory menuFactory(QLatin1String("kate/addons/project/git-tools")); if (isGit(filename)) { auto gitMenu = menuFactory.createMenuFromGroupingNames({ QLatin1String("git-clients-and-actions") }, QUrl::fromLocalFile(filename)); menu.addSection(i18n("Git:")); Q_FOREACH(auto action, gitMenu->actions()) { menu.addAction(action); } } /** * run menu and handle the triggered action */ if (QAction *action = menu.exec(pos)) { // handle apps if (copyAction == action) { QApplication::clipboard()->setText(filename); } else { // handle "open with" const QString openWith = action->data().toString(); if (KService::Ptr app = KService::serviceByDesktopPath(openWith)) { QList<QUrl> list; list << QUrl::fromLocalFile(filename); KRun::runService(*app, list, parent); } } } }
/** ***************************************************************************/ void Files::Extension::Indexer::run() { // Notification qDebug("[%s] Start indexing in background thread", extension_->name_); emit statusInfo("Indexing files ..."); // Prepare the iterator properties QDir::Filters filters = QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot; if (extension_->indexHidden_) filters |= QDir::Hidden; // Get a new index std::vector<shared_ptr<File>> newIndex; std::set<QString> indexedDirs; // Anonymous function that implemnents the index recursion std::function<void(const QFileInfo&)> indexRecursion = [this, &newIndex, &indexedDirs, &filters, &indexRecursion](const QFileInfo& fileInfo){ if (abort_) return; const QString canonicalPath = fileInfo.canonicalFilePath(); if (fileInfo.isFile()) { // If the file matches the index options, index it QMimeType mimetype = mimeDatabase_.mimeTypeForFile(canonicalPath); const QString mimeName = mimetype.name(); if ((extension_->indexAudio_ && mimeName.startsWith("audio")) ||(extension_->indexVideo_ && mimeName.startsWith("video")) ||(extension_->indexImage_ && mimeName.startsWith("image")) ||(extension_->indexDocs_ && (mimeName.startsWith("application") || mimeName.startsWith("text")))) { newIndex.push_back(std::make_shared<File>(canonicalPath, mimetype)); } } else if (fileInfo.isDir()) { emit statusInfo(QString("Indexing %1.").arg(canonicalPath)); // Skip if this dir has already been indexed if (indexedDirs.find(canonicalPath)!=indexedDirs.end()) return; // Remember that this dir has been indexed to avoid loops indexedDirs.insert(canonicalPath); // If the dir matches the index options, index it if (extension_->indexDirs_) { QMimeType mimetype = mimeDatabase_.mimeTypeForFile(canonicalPath); newIndex.push_back(std::make_shared<File>(canonicalPath, mimetype)); } // Ignore ignorefile by default std::vector<QRegExp> ignores; ignores.push_back(QRegExp(extension_->IGNOREFILE, Qt::CaseSensitive, QRegExp::Wildcard)); // Read the ignore file, see http://doc.qt.io/qt-5/qregexp.html#wildcard-matching QFile file(QDir(canonicalPath).filePath(extension_->IGNOREFILE)); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); while (!in.atEnd()) ignores.push_back(QRegExp(in.readLine().trimmed(), Qt::CaseSensitive, QRegExp::Wildcard)); file.close(); } // Index all children in the dir QDirIterator dirIterator(canonicalPath, filters, QDirIterator::NoIteratorFlags); while (dirIterator.hasNext()) { const QString fileName = dirIterator.next(); // Skip if this file matches one of the ignore patterns for (const QRegExp& ignore : ignores) if(ignore.exactMatch(fileName)) goto SKIP_THIS; // Skip if this file is a symlink and we shoud skip symlinks if (dirIterator.fileInfo().isSymLink() && !extension_->followSymlinks_) goto SKIP_THIS; // Index this file indexRecursion(dirIterator.fileInfo()); SKIP_THIS:; } } }; // Start the indexing for (const QString &rootDir : extension_->rootDirs_) { indexRecursion(QFileInfo(rootDir)); if (abort_) return; } // Sort the new index for linear usage copy [O(n*log(n))] emit statusInfo("Sorting ... "); std::sort(newIndex.begin(), newIndex.end(), [](const shared_ptr<File> &lhs, const shared_ptr<File> &rhs) { return QString::compare(lhs->path(), rhs->path(), Qt::CaseInsensitive) < 0; }); // Copy the usagecounters [O(n)] emit statusInfo("Copy usage statistics ... "); size_t i=0, j=0; while (i < extension_->index_.size() && j < newIndex.size()) { if (extension_->index_[i]->path() == newIndex[j]->path()) { newIndex[j]->setUsage(extension_->index_[i]->usage()); ++i;++j; } else if (extension_->index_[i]->path() < newIndex[j]->path()) { ++i; } else {// if ((*_fileIndex)[i]->path > (*newIndex)[j]->path) { ++j; } } /* * ▼ CRITICAL ▼ */ // Lock the access QMutexLocker locker(&extension_->indexAccess_); // Abortion requested while block if (abort_) return; // Set the new index (use swap to shift destruction out of critical area) std::swap(extension_->index_, newIndex); // Rebuild the offline index extension_->offlineIndex_.clear(); for (auto &item : extension_->index_) extension_->offlineIndex_.add(item); // Notification qDebug("[%s] Indexing done (%d items)", extension_->name_, static_cast<int>(extension_->index_.size())); emit statusInfo(QString("Indexed %1 files").arg(extension_->index_.size())); }
/** ***************************************************************************/ void Files::Indexer::run() { // Notification QString msg("Indexing files ..."); emit statusInfo(msg); qDebug() << "[Files]" << msg; // Prepare the iterator properties QDir::Filters filters = QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot; if (_extension->_indexHidden) filters |= QDir::Hidden; QDirIterator::IteratorFlags flags; if (_extension->_followSymlinks) flags = QDirIterator::FollowSymlinks; // Get a new index std::vector<shared_ptr<File>> newIndex; std::set<QString> indexedDirs; // Anonymous function that implemnents the index recursion std::function<void(const QFileInfo&)> indexRecursion = [this, &newIndex, &indexedDirs, &filters, &flags, &indexRecursion](const QFileInfo& fileInfo){ if (_abort) return; QString canonicalPath = fileInfo.canonicalFilePath(); if (fileInfo.isFile()) { // If the file matches the index options, index it QMimeType mimetype = _mimeDatabase.mimeTypeForFile(canonicalPath); QString mimeName = mimetype.name(); if ((_extension->_indexAudio && mimeName.startsWith("audio")) ||(_extension->_indexVideo && mimeName.startsWith("video")) ||(_extension->_indexImage && mimeName.startsWith("image")) ||(_extension->_indexDocs && (mimeName.startsWith("application") || mimeName.startsWith("text")))) { newIndex.push_back(std::make_shared<File>(canonicalPath, mimetype)); } } else if (fileInfo.isDir()) { emit statusInfo(QString("Indexing %1.").arg(canonicalPath)); // Skip if this dir has already been indexed if (indexedDirs.find(canonicalPath)!=indexedDirs.end()){ return; } // If the dir matches the index options, index it if (_extension->_indexDirs) { QMimeType mimetype = _mimeDatabase.mimeTypeForFile(canonicalPath); newIndex.push_back(std::make_shared<File>(canonicalPath, mimetype)); } // Ignore ignorefile by default std::vector<QRegExp> ignores; ignores.push_back(QRegExp(_extension->IGNOREFILE, Qt::CaseSensitive, QRegExp::Wildcard)); // Read the ignore file, see http://doc.qt.io/qt-5/qregexp.html#wildcard-matching QFile file(QDir(canonicalPath).filePath(_extension->IGNOREFILE)); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); while (!in.atEnd()) ignores.push_back(QRegExp(in.readLine().trimmed(), Qt::CaseSensitive, QRegExp::Wildcard)); file.close(); } // Index all children in the dir QDirIterator dirIterator(canonicalPath, filters, flags); while (dirIterator.hasNext()) { dirIterator.next(); // Skip if this file matches one of the ignore patterns for (QRegExp& ignore : ignores){ QString s = dirIterator.fileName(); // This is insane works only if its a lvalue if(ignore.exactMatch(s)) goto SKIP_THIS; } // Index this file indexRecursion(dirIterator.fileInfo()); SKIP_THIS:; } // Remember that this dir has been indexed to avoid loops indexedDirs.insert(canonicalPath); } }; // Start the indexing for (const QString& rootDir : _extension->_rootDirs) { indexRecursion(QFileInfo(rootDir)); if (_abort) return; } // Sort the new index for linear usage copy [O(n*log(n))] emit statusInfo("Sorting ... "); std::sort(newIndex.begin(), newIndex.end(), [](const shared_ptr<File> &lhs, const shared_ptr<File> &rhs) { return QString::compare(lhs->path(), rhs->path(), Qt::CaseInsensitive) < 0; }); // Copy the usagecounters [O(n)] emit statusInfo("Copy usage statistics ... "); size_t i=0, j=0; while (i < _extension->_fileIndex.size() && j < newIndex.size()) { if (_extension->_fileIndex[i]->path_ == newIndex[j]->path_) { newIndex[j]->usage_ = _extension->_fileIndex[i]->usage_; ++i;++j; } else if (_extension->_fileIndex[i]->path_ < newIndex[j]->path_) { ++i; } else {// if ((*_fileIndex)[i]->path > (*newIndex)[j]->path) { ++j; } } /* * ▼ CRITICAL ▼ */ // Lock the access _extension->_indexAccess.lock(); // Set the new index _extension->_fileIndex = std::move(newIndex); // Reset the offline index emit statusInfo("Build offline index... "); _extension->_searchIndex.clear(); // Build the new offline index for (shared_ptr<IIndexable> i : _extension->_fileIndex) _extension->_searchIndex.add(i); // Unlock the accress _extension->_indexAccess.unlock(); /* * ▲ CRITICAL ▲ */ // Notification msg = QString("Indexed %1 files.").arg(_extension->_fileIndex.size()); emit statusInfo(msg); qDebug() << "[Files]" << msg; }