Merge branch 'ukss-dev-content' into 'ukss-dev'
1.新增内容搜索插件,2.新增搜索错误信号 See merge request kylin-desktop/ukui-search!299
This commit is contained in:
commit
f76f8c8d14
|
@ -4,6 +4,9 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
|
#define CONTENT_DATABASE_PATH_SLOT 1
|
||||||
|
#define CONTENT_DATABASE_SUFFIX_SLOT 2
|
||||||
|
|
||||||
static const int LABEL_MAX_WIDTH = 300;
|
static const int LABEL_MAX_WIDTH = 300;
|
||||||
|
|
||||||
static const QString HOME_PATH = QDir::homePath();
|
static const QString HOME_PATH = QDir::homePath();
|
||||||
|
|
|
@ -21,6 +21,7 @@ public:
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void searchFinished(size_t searchId);
|
void searchFinished(size_t searchId);
|
||||||
|
void searchError(size_t searchId, QString msg = {});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Q_DECLARE_INTERFACE(UkuiSearch::SearchTaskPluginIface, SearchTaskPluginIface_iid)
|
Q_DECLARE_INTERFACE(UkuiSearch::SearchTaskPluginIface, SearchTaskPluginIface_iid)
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "file-search-task.h"
|
#include "file-search-task.h"
|
||||||
|
#include "file-content-search-task.h"
|
||||||
|
|
||||||
using namespace UkuiSearch;
|
using namespace UkuiSearch;
|
||||||
static SearchTaskPluginManager *global_instance = nullptr;
|
static SearchTaskPluginManager *global_instance = nullptr;
|
||||||
SearchTaskPluginManager *SearchTaskPluginManager::getInstance()
|
SearchTaskPluginManager *SearchTaskPluginManager::getInstance()
|
||||||
|
@ -14,9 +16,15 @@ SearchTaskPluginManager *SearchTaskPluginManager::getInstance()
|
||||||
|
|
||||||
void SearchTaskPluginManager::initPlugins(SearchType searchType)
|
void SearchTaskPluginManager::initPlugins(SearchType searchType)
|
||||||
{
|
{
|
||||||
size_t type = static_cast<size_t>(searchType);
|
switch (searchType) {
|
||||||
if (type & static_cast<size_t>(SearchType::File)) {
|
case SearchType::File:
|
||||||
registerBuildinPlugin(new FileSearchTask(this));
|
registerBuildinPlugin(new FileSearchTask(this));
|
||||||
|
break;
|
||||||
|
case SearchType::FileContent:
|
||||||
|
registerBuildinPlugin(new FileContentSearchTask(this));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +39,7 @@ bool SearchTaskPluginManager::registerPlugin(SearchTaskPluginIface *plugin)
|
||||||
}
|
}
|
||||||
m_loadedPlugin.insert(plugin->getCustomSearchType(), plugin);
|
m_loadedPlugin.insert(plugin->getCustomSearchType(), plugin);
|
||||||
connect(plugin, &SearchTaskPluginIface::searchFinished, this, &SearchTaskPluginManager::searchFinished);
|
connect(plugin, &SearchTaskPluginIface::searchFinished, this, &SearchTaskPluginManager::searchFinished);
|
||||||
|
connect(plugin, &SearchTaskPluginIface::searchError, this, &SearchTaskPluginManager::searchError);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +47,7 @@ bool SearchTaskPluginManager::registerBuildinPlugin(SearchTaskPluginIface *plugi
|
||||||
{
|
{
|
||||||
m_buildinPlugin.insert(static_cast<size_t>(plugin->getSearchType()), plugin);
|
m_buildinPlugin.insert(static_cast<size_t>(plugin->getSearchType()), plugin);
|
||||||
connect(plugin, &SearchTaskPluginIface::searchFinished, this, &SearchTaskPluginManager::searchFinished);
|
connect(plugin, &SearchTaskPluginIface::searchFinished, this, &SearchTaskPluginManager::searchFinished);
|
||||||
|
connect(plugin, &SearchTaskPluginIface::searchError, this, &SearchTaskPluginManager::searchError);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,11 +61,13 @@ void SearchTaskPluginManager::pluginSearch(SearchType searchType, std::shared_pt
|
||||||
qDebug() << "search type" << type;
|
qDebug() << "search type" << type;
|
||||||
if(m_buildinPlugin.contains(type)) {
|
if(m_buildinPlugin.contains(type)) {
|
||||||
if(!m_buildinPlugin.value(type)->isEnable()) {
|
if(!m_buildinPlugin.value(type)->isEnable()) {
|
||||||
Q_EMIT this->pluginDisable(searchController.get()->getCurrentSearchId());
|
Q_EMIT this->searchError(searchController.get()->getCurrentSearchId(), tr("plugin type: %1, is disabled!").arg(type));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qDebug() << "start search";
|
qDebug() << "start search";
|
||||||
m_buildinPlugin.value(type)->startSearch(searchController);
|
m_buildinPlugin.value(type)->startSearch(searchController);
|
||||||
|
} else {
|
||||||
|
Q_EMIT this->searchError(searchController.get()->getCurrentSearchId(), tr("plugin type: %1, is not registered!").arg(type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +75,11 @@ void SearchTaskPluginManager::pluginSearch(QString customSearchType, std::shared
|
||||||
{
|
{
|
||||||
if(m_loadedPlugin.contains(customSearchType)) {
|
if(m_loadedPlugin.contains(customSearchType)) {
|
||||||
if(!m_loadedPlugin.value(customSearchType)->isEnable()) {
|
if(!m_loadedPlugin.value(customSearchType)->isEnable()) {
|
||||||
Q_EMIT this->pluginDisable(searchController.get()->getCurrentSearchId());
|
Q_EMIT this->searchError(searchController.get()->getCurrentSearchId(), tr("plugin type: %1, is disabled!").arg(customSearchType));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_loadedPlugin.value(customSearchType)->startSearch(searchController);
|
m_loadedPlugin.value(customSearchType)->startSearch(searchController);
|
||||||
|
} else {
|
||||||
|
Q_EMIT this->searchError(searchController.get()->getCurrentSearchId(), tr("plugin type: %1, is not registered!").arg(customSearchType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@ public:
|
||||||
void pluginSearch(QString customSearchType, std::shared_ptr<SearchController> searchController);
|
void pluginSearch(QString customSearchType, std::shared_ptr<SearchController> searchController);
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void searchFinished(size_t searchId);
|
void searchFinished(size_t searchId);
|
||||||
void pluginDisable(size_t searchId);
|
void searchError(size_t searchId, QString msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit SearchTaskPluginManager(QObject *parent = nullptr);
|
explicit SearchTaskPluginManager(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
//
|
||||||
|
// Created by hxf on 2022/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
//ukui-search
|
||||||
|
#include "file-content-search-task.h"
|
||||||
|
#include "index-status-recorder.h"
|
||||||
|
#include "chinese-segmentation.h"
|
||||||
|
#include "result-item.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "file-utils.h"
|
||||||
|
|
||||||
|
//Qt
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
using namespace UkuiSearch;
|
||||||
|
|
||||||
|
FileContentSearchTask::FileContentSearchTask(QObject *parent)
|
||||||
|
{
|
||||||
|
this->setParent(parent);
|
||||||
|
qRegisterMetaType<size_t>("size_t");
|
||||||
|
m_pool = new QThreadPool(this);
|
||||||
|
m_pool->setMaxThreadCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileContentSearchTask::~FileContentSearchTask()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginInterface::PluginType FileContentSearchTask::pluginType()
|
||||||
|
{
|
||||||
|
return PluginType::SearchTaskPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString FileContentSearchTask::name()
|
||||||
|
{
|
||||||
|
return tr("File Content");
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString FileContentSearchTask::description()
|
||||||
|
{
|
||||||
|
return tr("File Content Search");
|
||||||
|
}
|
||||||
|
|
||||||
|
const QIcon FileContentSearchTask::icon()
|
||||||
|
{
|
||||||
|
return QIcon::fromTheme("folder", QIcon(":/unknown.svg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileContentSearchTask::setEnable(bool enable)
|
||||||
|
{
|
||||||
|
e_enable = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileContentSearchTask::isEnable()
|
||||||
|
{
|
||||||
|
return e_enable && IndexStatusRecorder::getInstance()->contentIndexDatabaseEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileContentSearchTask::getCustomSearchType()
|
||||||
|
{
|
||||||
|
return tr("File Content");
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchType FileContentSearchTask::getSearchType()
|
||||||
|
{
|
||||||
|
return SearchType::FileContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileContentSearchTask::startSearch(std::shared_ptr<SearchController> searchController)
|
||||||
|
{
|
||||||
|
FileContentSearchWorker *worker = new FileContentSearchWorker(this, searchController);
|
||||||
|
m_pool->start(worker);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileContentSearchTask::stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FileContentSearchWorker::FileContentSearchWorker(FileContentSearchTask *fileContentSearchTask, std::shared_ptr<SearchController> searchController)
|
||||||
|
{
|
||||||
|
m_fileContentSearchTask = fileContentSearchTask;
|
||||||
|
m_searchController = std::move(searchController);
|
||||||
|
m_currentSearchId = m_searchController->getCurrentSearchId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileContentSearchWorker::run()
|
||||||
|
{
|
||||||
|
QStringList searchDirs = m_searchController->getSearchDir();
|
||||||
|
searchDirs.removeDuplicates();
|
||||||
|
|
||||||
|
for (QString &dir : searchDirs) {
|
||||||
|
if (dir.endsWith("/")) {
|
||||||
|
dir = dir.mid(0, dir.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO 指定黑名单
|
||||||
|
m_validDirectories.append(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool finished = true;
|
||||||
|
if (IndexStatusRecorder::getInstance()->contentIndexDatabaseEnable()) {
|
||||||
|
qDebug() << "content index ready";
|
||||||
|
finished = execSearch();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qWarning() << "content index incomplete";
|
||||||
|
sendErrorMsg(QObject::tr("Content index incomplete."));
|
||||||
|
|
||||||
|
finished = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finished) QMetaObject::invokeMethod(m_fileContentSearchTask, "searchFinished", Q_ARG(size_t, m_currentSearchId));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileContentSearchWorker::sendErrorMsg(const QString &msg)
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(m_fileContentSearchTask, "searchError",
|
||||||
|
Q_ARG(size_t, m_currentSearchId),
|
||||||
|
Q_ARG(QString, msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileContentSearchWorker::execSearch()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Xapian::Database db(CONTENT_INDEX_PATH.toStdString());
|
||||||
|
Xapian::Enquire enquire(db);
|
||||||
|
|
||||||
|
enquire.set_query(createQuery());
|
||||||
|
|
||||||
|
FileContentSearchFilter filter(this);
|
||||||
|
|
||||||
|
Xapian::MSet result = enquire.get_mset(m_searchController->first(), m_searchController->maxResults(), 0, &filter);
|
||||||
|
|
||||||
|
for (auto it = result.begin(); it != result.end(); ++it) {
|
||||||
|
if (m_searchController->beginSearchIdCheck(m_currentSearchId)) {
|
||||||
|
QString path = QString::fromStdString(it.get_document().get_value(CONTENT_DATABASE_PATH_SLOT));
|
||||||
|
|
||||||
|
ResultItem resultItem(m_currentSearchId, path);
|
||||||
|
m_searchController->getDataQueue()->enqueue(resultItem);
|
||||||
|
m_searchController->finishSearchIdCheck();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qDebug() << "Search id changed!";
|
||||||
|
m_searchController->finishSearchIdCheck();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (const Xapian::Error &e) {
|
||||||
|
qWarning() << QString::fromStdString(e.get_description());
|
||||||
|
sendErrorMsg("Xapian Error: " + QString::fromStdString(e.get_description()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Xapian::Query FileContentSearchWorker::createQuery()
|
||||||
|
{
|
||||||
|
std::vector<Xapian::Query> v;
|
||||||
|
|
||||||
|
for (const auto &keyword : m_searchController->getKeyword()) {
|
||||||
|
QVector<SKeyWord> sKeyWord = ChineseSegmentation::getInstance()->callSegement(keyword.toStdString());
|
||||||
|
|
||||||
|
for(const auto & c : sKeyWord) {
|
||||||
|
v.emplace_back(c.word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {Xapian::Query::OP_AND, v.begin(), v.end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileContentSearchFilter::FileContentSearchFilter(FileContentSearchWorker *worker) : m_worker(worker)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileContentSearchFilter::operator()(const Xapian::Document &doc) const
|
||||||
|
{
|
||||||
|
//在此处对搜索结果进行过滤
|
||||||
|
QString path = QString::fromStdString(doc.get_value(CONTENT_DATABASE_PATH_SLOT));
|
||||||
|
bool isExists = QFileInfo::exists(path);
|
||||||
|
bool inSearchDir = true;
|
||||||
|
|
||||||
|
//如果不指定搜索目录,那么搜索整个数据库
|
||||||
|
if (m_worker && !m_worker->m_validDirectories.empty()) {
|
||||||
|
inSearchDir = std::any_of(m_worker->m_validDirectories.begin(), m_worker->m_validDirectories.end(), [=] (const QString& dir) {
|
||||||
|
return path.startsWith(dir);
|
||||||
|
});
|
||||||
|
//TODO 黑名单
|
||||||
|
}
|
||||||
|
|
||||||
|
return isExists && inSearchDir;
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
//
|
||||||
|
// Created by hxf on 2022/4/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef UKUI_SEARCH_FILE_CONTENT_SEARCH_TASK_H
|
||||||
|
#define UKUI_SEARCH_FILE_CONTENT_SEARCH_TASK_H
|
||||||
|
|
||||||
|
//ukui-search
|
||||||
|
#include "search-task-plugin-iface.h"
|
||||||
|
|
||||||
|
//Qt
|
||||||
|
#include <QThreadPool>
|
||||||
|
#include <QRunnable>
|
||||||
|
|
||||||
|
//Xapian
|
||||||
|
#include <xapian.h>
|
||||||
|
|
||||||
|
namespace UkuiSearch {
|
||||||
|
|
||||||
|
class FileContentSearchTask : public SearchTaskPluginIface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit FileContentSearchTask(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
~FileContentSearchTask() override;
|
||||||
|
|
||||||
|
PluginType pluginType() override;
|
||||||
|
const QString name() override;
|
||||||
|
const QString description() override;
|
||||||
|
const QIcon icon() override;
|
||||||
|
void setEnable(bool enable) override;
|
||||||
|
bool isEnable() override;
|
||||||
|
|
||||||
|
QString getCustomSearchType() override;
|
||||||
|
SearchType getSearchType() override;
|
||||||
|
void startSearch(std::shared_ptr<SearchController> searchController) override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QThreadPool *m_pool = nullptr;
|
||||||
|
bool e_enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileContentSearchWorker : public QRunnable
|
||||||
|
{
|
||||||
|
friend class FileContentSearchFilter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FileContentSearchWorker(FileContentSearchTask *fileContentSearchTask, std::shared_ptr<SearchController> searchController);
|
||||||
|
|
||||||
|
void run() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool execSearch();
|
||||||
|
inline Xapian::Query createQuery();
|
||||||
|
|
||||||
|
void sendErrorMsg(const QString &msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileContentSearchTask *m_fileContentSearchTask = nullptr;
|
||||||
|
std::shared_ptr<SearchController> m_searchController;
|
||||||
|
|
||||||
|
QStringList m_validDirectories;
|
||||||
|
|
||||||
|
size_t m_currentSearchId = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileContentSearchFilter : public Xapian::MatchDecider {
|
||||||
|
public:
|
||||||
|
explicit FileContentSearchFilter(FileContentSearchWorker*);
|
||||||
|
bool operator ()(const Xapian::Document &doc) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileContentSearchWorker *m_worker;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //UKUI_SEARCH_FILE_CONTENT_SEARCH_TASK_H
|
|
@ -144,11 +144,20 @@ bool FileSearchWorker::searchWithIndex()
|
||||||
|
|
||||||
} catch(const Xapian::Error &e) {
|
} catch(const Xapian::Error &e) {
|
||||||
qWarning() << QString::fromStdString(e.get_description());
|
qWarning() << QString::fromStdString(e.get_description());
|
||||||
|
sendErrorMsg("Xapian Error: " + QString::fromStdString(e.get_description()));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileSearchWorker::sendErrorMsg(const QString &msg)
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(m_FileSearchTask, "searchError",
|
||||||
|
Q_ARG(size_t, m_currentSearchId),
|
||||||
|
Q_ARG(QString, msg));
|
||||||
|
}
|
||||||
|
|
||||||
bool FileSearchWorker::directSearch()
|
bool FileSearchWorker::directSearch()
|
||||||
{
|
{
|
||||||
unsigned int maxResults = m_searchController->maxResults();
|
unsigned int maxResults = m_searchController->maxResults();
|
||||||
|
|
|
@ -57,6 +57,7 @@ private:
|
||||||
//同上
|
//同上
|
||||||
bool directSearch();
|
bool directSearch();
|
||||||
Xapian::Query creatQueryForFileSearch();
|
Xapian::Query creatQueryForFileSearch();
|
||||||
|
void sendErrorMsg(const QString &msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileSearchTask *m_FileSearchTask;
|
FileSearchTask *m_FileSearchTask;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
INCLUDEPATH += $$PWD
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/file-search-task.h
|
$$PWD/file-search-task.h \
|
||||||
|
$$PWD/file-content-search-task.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/file-search-task.cpp
|
$$PWD/file-search-task.cpp \
|
||||||
|
$$PWD/file-content-search-task.cpp
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ UkuiSearchTaskPrivate::UkuiSearchTaskPrivate(UkuiSearchTask *parent)
|
||||||
{
|
{
|
||||||
m_searchCotroller = std::shared_ptr<SearchController>(new SearchController());
|
m_searchCotroller = std::shared_ptr<SearchController>(new SearchController());
|
||||||
connect(SearchTaskPluginManager::getInstance(), &SearchTaskPluginManager::searchFinished, this, &UkuiSearchTaskPrivate::searchFinished);
|
connect(SearchTaskPluginManager::getInstance(), &SearchTaskPluginManager::searchFinished, this, &UkuiSearchTaskPrivate::searchFinished);
|
||||||
|
connect(SearchTaskPluginManager::getInstance(), &SearchTaskPluginManager::searchError, q, &UkuiSearchTask::searchError);
|
||||||
}
|
}
|
||||||
|
|
||||||
UkuiSearchTaskPrivate::~UkuiSearchTaskPrivate()
|
UkuiSearchTaskPrivate::~UkuiSearchTaskPrivate()
|
||||||
|
|
|
@ -31,6 +31,7 @@ public:
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void searchFinished(size_t searchId);
|
void searchFinished(size_t searchId);
|
||||||
|
void searchError(size_t searchId, QString msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UkuiSearchTaskPrivate* d = nullptr;
|
UkuiSearchTaskPrivate* d = nullptr;
|
||||||
|
|
Loading…
Reference in New Issue