From c4fb3123b267ea12c8295be5544da3114de336c0 Mon Sep 17 00:00:00 2001 From: hewenfei Date: Fri, 25 Mar 2022 09:40:56 +0800 Subject: [PATCH 1/2] =?UTF-8?q?1.=E4=BD=BF=E7=94=A8=E7=B4=A2=E5=BC=95?= =?UTF-8?q?=E6=90=9C=E7=B4=A2home=E7=9B=AE=E5=BD=95=E4=B8=8B=E7=9A=84?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E3=80=822.=E5=A2=9E=E5=8A=A0=E6=8C=87?= =?UTF-8?q?=E5=AE=9A=E7=BB=93=E6=9E=9C=E9=9B=86=E6=95=B0=E9=87=8F=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search-controller-private.h | 14 ++ .../searchinterface/search-controller.cpp | 68 +++++- libsearch/searchinterface/search-controller.h | 8 + .../searchtasks/file-search-task.cpp | 208 +++++++++++++++--- .../searchtasks/file-search-task.h | 26 +++ .../ukui-search-task-private.h | 5 + .../searchinterface/ukui-search-task.cpp | 40 ++++ libsearch/searchinterface/ukui-search-task.h | 5 + 8 files changed, 340 insertions(+), 34 deletions(-) diff --git a/libsearch/searchinterface/search-controller-private.h b/libsearch/searchinterface/search-controller-private.h index 7211461..9000f95 100644 --- a/libsearch/searchinterface/search-controller-private.h +++ b/libsearch/searchinterface/search-controller-private.h @@ -34,6 +34,18 @@ public: QStringList getFileLabel(); bool isSearchFileOnly(); bool isSearchDirOnly(); + void clearAllConditions(); + void clearKeyWords(); + void clearSearchDir(); + + /** + * @brief 分页选项 + * @param first 指定起始位置 + * @param maxResults 每次搜索结果集的数量 + */ + void setPagination(unsigned int first, unsigned int maxResults); + unsigned int first() const; + unsigned int maxResults() const; private: void copyData(); @@ -53,6 +65,8 @@ private: bool m_onlySearchFile = false; bool m_onlySearchDir = false; + unsigned int m_first = 0; + unsigned int m_maxResults = 100; //默认取100条结果 }; } diff --git a/libsearch/searchinterface/search-controller.cpp b/libsearch/searchinterface/search-controller.cpp index 0ec48b0..4f9f485 100644 --- a/libsearch/searchinterface/search-controller.cpp +++ b/libsearch/searchinterface/search-controller.cpp @@ -79,7 +79,11 @@ void SearchControllerPrivate::setOnlySearchDir(bool onlySearchDir) size_t SearchControllerPrivate::getCurrentSearchId() { - return m_searchId; + m_searchIdMutex.lock(); + size_t searchId = m_searchId; + m_searchIdMutex.unlock(); + + return searchId; } DataQueue *SearchControllerPrivate::getDataQueue() @@ -164,6 +168,38 @@ void SearchControllerPrivate::copyData() } } +void SearchControllerPrivate::clearAllConditions() +{ + clearKeyWords(); + clearSearchDir(); +} + +void SearchControllerPrivate::clearKeyWords() +{ + m_keywords.clear(); +} + +void SearchControllerPrivate::clearSearchDir() +{ + m_searchDirs.clear(); +} + +void SearchControllerPrivate::setPagination(unsigned int first, unsigned int maxResults) +{ + m_first = first; + m_maxResults = maxResults; +} + +unsigned int SearchControllerPrivate::first() const +{ + return m_first; +} + +unsigned int SearchControllerPrivate::maxResults() const +{ + return m_maxResults; +} + SearchController::SearchController(std::shared_ptr parent) : m_parent(parent), d(new SearchControllerPrivate(this)) { } @@ -285,3 +321,33 @@ void SearchController::stop() { d->stop(); } + +void SearchController::clearAllConditions() +{ + d->clearAllConditions(); +} + +void SearchController::clearKeyWords() +{ + d->clearKeyWords(); +} + +void SearchController::clearSearchDir() +{ + d->clearSearchDir(); +} + +void SearchController::setPagination(unsigned int first, unsigned int maxResults) +{ + d->setPagination(first, maxResults); +} + +unsigned int SearchController::first() const +{ + return d->first(); +} + +unsigned int SearchController::maxResults() const +{ + return d->maxResults(); +} diff --git a/libsearch/searchinterface/search-controller.h b/libsearch/searchinterface/search-controller.h index 7113061..80edb45 100644 --- a/libsearch/searchinterface/search-controller.h +++ b/libsearch/searchinterface/search-controller.h @@ -49,6 +49,14 @@ public: QStringList getFileLabel(); bool isSearchFileOnly(); bool isSearchDirOnly(); + void clearAllConditions(); + void clearKeyWords(); + void clearSearchDir(); + + void setPagination(unsigned int first, unsigned int maxResults); + unsigned int first() const; + unsigned int maxResults() const; + private: std::shared_ptr m_parent = nullptr; SearchControllerPrivate *d = nullptr; diff --git a/libsearch/searchinterface/searchtasks/file-search-task.cpp b/libsearch/searchinterface/searchtasks/file-search-task.cpp index cb6a328..ff90075 100644 --- a/libsearch/searchinterface/searchtasks/file-search-task.cpp +++ b/libsearch/searchinterface/searchtasks/file-search-task.cpp @@ -1,8 +1,13 @@ #include "file-search-task.h" +#include "index-status-recorder.h" +#include "dir-watcher.h" +#include "common.h" + #include #include #include #include + using namespace UkuiSearch; FileSearchTask::FileSearchTask(QObject *parent) { @@ -51,49 +56,186 @@ FileSearchWorker::FileSearchWorker(FileSearchTask *fileSarchTask, std::shared_pt void FileSearchWorker::run() { - qDebug() << "File search start"; - //TODO do search here - QQueue bfs; - bfs.enqueue(QDir::homePath()); - QFileInfoList list; + m_currentSearchId = m_searchController->getCurrentSearchId(); + //1.检查是否为不可搜索目录 + QStringList searchDirs = m_searchController->getSearchDir(); + searchDirs.removeDuplicates(); + + for (QString &dir : searchDirs) { + if (dir.endsWith("/")) { + dir = dir.mid(0, dir.length() - 1); + } + + QStringList blackListTmp = DirWatcher::getDirWatcher()->blackListOfDir(dir); + if (!blackListTmp.contains(dir)) { + m_validDirectories.append(dir); + m_blackList.append(blackListTmp); + } + } + + //TODO 还需要判断是否为不能建立索引的目录 + if (IndexStatusRecorder::getInstance()->indexDatabaseEnable()) { + qDebug() << "index ready"; + searchWithIndex(); + + } else { + qDebug() << "direct search"; + directSearch(); + } + + QMetaObject::invokeMethod(m_FileSearchTask, "searchFinished", Q_ARG(size_t, m_currentSearchId)); +} + +Xapian::Query FileSearchWorker::creatQueryForFileSearch() { + Xapian::Query fileOrDir = Xapian::Query::MatchAll; + if (!m_searchController->isSearchDirOnly() || !m_searchController->isSearchFileOnly()) { + if (m_searchController->isSearchDirOnly()) { + fileOrDir = Xapian::Query(Xapian::Query::OP_VALUE_RANGE, 1, "1", "1"); + + } else if (m_searchController->isSearchFileOnly()) { + fileOrDir = Xapian::Query(Xapian::Query::OP_VALUE_RANGE, 1, "0", "0"); + } + + } else { + //同时指定只搜索目录和只搜索文件。。。 + return {}; + } + + std::vector queries; + for (QString &keyword : m_searchController->getKeyword()) { + if (!keyword.isEmpty()) { + std::vector queryOfKeyword; + for(auto &c : keyword) { + queryOfKeyword.emplace_back(Xapian::Query(QUrl::toPercentEncoding(c).toStdString())); + } + queries.emplace_back(Xapian::Query(Xapian::Query::OP_PHRASE, queryOfKeyword.begin(), queryOfKeyword.end())); + } + } + + return {Xapian::Query::OP_AND, {Xapian::Query::OP_AND, queries.begin(), queries.end()}, fileOrDir}; +} + +void FileSearchWorker::searchWithIndex() +{ + try { + Xapian::Database db(INDEX_PATH.toStdString()); + Xapian::Enquire enquire(db); +// qDebug() << "===" << QString::fromStdString(creatQueryForFileSearch().get_description()); + enquire.set_query(creatQueryForFileSearch()); + FileSearchFilter fileSearchFilter(this); + + Xapian::MSet result = enquire.get_mset(m_searchController->first(), m_searchController->maxResults(), 0, &fileSearchFilter); + + for (auto it = result.begin(); it != result.end(); ++it) { + if (m_searchController->beginSearchIdCheck(m_currentSearchId)) { + std::string data = it.get_document().get_data(); + + ResultItem resultItem(m_currentSearchId, QString::fromStdString(data)); + m_searchController->getDataQueue()->enqueue(resultItem); + m_searchController->finishSearchIdCheck(); + + } else { + qDebug() << "Search id changed!"; + m_searchController->finishSearchIdCheck(); + return; + } + } + + } catch(const Xapian::Error &e) { + qWarning() << QString::fromStdString(e.get_description()); + } +} + +void FileSearchWorker::directSearch() +{ + QQueue searchPathQueue; + for (QString &dir : m_validDirectories) { + searchPathQueue.enqueue(dir); + } + QDir dir; - if(true == m_searchController.get()->isSearchDirOnly()) { - dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + QFileInfoList infoList; + if (m_searchController->isSearchDirOnly()) { + dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); } else { dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); dir.setSorting(QDir::DirsFirst); } - while(!bfs.empty()) { - dir.setPath(bfs.dequeue()); - list = dir.entryInfoList(); - for (auto i : list) { - if (i.isDir() && (!(i.isSymLink()))) { - bfs.enqueue(i.absoluteFilePath()); - } - bool matched = true; - for(QString word : m_searchController.get()->getKeyword()) { - if(!i.fileName().contains(word, Qt::CaseInsensitive)) { - matched = false; -// return; + + while (!searchPathQueue.empty()) { + dir.setPath(searchPathQueue.dequeue()); + infoList = dir.entryInfoList(); + + for (const auto &fileInfo : infoList) { + if (fileInfo.isDir() && !fileInfo.isSymLink()) { + QString newPath = fileInfo.absoluteFilePath(); + if (m_blackList.contains(newPath)) { + //在黑名单的路径忽略搜索 + continue; + } + if (m_searchController->isRecurse()) { + searchPathQueue.enqueue(newPath); } } - if(matched) { - if((i.isDir() && true == m_searchController.get()->isSearchFileOnly()) || - (i.isFile() && true == m_searchController.get()->isSearchDirOnly())) { - continue; - } else { - ResultItem ri(m_searchController.get()->getCurrentSearchId(), i.absoluteFilePath()); - if(m_searchController.get()->beginSearchIdCheck(m_searchController.get()->getCurrentSearchId())) { - m_searchController.get()->getDataQueue()->enqueue(ri); - m_searchController.get()->finishSearchIdCheck(); - } else { - qDebug() << "Search id changed!"; - m_searchController.get()->finishSearchIdCheck(); - return; + + bool matched = false; + //同时包含几个key为成功匹配 + for (const QString &keyword: m_searchController->getKeyword()) { + if (!keyword.isEmpty()) { + //TODO 修改匹配方式,对结果进行排序 + if (fileInfo.fileName().contains(keyword, Qt::CaseInsensitive)) { + matched = true; + break; } } } + + if (m_searchController->beginSearchIdCheck(m_currentSearchId)) { + if (matched) { + ResultItem ri(m_currentSearchId, fileInfo.absoluteFilePath()); + m_searchController->getDataQueue()->enqueue(ri); + } + m_searchController->finishSearchIdCheck(); + } else { + qDebug() << "Search id changed!"; + m_searchController->finishSearchIdCheck(); + return; + } } } - QMetaObject::invokeMethod(m_FileSearchTask, "searchFinished", Q_ARG(size_t, m_searchController.get()->getCurrentSearchId())); +} + +FileSearchFilter::FileSearchFilter(FileSearchWorker *parent) : parent(parent) {} + +bool FileSearchFilter::operator ()(const Xapian::Document &doc) const +{ + if (parent) { + QString path = QString::fromStdString(doc.get_data()); + bool isRecurse = parent->m_searchController->isRecurse(); + bool inSearchDir = std::any_of(parent->m_validDirectories.begin(), parent->m_validDirectories.end(), [&](QString &dir) { + bool startWithDir = path.startsWith(dir); + if (!startWithDir) { + return false; + } + + if (path.length() == dir.length()) { + return false; + } + + if (!isRecurse) { + //去除搜索路径后,是否包含 "/" + return !path.midRef((dir.length() + 1), (path.length() - dir.length() - 1)).contains("/"); + } + + return true; + }); + + bool inBlackList = std::any_of(parent->m_blackList.begin(), parent->m_blackList.end(), [&](QString &dir) { + return path.startsWith(dir); + }); + + return inSearchDir && !inBlackList; + } + + return true; } diff --git a/libsearch/searchinterface/searchtasks/file-search-task.h b/libsearch/searchinterface/searchtasks/file-search-task.h index 9c3082b..48b09e0 100644 --- a/libsearch/searchinterface/searchtasks/file-search-task.h +++ b/libsearch/searchinterface/searchtasks/file-search-task.h @@ -4,9 +4,12 @@ #include #include #include +#include + #include "search-task-plugin-iface.h" #include "search-controller.h" #include "result-item.h" + namespace UkuiSearch { /* * 这里只写了大概框架,具体逻辑未实现,可以当成伪代码参考。 @@ -35,13 +38,36 @@ private: class FileSearchWorker : public QRunnable { + friend class FileSearchFilter; + public: explicit FileSearchWorker(FileSearchTask *fileSarchTask, std::shared_ptr searchController); + protected: void run(); + +private: + void searchWithIndex(); + void directSearch(); + Xapian::Query creatQueryForFileSearch(); + private: FileSearchTask *m_FileSearchTask; std::shared_ptr m_searchController; + + size_t m_currentSearchId = 0; + QStringList m_validDirectories; + QStringList m_blackList; }; + +class FileSearchFilter : public Xapian::MatchDecider { +public: + explicit FileSearchFilter(FileSearchWorker *parent); + bool operator ()(const Xapian::Document &doc) const; + +private: + FileSearchWorker *parent = nullptr; +}; + } #endif // FILESEARCHTASK_H diff --git a/libsearch/searchinterface/ukui-search-task-private.h b/libsearch/searchinterface/ukui-search-task-private.h index 56a31b4..cf109a5 100644 --- a/libsearch/searchinterface/ukui-search-task-private.h +++ b/libsearch/searchinterface/ukui-search-task-private.h @@ -24,6 +24,11 @@ public: void setOnlySearchDir(bool onlySearchDir); void setSearchOnlineApps(bool searchOnlineApps); void initSearchPlugin(SearchType searchType); + void clearAllConditions(); + void clearKeyWords(); + void clearSearchDir(); + void setPagination(unsigned int first, unsigned int maxResults); + size_t startSearch(SearchType searchtype, QString customSearchType = QString()); void stop(); diff --git a/libsearch/searchinterface/ukui-search-task.cpp b/libsearch/searchinterface/ukui-search-task.cpp index c5ac029..312256b 100644 --- a/libsearch/searchinterface/ukui-search-task.cpp +++ b/libsearch/searchinterface/ukui-search-task.cpp @@ -84,6 +84,26 @@ void UkuiSearchTaskPrivate::stop() m_searchCotroller->stop(); } +void UkuiSearchTaskPrivate::clearKeyWords() +{ + m_searchCotroller->clearKeyWords(); +} + +void UkuiSearchTaskPrivate::clearAllConditions() +{ + m_searchCotroller->clearAllConditions(); +} + +void UkuiSearchTaskPrivate::clearSearchDir() +{ + m_searchCotroller->clearSearchDir(); +} + +void UkuiSearchTaskPrivate::setPagination(unsigned int first, unsigned int maxResults) +{ + m_searchCotroller->setPagination(first, maxResults); +} + UkuiSearchTask::UkuiSearchTask(QObject *parent) : QObject(parent), d(new UkuiSearchTaskPrivate(this)) { connect(d, &UkuiSearchTaskPrivate::searchFinished, this, &UkuiSearchTask::searchFinished); @@ -147,3 +167,23 @@ void UkuiSearchTask::stop() { d->stop(); } + +void UkuiSearchTask::clearAllConditions() +{ + d->clearAllConditions(); +} + +void UkuiSearchTask::clearKeyWords() +{ + d->clearKeyWords(); +} + +void UkuiSearchTask::clearSearchDir() +{ + d->clearSearchDir(); +} + +void UkuiSearchTask::setPagination(unsigned int first, unsigned int maxResults) +{ + d->setPagination(first, maxResults); +} diff --git a/libsearch/searchinterface/ukui-search-task.h b/libsearch/searchinterface/ukui-search-task.h index 8cdda5b..7b27ca8 100644 --- a/libsearch/searchinterface/ukui-search-task.h +++ b/libsearch/searchinterface/ukui-search-task.h @@ -21,6 +21,11 @@ public: void setOnlySearchDir(bool onlySearchDir); void setSearchOnlineApps(bool searchOnlineApps); void initSearchPlugin(SearchType searchType); + void clearAllConditions(); + void clearKeyWords(); + void clearSearchDir(); + void setPagination(unsigned int first, unsigned int maxResults); + size_t startSearch(SearchType searchtype, QString customSearchType = QString()); void stop(); From 8e689623936e8056ddff214ce272ae4521ae250c Mon Sep 17 00:00:00 2001 From: hewenfei Date: Fri, 25 Mar 2022 14:09:34 +0800 Subject: [PATCH 2/2] =?UTF-8?q?1.=E6=AF=8F=E4=B8=AAtask=E5=8F=AA=E5=8F=91?= =?UTF-8?q?=E9=80=81=E4=B8=80=E6=AC=A1finish=E4=BF=A1=E5=8F=B7=E3=80=822.?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E7=9B=B4=E6=8E=A5=E6=90=9C=E7=B4=A2=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E6=9C=80=E5=A4=A7=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../searchtasks/file-search-task.cpp | 24 +++++++++++++------ .../searchtasks/file-search-task.h | 11 +++++++-- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/libsearch/searchinterface/searchtasks/file-search-task.cpp b/libsearch/searchinterface/searchtasks/file-search-task.cpp index ff90075..a332bb7 100644 --- a/libsearch/searchinterface/searchtasks/file-search-task.cpp +++ b/libsearch/searchinterface/searchtasks/file-search-task.cpp @@ -73,17 +73,18 @@ void FileSearchWorker::run() } } + bool finished = true; //TODO 还需要判断是否为不能建立索引的目录 if (IndexStatusRecorder::getInstance()->indexDatabaseEnable()) { qDebug() << "index ready"; - searchWithIndex(); + finished = searchWithIndex(); } else { qDebug() << "direct search"; - directSearch(); + finished = directSearch(); } - QMetaObject::invokeMethod(m_FileSearchTask, "searchFinished", Q_ARG(size_t, m_currentSearchId)); + if (finished) QMetaObject::invokeMethod(m_FileSearchTask, "searchFinished", Q_ARG(size_t, m_currentSearchId)); } Xapian::Query FileSearchWorker::creatQueryForFileSearch() { @@ -115,7 +116,7 @@ Xapian::Query FileSearchWorker::creatQueryForFileSearch() { return {Xapian::Query::OP_AND, {Xapian::Query::OP_AND, queries.begin(), queries.end()}, fileOrDir}; } -void FileSearchWorker::searchWithIndex() +bool FileSearchWorker::searchWithIndex() { try { Xapian::Database db(INDEX_PATH.toStdString()); @@ -137,17 +138,20 @@ void FileSearchWorker::searchWithIndex() } else { qDebug() << "Search id changed!"; m_searchController->finishSearchIdCheck(); - return; + return false; } } } catch(const Xapian::Error &e) { qWarning() << QString::fromStdString(e.get_description()); } + + return true; } -void FileSearchWorker::directSearch() +bool FileSearchWorker::directSearch() { + unsigned int maxResults = m_searchController->maxResults(); QQueue searchPathQueue; for (QString &dir : m_validDirectories) { searchPathQueue.enqueue(dir); @@ -194,15 +198,21 @@ void FileSearchWorker::directSearch() if (matched) { ResultItem ri(m_currentSearchId, fileInfo.absoluteFilePath()); m_searchController->getDataQueue()->enqueue(ri); + --maxResults; } m_searchController->finishSearchIdCheck(); + if (maxResults == 0) { + return true; + } } else { qDebug() << "Search id changed!"; m_searchController->finishSearchIdCheck(); - return; + return false; } } } + + return true; } FileSearchFilter::FileSearchFilter(FileSearchWorker *parent) : parent(parent) {} diff --git a/libsearch/searchinterface/searchtasks/file-search-task.h b/libsearch/searchinterface/searchtasks/file-search-task.h index 48b09e0..bbbe18a 100644 --- a/libsearch/searchinterface/searchtasks/file-search-task.h +++ b/libsearch/searchinterface/searchtasks/file-search-task.h @@ -47,8 +47,15 @@ protected: void run(); private: - void searchWithIndex(); - void directSearch(); + /** + * @brief 通过索引进行搜索,如果搜索过程正常,返回true + * 如果搜索被打断,返回false. + * 搜索被打断是指用户使用同一个task发起多次搜索,导致searchId发生变化,那么上一次搜索即被打断。 + * @return + */ + bool searchWithIndex(); + //同上 + bool directSearch(); Xapian::Query creatQueryForFileSearch(); private: