diff --git a/frontend/control/stack-pages/search-page-section.cpp b/frontend/control/stack-pages/search-page-section.cpp index ee5191e..fb5973e 100644 --- a/frontend/control/stack-pages/search-page-section.cpp +++ b/frontend/control/stack-pages/search-page-section.cpp @@ -59,6 +59,52 @@ void ResultArea::appendWidet(ResultWidget *widget) m_widget->setFixedHeight(m_widget->height() + widget->height() + spacing_height); } +void ResultArea::insertWidget(ResultWidget *widget, int index) +{ + m_mainLyt->insertWidget(index, widget); + setupConnectionsForWidget(widget); + widget->clearResult(); + m_widget_list.insert(index, widget); + qDebug() << "========insert widget:" << widget->pluginId() << index; + int spacing_height = m_widget_list.length() > 1 ? m_mainLyt->spacing() : 0; + m_widget->setFixedHeight(m_widget->height() + widget->height() + spacing_height); +} + +bool ResultArea::removeWidget(const QString &pluginName) +{ + int height = 0; + bool res(false); + for (ResultWidget *myWidget : m_widget_list) { + if (myWidget->pluginId() == pluginName) { + height = myWidget->height(); + myWidget->disconnect(); + myWidget->clearResult(); + m_mainLyt->removeWidget(myWidget); + m_widget_list.removeAll(myWidget); + res = true; + break; + } + } + if (res) { + int spacing_height = m_widget_list.length() > 0 ? m_mainLyt->spacing() : 0; + m_widget->setFixedHeight(m_widget->height() - (height + spacing_height)); + qDebug() << "Remove Widget " << pluginName; + } + return res; +} + +bool ResultArea::moveWidget(const QString& pluginName, int index) +{ + for (ResultWidget *myWidget : m_widget_list) { + if (myWidget->pluginId() == pluginName) { + m_mainLyt->removeWidget(myWidget); + m_mainLyt->insertWidget(index, myWidget);//第一个插件固定为bestlist + return true; + } + } + return false; +} + /** * @brief ResultArea::setVisibleList 设置哪些插件可见,默认全部可见 * @param list @@ -517,6 +563,8 @@ void ResultArea::setupConnectionsForWidget(ResultWidget *widget) } }); connect(widget, &ResultWidget::sendBestListData, m_bestListWidget, &BestListWidget::sendBestListData); + + connect(SearchPluginManager::getInstance(), &SearchPluginManager::unregistered, this, &ResultArea::removeWidget); } DetailArea::DetailArea(QWidget *parent) : QScrollArea(parent) diff --git a/frontend/control/stack-pages/search-page-section.h b/frontend/control/stack-pages/search-page-section.h index e5fa712..5f42d25 100644 --- a/frontend/control/stack-pages/search-page-section.h +++ b/frontend/control/stack-pages/search-page-section.h @@ -37,6 +37,9 @@ public: ResultArea(QWidget *parent = nullptr); ~ResultArea() = default; void appendWidet(ResultWidget *); + void insertWidget(ResultWidget *widget, int index); + bool removeWidget(const QString& pluginName); + bool moveWidget(const QString& pluginName, int index); void setVisibleList(const QStringList &); void pressEnter(); void pressDown(); diff --git a/frontend/control/stack-pages/search-result-page.cpp b/frontend/control/stack-pages/search-result-page.cpp index 028ce87..14fc0e8 100644 --- a/frontend/control/stack-pages/search-result-page.cpp +++ b/frontend/control/stack-pages/search-result-page.cpp @@ -42,20 +42,57 @@ void SearchResultPage::setSize(const int&width, const int&height) void SearchResultPage::setInternalPlugins() { - Q_FOREACH (QString plugin_id, SearchPluginManager::getInstance()->getPluginIds()) { - ResultWidget * widget = new ResultWidget(plugin_id, m_resultArea); + QList infoList = SearchPluginManager::getInstance()->getPluginIds(); + QVector pluginOrders(infoList.size()); + for (const PluginInfo& info : infoList) { + if (info.isEnable() and info.order() > 0) { + if (info.order() > pluginOrders.size()) { + QVector tmpVct(info.order() - pluginOrders.size()); + pluginOrders.append(tmpVct); + } + pluginOrders[info.order() - 1] = info.name(); + } + } + pluginOrders.removeAll(""); + + for (const QString& pluginId : pluginOrders) { + ResultWidget * widget = new ResultWidget(pluginId, m_resultArea); m_resultArea->appendWidet(widget); setupConnectionsForWidget(widget); } + } void SearchResultPage::appendPlugin(const QString &plugin_id) { ResultWidget * widget = new ResultWidget(plugin_id, m_resultArea); - m_resultArea->appendWidet(widget); + QList infoList = SearchPluginManager::getInstance()->getPluginIds(); + QVector pluginOrders(infoList.size()); + for (const PluginInfo& info : infoList) { + if (info.isEnable() and info.order() > 0) { + if (info.order() > pluginOrders.size()) { + QVector tmpVct(info.order() - pluginOrders.size()); + pluginOrders.append(tmpVct); + } + pluginOrders[info.order() - 1] = info.name(); + } + } + pluginOrders.removeAll(""); + + if (pluginOrders.contains(plugin_id)) { + m_resultArea->insertWidget(widget, pluginOrders.indexOf(plugin_id) + 1); + } else { + m_resultArea->insertWidget(widget, pluginOrders.size()); + } + setupConnectionsForWidget(widget); } +void SearchResultPage::movePlugin(const QString &plugin_id, int index) +{ + m_resultArea->moveWidget(plugin_id, index); +} + void SearchResultPage::pressEnter() { this->m_resultArea->pressEnter(); @@ -177,6 +214,9 @@ void SearchResultPage::initConnections() connect(qApp, &QApplication::paletteChanged, this, [=]() { update(); }); + + connect(SearchPluginManager::getInstance(), &SearchPluginManager::reRegistered, this, &SearchResultPage::appendPlugin); + connect(SearchPluginManager::getInstance(), &SearchPluginManager::changePos, this, &SearchResultPage::movePlugin); } void SearchResultPage::setupConnectionsForWidget(ResultWidget *widget) diff --git a/frontend/control/stack-pages/search-result-page.h b/frontend/control/stack-pages/search-result-page.h index 1c1d42f..2813c7f 100644 --- a/frontend/control/stack-pages/search-result-page.h +++ b/frontend/control/stack-pages/search-result-page.h @@ -34,6 +34,7 @@ public: void setSize(const int&, const int&); void setInternalPlugins(); void appendPlugin(const QString &plugin_id); + void movePlugin(const QString &plugin_id, int index); void pressEnter(); void pressUp(); void pressDown(); diff --git a/frontend/mainwindow.cpp b/frontend/mainwindow.cpp index d04e876..e2e73f9 100644 --- a/frontend/mainwindow.cpp +++ b/frontend/mainwindow.cpp @@ -313,7 +313,7 @@ void MainWindow::searchKeywordSlot(const QString &keyword) // m_stackedWidget->setPage(int(StackedPage::HomePage)); QTimer::singleShot(10, this, [ = ]() { m_askTimer->stop(); -// Q_EMIT m_searchResultPage->stopSearch(); + Q_EMIT m_searchResultPage->stopSearch(); m_searchResultPage->hide(); this->resizeHeight(68); }); diff --git a/frontend/model/best-list-model.cpp b/frontend/model/best-list-model.cpp index 1860191..97f5159 100644 --- a/frontend/model/best-list-model.cpp +++ b/frontend/model/best-list-model.cpp @@ -130,8 +130,22 @@ void BestListModel::appendInfo(const QString &pluginId, const SearchPluginIface: m_item->m_result_info_list.append(info); QVector result_info_list_tmp; QVector plugin_id_list_tmp; - QStringList plugin_order = SearchPluginManager::getInstance()->getPluginIds(); - Q_FOREACH (QString plugin, plugin_order) { + + + QList infoList = SearchPluginManager::getInstance()->getPluginIds(); + QVector orders(infoList.length()); + for (const PluginInfo& info : infoList) { + if (info.isEnable() and info.order() > 0) { + if (info.order() > orders.size()) { + QVector tmpVct(info.order() - orders.size()); + orders.append(tmpVct); + } + orders[info.order() - 1] = info.name(); + } + } + orders.removeAll(""); + + Q_FOREACH (const QString& plugin, orders) { if (m_plugin_id_list.contains(plugin)) { result_info_list_tmp.append(m_item->m_result_info_list.at(m_plugin_id_list.lastIndexOf(plugin))); plugin_id_list_tmp.append(plugin); @@ -146,6 +160,44 @@ void BestListModel::appendInfo(const QString &pluginId, const SearchPluginIface: } +void BestListModel::removeInfo(const QString &pluginId) +{ + this->beginResetModel(); + int index = m_plugin_id_list.lastIndexOf(pluginId); + if (index == -1) { + return; + } + m_item->m_result_info_list.removeAt(index); + m_plugin_id_list.removeAll(pluginId); + this->endResetModel(); + Q_EMIT this->itemListChanged(m_item->m_result_info_list.length()); +} + +void BestListModel::moveInfo(const QString &pluginName, const int pos) +{ + this->beginResetModel(); + int index = m_plugin_id_list.lastIndexOf(pluginName); + if (index == -1) { + return; + } + + m_plugin_id_list.removeAll(pluginName); + if (pos > m_plugin_id_list.size()) { + m_plugin_id_list.append(pluginName); + } else { + m_plugin_id_list.insert(pos - 1, pluginName); + } + + SearchPluginIface::ResultInfo info = m_item->m_result_info_list.at(index); + m_item->m_result_info_list.removeAt(index); + if (pos > m_item->m_result_info_list.size()) { + m_item->m_result_info_list.append(info); + } else { + m_item->m_result_info_list.insert(pos - 1, info); + } + this->endResetModel(); +} + void BestListModel::startSearch(const QString &keyword) { if (!m_item->m_result_info_list.isEmpty()) { diff --git a/frontend/model/best-list-model.h b/frontend/model/best-list-model.h index d38af16..c39c8a8 100644 --- a/frontend/model/best-list-model.h +++ b/frontend/model/best-list-model.h @@ -33,6 +33,8 @@ public: public Q_SLOTS: void appendInfo(const QString &, const SearchPluginIface::ResultInfo &); + void removeInfo(const QString &); + void moveInfo(const QString &pluginName, const int pos); void startSearch(const QString &); Q_SIGNALS: diff --git a/frontend/ukui-search-gui.cpp b/frontend/ukui-search-gui.cpp index 2420dbf..2f1482e 100644 --- a/frontend/ukui-search-gui.cpp +++ b/frontend/ukui-search-gui.cpp @@ -85,12 +85,24 @@ void UkuiSearchGui::parseCmd(QString msg, bool isPrimary) parser.addHelpOption(); parser.addVersionOption(); - QCommandLineOption quitOption(QStringList()<<"q"<<"quit", tr("Quit ukui-search application")); + QCommandLineOption quitOption(QStringList{"q","quit"}, tr("Quit ukui-search application")); parser.addOption(quitOption); - QCommandLineOption showOption(QStringList()<<"s"<<"show", tr("Show main window")); + QCommandLineOption showOption(QStringList{"s","show"}, tr("Show main window")); parser.addOption(showOption); + QCommandLineOption unregisterOption("unregister", tr("unregister a plugin with "), "pluginName"); + parser.addOption(unregisterOption); + + QCommandLineOption registerOption("register", tr("register a plugin with "), "pluginName"); + parser.addOption(registerOption); + + QCommandLineOption moveOption(QStringList{"m", "move"}, tr("move to the target pos"), "pluginName"); + parser.addOption(moveOption); + + QCommandLineOption indexOption(QStringList{"i", "index"}, tr("move plugin to "), "index"); + parser.addOption(indexOption); + if (isPrimary) { const QStringList args = QString(msg).split(' '); parser.process(args); @@ -100,6 +112,21 @@ void UkuiSearchGui::parseCmd(QString msg, bool isPrimary) if (parser.isSet(quitOption)) { this->quit(); } + if (parser.isSet(unregisterOption)) { + QString pluginName = parser.value(unregisterOption); + qDebug() << "unregister plugin:" << pluginName << SearchPluginManager::getInstance()->unregisterPlugin(pluginName); + } + if (parser.isSet(registerOption)) { + qDebug() << parser.values("register"); + QString pluginName = parser.value(registerOption); + + qDebug() << "register plugin:" << pluginName << SearchPluginManager::getInstance()->reRegisterPlugin(pluginName); + } + if (parser.isSet(moveOption) and parser.isSet(indexOption)) { + QString pluginName = parser.value(moveOption); + int pos = parser.value(indexOption).toInt(); + qDebug() << QString("move plugin:%1 to %2").arg(pluginName).arg(pos) << SearchPluginManager::getInstance()->changePluginPos(pluginName, pos); + } } else { if (arguments().count() < 2) { diff --git a/frontend/view/best-list-view.cpp b/frontend/view/best-list-view.cpp index ea89998..547689f 100644 --- a/frontend/view/best-list-view.cpp +++ b/frontend/view/best-list-view.cpp @@ -209,6 +209,16 @@ void BestListView::initConnections() this->setCurrentIndex(index); } }); + connect(SearchPluginManager::getInstance(), &SearchPluginManager::unregistered, this, [=] (const QString &plugin) { + QModelIndex index = this->currentIndex(); + this->m_model->removeInfo(plugin); + if (index.isValid()) { + this->setCurrentIndex(index); + } + }); + connect(SearchPluginManager::getInstance(), &SearchPluginManager::changePos, this, [ = ] (const QString &pluginName, const int index){ + this->m_model->moveInfo(pluginName, index); + }); } BestListWidget::BestListWidget(QWidget *parent) : QWidget(parent) diff --git a/libsearch/appsearch/app-search-plugin.cpp b/libsearch/appsearch/app-search-plugin.cpp index 0132767..da4efc7 100644 --- a/libsearch/appsearch/app-search-plugin.cpp +++ b/libsearch/appsearch/app-search-plugin.cpp @@ -18,10 +18,10 @@ AppSearchPlugin::AppSearchPlugin(QObject *parent) : QThread(parent), m_appSearch // m_pool.setExpiryTimeout(1000); initDetailPage(); - m_timer = new QTimer(this); + m_timer = new QTimer; m_timer->setInterval(3000); m_timer->moveToThread(this); - connect(this, SIGNAL(startTimer), m_timer, SLOT(start())); + connect(this, SIGNAL(startTimer()), m_timer, SLOT(start())); connect(this, &AppSearchPlugin::stopTimer, m_timer, &QTimer::stop); connect(m_timer, &QTimer::timeout, this, [ & ]{ qWarning() << "The app-search thread stopped because of timeout."; @@ -63,6 +63,16 @@ AppSearchPlugin::AppSearchPlugin(QObject *parent) : QThread(parent), m_appSearch }); } +AppSearchPlugin::~AppSearchPlugin() +{ + this->quit(); + this->wait(); + if (m_timer) { + delete m_timer; + m_timer = nullptr; + } +} + const QString AppSearchPlugin::name() { return "Applications Search"; diff --git a/libsearch/appsearch/app-search-plugin.h b/libsearch/appsearch/app-search-plugin.h index 13eb7b5..ee14954 100644 --- a/libsearch/appsearch/app-search-plugin.h +++ b/libsearch/appsearch/app-search-plugin.h @@ -24,6 +24,7 @@ class LIBSEARCH_EXPORT AppSearchPlugin : public QThread, public SearchPluginIfac Q_OBJECT public: AppSearchPlugin(QObject *parent = nullptr); + ~AppSearchPlugin(); PluginType pluginType() {return PluginType::SearchPlugin;} const QString name(); const QString description(); diff --git a/libsearch/pluginmanage/plugin-info.h b/libsearch/pluginmanage/plugin-info.h new file mode 100644 index 0000000..cb25368 --- /dev/null +++ b/libsearch/pluginmanage/plugin-info.h @@ -0,0 +1,37 @@ +#ifndef PLUGININFO_H +#define PLUGININFO_H + +#include + +namespace UkuiSearch { + +class PluginInfo +{ + +public: + explicit PluginInfo(QString name, bool enable, int order, bool isFixed, bool isExternal, QString path = QString()) + : m_name(name), + m_enable(enable), + m_order(order), + m_isFixed(isFixed), + m_isExternal(isExternal), + m_path(path) {} + QString name() const {return m_name;} + int order() const {return m_order;} + bool isEnable() const {return m_enable;} + bool isFixed() const {return m_isFixed;} + bool isExternal() const {return m_isExternal;} + QString path() const {return m_path;} + +private: + QString m_name; + QString m_path; + int m_order; + bool m_enable; + bool m_isExternal; + bool m_isFixed; +}; + +} + +#endif // PLUGININFO_H diff --git a/libsearch/pluginmanage/plugin-manager.cpp b/libsearch/pluginmanage/plugin-manager.cpp index 0ec7a6c..3053e68 100644 --- a/libsearch/pluginmanage/plugin-manager.cpp +++ b/libsearch/pluginmanage/plugin-manager.cpp @@ -58,7 +58,9 @@ PluginManager::PluginManager(QObject *parent) : QObject(parent) switch (piface->pluginType()) { case PluginInterface::PluginType::SearchPlugin: { auto p = dynamic_cast(plugin); - SearchPluginManager::getInstance()->registerPlugin(p); + if (!SearchPluginManager::getInstance()->registerExternalPlugin(p, pluginsDir.absoluteFilePath(fileName))) { + m_hash.erase(m_hash.find(piface->name())); + } break; } case PluginInterface::PluginType::SearchTaskPlugin: { diff --git a/libsearch/pluginmanage/plugin-manager.pri b/libsearch/pluginmanage/plugin-manager.pri index 87c7157..e4d0a91 100644 --- a/libsearch/pluginmanage/plugin-manager.pri +++ b/libsearch/pluginmanage/plugin-manager.pri @@ -1,6 +1,7 @@ INCLUDEPATH += $$PWD HEADERS += \ + $$PWD/plugin-info.h \ $$PWD/search-plugin-manager.h \ $$PWD/plugin-manager.h \ $$PWD/search-task-plugin-manager.h diff --git a/libsearch/pluginmanage/search-plugin-manager.cpp b/libsearch/pluginmanage/search-plugin-manager.cpp index 20e759b..4f87019 100644 --- a/libsearch/pluginmanage/search-plugin-manager.cpp +++ b/libsearch/pluginmanage/search-plugin-manager.cpp @@ -7,30 +7,383 @@ #include "web-search-plugin.h" #include "mail-search-plugin.h" +#define PLUGIN_ORDER_SETTINGS QDir::homePath() + "/.config/org.ukui/ukui-search/ukui-search-plugin-order.conf" +#define PLUGINS_INFO_GROUP "PluginsInfo" +#define EXTERNAL_PLUGINS_GROUP "ExternalPlugins" +#define PLUGIN_NAME_VALUE "PluginName" +#define PLUGIN_ORDER_VALUE "Order" +#define PLUGIN_ENABLE_VALUE "Enable" +#define PLUGIN_EXTERNAL_VALUE "External" +#define PLUGIN_PATH_VALUE "Path" +#define PLUGIN_FIX_VALUE "FixPos" + using namespace UkuiSearch; static SearchPluginManager *global_instance = nullptr; SearchPluginManager::SearchPluginManager(QObject *parent) { - registerPlugin(new AppSearchPlugin(this)); - registerPlugin(new NoteSearchPlugin(this)); - registerPlugin(new SettingsSearchPlugin(this)); - registerPlugin(new DirSearchPlugin(this)); - registerPlugin(new FileSearchPlugin(this)); - registerPlugin(new FileContengSearchPlugin(this)); + initOrderSettings(); + registerPlugin(new AppSearchPlugin); + registerPlugin(new NoteSearchPlugin); + registerPlugin(new SettingsSearchPlugin); + registerPlugin(new DirSearchPlugin); + registerPlugin(new FileSearchPlugin); + registerPlugin(new FileContengSearchPlugin); // registerPlugin(new MailSearchPlugin(this)); - registerPlugin(new WebSearchPlugin(this)); + registerPlugin(new WebSearchPlugin); } bool SearchPluginManager::registerPlugin(UkuiSearch::SearchPluginIface *plugin) { - if (m_map.end() != m_map.find(plugin->name())){ - return false; + bool res(false); + + if (m_map.end() != m_map.find(plugin->name())) { + qWarning() << "the plugin:" << plugin->name() << "has been registered."; + return res; + } + + m_orderSettings->beginGroup(PLUGINS_INFO_GROUP); + QStringList plugins = m_orderSettings->childGroups(); + if (plugins.contains(plugin->name())) { + m_orderSettings->beginGroup(plugin->name()); + if (!m_orderSettings->value(PLUGIN_ENABLE_VALUE).toBool()) { + qWarning() << "plugin: " << plugin->name() << "is not available now."; + } else { + m_map[plugin->name()] = plugin; + qDebug() << "register search plugin: " << plugin->name(); + res = true; + } + m_orderSettings->endGroup(); + } else { + qWarning() << "Fail to register, can not find plugin:" << plugin->name() << "in config file"; + } + m_orderSettings->endGroup(); + + if (!res) { + qWarning() << "Can not register plugin:" << plugin->name(); + if (plugin) { + delete plugin; + plugin = nullptr; + } + } + return res; +} + +bool SearchPluginManager::registerExternalPlugin(SearchPluginIface *plugin, const QString &path) +{ + //TODO: external plugin need a life cycle management! + bool res(false); + if (m_map.end() != m_map.find(plugin->name())) { + qWarning() << "the plugin:" << plugin->name() << "has been registered."; + return res; + } + + m_orderSettings->beginGroup(PLUGINS_INFO_GROUP); + QStringList plugins = m_orderSettings->childGroups(); + if (!plugins.contains(plugin->name())) { + int pluginOrder = plugins.length() + 1; + //网页搜索为最后一项 + if (plugins.contains("Web Page")) { + m_orderSettings->beginGroup("Web Page"); + m_orderSettings->setValue(PLUGIN_ORDER_VALUE, pluginOrder); + m_orderSettings->endGroup(); + pluginOrder--; + } + //更新配置文件 + m_orderSettings->beginGroup(plugin->name()); + m_orderSettings->setValue(PLUGIN_PATH_VALUE, path); + m_orderSettings->setValue(PLUGIN_ORDER_VALUE, pluginOrder); + m_orderSettings->setValue(PLUGIN_ENABLE_VALUE, true); + m_orderSettings->setValue(PLUGIN_EXTERNAL_VALUE, true); + m_orderSettings->setValue(PLUGIN_FIX_VALUE, false); + m_orderSettings->endGroup(); + } + + if (m_orderSettings->value(plugin->name() + QString("/") + PLUGIN_ENABLE_VALUE).toBool()) { + m_map[plugin->name()] = plugin; + qDebug() << "register search plugin: " << path; + res = true; + } else { + qWarning() << "Plugin is not available.Fail to register: " << plugin->name(); + } + m_orderSettings->endGroup(); + + m_orderSettings->beginGroup(EXTERNAL_PLUGINS_GROUP); + m_orderSettings->setValue(path, plugin->name()); + m_orderSettings->endGroup(); + + return res; +} + +bool SearchPluginManager::reRegisterPlugin(const QString &pluginName) +{ + QString name; + if (pluginName == "Web") { + name = pluginName + " Page"; + } else if (pluginName == "Content") { + name = "File " + name + " Search"; + } else if (pluginName.contains(".so")) { + m_orderSettings->beginGroup(EXTERNAL_PLUGINS_GROUP); + name = m_orderSettings->value(pluginName).toString(); + m_orderSettings->endGroup(); + } else { + name = pluginName + " Search"; + } + bool res(false); + if (m_map.end() == m_map.find(name)) { + bool isExternal(false); + QVariant value = m_orderSettings->value(PLUGINS_INFO_GROUP + QString("/") + name); + if (value.isNull()) { + isExternal = true; + } else { + isExternal = value.toBool(); + } + if (pluginName == "Applications") { + reRegisterPlugin(new AppSearchPlugin, isExternal); + res = true; + } else if (pluginName == "Note") { + reRegisterPlugin(new NoteSearchPlugin, isExternal); + res = true; + } else if (pluginName == "Settings") { + reRegisterPlugin(new SettingsSearchPlugin, isExternal); + res = true; + } else if (pluginName == "Dir") { + reRegisterPlugin(new DirSearchPlugin, isExternal); + res = true; + } else if (pluginName == "File") { + reRegisterPlugin(new FileSearchPlugin, isExternal); + res = true; + } else if (pluginName == "Content") { + reRegisterPlugin(new FileContengSearchPlugin, isExternal); + res = true; + } else if (pluginName == "Web") { + reRegisterPlugin(new WebSearchPlugin, isExternal); + res = true; + } else if (pluginName.contains(".so")) { + //外部插件pluginName为so文件全路径 + QPluginLoader loader(pluginName); + // version check + QString type = loader.metaData().value("MetaData").toObject().value("type").toString(); + QString version = loader.metaData().value("MetaData").toObject().value("version").toString(); + if(type == "SEARCH_PLUGIN" and version == SEARCH_PLUGIN_IFACE_VERSION) { + QObject *plugin = loader.instance(); + if (plugin) { + auto externalPlugin = dynamic_cast(plugin); + reRegisterPlugin(externalPlugin, isExternal, pluginName); + res = true; + } + } + + } else { + return res; + } + } + + return res; +} + +bool SearchPluginManager::reRegisterPlugin(SearchPluginIface *plugin, bool isExternal, const QString &externalPluginPath) +{ + bool res(false); + if (m_map.end() != m_map.find(plugin->name())) { + qWarning() << "plugin " << plugin->name() << "has been registered."; + if (plugin) { + delete plugin; + plugin = nullptr; + } + return res; } m_map[plugin->name()] = plugin; - qDebug() << "register search plugin: " << plugin->name(); - m_plugin_order[m_plugin_order.size()] = plugin->name();//按注册顺序绑定优先级 + + if (isExternal) { + if (!externalPluginPath.isEmpty()) { + m_orderSettings->beginGroup(EXTERNAL_PLUGINS_GROUP); + m_orderSettings->setValue(externalPluginPath, plugin->name()); + m_orderSettings->endGroup(); + } else { + qWarning() << QString("Can not identify external plugin %1 through a empty path!").arg(plugin->name()); + } + } + + m_orderSettings->beginGroup(PLUGINS_INFO_GROUP); + QStringList plugins = m_orderSettings->childGroups(); + if (plugins.contains(plugin->name())) { + m_orderSettings->beginGroup(plugin->name()); + m_orderSettings->setValue(PLUGIN_ENABLE_VALUE, true); + m_orderSettings->endGroup(); + res = true; + } else { + qWarning() << "Fail to re-register plugin" << plugin->name() << " Conf file error!"; + } + m_orderSettings->endGroup(); + + if (!res) { + if (plugin) { + delete plugin; + plugin = nullptr; + } + } else { + Q_EMIT this->reRegistered(plugin->name()); + } + return res; +} + +bool SearchPluginManager::unregisterPlugin(const QString &pluginName) +{ + //用来测试命令行的字符串拼接 + QString name = pluginName + " Search"; + if (pluginName == "Web") { + name = pluginName + " Page"; + } else if (pluginName == "Content") { + name = "File " + name + " Search"; + } + //外部插件pluginName是so文件全路径 + QString externalPluginPath; + if (pluginName.contains(".so")) { + externalPluginPath = pluginName; + m_orderSettings->beginGroup(EXTERNAL_PLUGINS_GROUP); + name = m_orderSettings->value(externalPluginPath).toString(); + m_orderSettings->endGroup(); + } + + if (m_map.end() == m_map.find(name)) { + qWarning() << "plugin:" << name << "has not been registered."; + return false; + } + Q_EMIT this->unregistered(name); + + if (m_map[name]) { + m_map[name]->stopSearch(); + delete m_map[name]; + m_map[name] = nullptr; + } + m_map.erase(m_map.find(name)); + + if (!externalPluginPath.isEmpty()) { + m_orderSettings->remove(EXTERNAL_PLUGINS_GROUP + QString("/") + externalPluginPath); + } + m_orderSettings->beginGroup(PLUGINS_INFO_GROUP + QString("/") + name); + m_orderSettings->setValue(PLUGIN_ENABLE_VALUE, false); + m_orderSettings->endGroup(); + return true; + /* +// m_plugin_order.clear(); +// int i = 0; +// for (auto iter = m_map.cbegin(); iter != m_map.cend(); iter++) { +// m_plugin_order[i] = iter->first; +// i++; +// } + +// std::map::iterator iter; +// bool removed(false); +// for (iter = m_plugin_order.begin(); iter != m_plugin_order.end();) { +// if (iter->second == name) { +// iter = m_plugin_order.erase(iter); +// removed = true; +// } else if (removed) { +// m_plugin_order[iter->first - 1] = iter->second; +// iter = m_plugin_order.erase(iter); +// } else { +// iter++; +// } +// } +// return true; + */ +} + +bool SearchPluginManager::changePluginPos(const QString &pluginName, int pos) +{ + bool res(false); + if (pos < 1) { + qWarning() << "Invalid destination position!"; + return res; + } + //用来测试命令行的字符串拼接 + QString name = pluginName + " Search"; + if (pluginName == "Web") { + name = pluginName + " Page"; + } else if (pluginName == "Content") { + name = "File " + name + " Search"; + } else if (pluginName.contains(".so")) { + m_orderSettings->beginGroup(EXTERNAL_PLUGINS_GROUP); + name = m_orderSettings->value(pluginName).toString(); + m_orderSettings->endGroup(); + } + + if (m_map.find(name) == m_map.end()) { + qWarning() << "Fail to change pos, plugin" << name << "has not been registered."; + return res; + } + + m_orderSettings->beginGroup(PLUGINS_INFO_GROUP); + QStringList plugins = m_orderSettings->childGroups(); + int oldOrder = m_orderSettings->value(name + QString("/") + PLUGIN_ORDER_VALUE).toInt(); + + if (oldOrder < 1) { + qWarning() << "Invalid order value of " << name; + m_orderSettings->endGroup(); + return res; + } + + if (oldOrder == pos) { + qWarning() << "Plugin's position has not been changed"; + m_orderSettings->endGroup(); + return res; + } + + for (const QString& orderName : plugins) { + m_orderSettings->beginGroup(orderName); + if (orderName == name) { + m_orderSettings->setValue(PLUGIN_ORDER_VALUE, pos); + } else { + int orderValue = m_orderSettings->value(PLUGIN_ORDER_VALUE).toInt(); + if (oldOrder > pos and orderValue >= pos and orderValue < oldOrder) { + m_orderSettings->setValue(PLUGIN_ORDER_VALUE, orderValue + 1); + } else if (oldOrder < pos and orderValue > oldOrder and orderValue <= pos) { + m_orderSettings->setValue(PLUGIN_ORDER_VALUE, orderValue - 1); + } + } + m_orderSettings->endGroup(); + } + m_orderSettings->endGroup(); + + Q_EMIT this->changePos(name, pos); + return res; +} + +bool SearchPluginManager::unregisterPlugin(SearchPluginIface *plugin, bool isExternal, const QString &externalPluginPath) +{ + bool res(false); + if (m_map.end() == m_map.find(plugin->name())) { + qWarning() << "plugin:" << plugin->name() << "has not been registered."; + return res; + } + Q_EMIT this->unregistered(plugin->name()); + + if (m_map[plugin->name()]) { + m_map[plugin->name()]->stopSearch(); + delete m_map[plugin->name()]; + m_map[plugin->name()] = nullptr; + } + m_map.erase(m_map.find(plugin->name())); + + if (isExternal) { + if (!externalPluginPath.isEmpty()) { + m_orderSettings->beginGroup(EXTERNAL_PLUGINS_GROUP); + m_orderSettings->remove(externalPluginPath); + m_orderSettings->endGroup(); + res = true; + } else { + qWarning() << "Fail to unregister, can not identify the plugin through a empty path."; + } + } + + m_orderSettings->beginGroup(PLUGINS_INFO_GROUP + QString("/") + plugin->name()); + m_orderSettings->setValue(PLUGIN_ENABLE_VALUE, false); + m_orderSettings->endGroup(); + + return res; } SearchPluginManager *SearchPluginManager::getInstance() @@ -41,13 +394,26 @@ SearchPluginManager *SearchPluginManager::getInstance() return global_instance; } -const QStringList SearchPluginManager::getPluginIds() +const QList SearchPluginManager::getPluginIds() { - QStringList list; - for (auto i = m_plugin_order.begin(); i != m_plugin_order.end(); i++) { - list.append(m_plugin_order[(*i).first]);//根据优先级返回plugin ID + QList infoList; + m_orderSettings->beginGroup(PLUGINS_INFO_GROUP); + QStringList plugins = m_orderSettings->childGroups(); + for (const QString& pluginName : plugins) { + if (m_map.find(pluginName) != m_map.end()) { + m_orderSettings->beginGroup(pluginName); + PluginInfo info(pluginName, + m_orderSettings->value(PLUGIN_ENABLE_VALUE).toBool(), + m_orderSettings->value(PLUGIN_ORDER_VALUE).toInt(), + m_orderSettings->value(PLUGIN_FIX_VALUE).toBool(), + m_orderSettings->value(PLUGIN_EXTERNAL_VALUE).toBool(), + m_orderSettings->value(PLUGIN_PATH_VALUE).toString()); + m_orderSettings->endGroup(); + infoList.append(info); + } } - return list; + m_orderSettings->endGroup(); + return infoList; } SearchPluginIface *SearchPluginManager::getPlugin(const QString &pluginId) @@ -62,5 +428,35 @@ void SearchPluginManager::close() SearchPluginManager::~SearchPluginManager() { + for (auto iter = m_map.begin(); iter != m_map.end();) { + if (iter->second) { + delete iter->second; + iter->second = nullptr; + } + } m_map.clear(); } + +void SearchPluginManager::initOrderSettings() +{ + m_orderSettings = new QSettings(PLUGIN_ORDER_SETTINGS, QSettings::IniFormat, this); + + m_orderSettings->beginGroup(PLUGINS_INFO_GROUP); + if (m_orderSettings->childGroups().isEmpty()) { + bool isFixed(false); + for (int i = 0; i < m_defaultPluginOrder.size(); i++) { + QString pluginName = m_defaultPluginOrder.at(i); + //默认Web Page固定位置 + if (pluginName == "Web Page") { + isFixed = true; + } + m_orderSettings->beginGroup(pluginName); + m_orderSettings->setValue(PLUGIN_ORDER_VALUE, i + 1); + m_orderSettings->setValue(PLUGIN_ENABLE_VALUE, true); + m_orderSettings->setValue(PLUGIN_EXTERNAL_VALUE, false); + m_orderSettings->setValue(PLUGIN_FIX_VALUE, isFixed); + m_orderSettings->endGroup(); + } + } + m_orderSettings->endGroup(); +} diff --git a/libsearch/pluginmanage/search-plugin-manager.h b/libsearch/pluginmanage/search-plugin-manager.h index be13018..5d76b99 100644 --- a/libsearch/pluginmanage/search-plugin-manager.h +++ b/libsearch/pluginmanage/search-plugin-manager.h @@ -2,28 +2,58 @@ #define SEARCHPLUGINFACTORY_H #include +#include #include "search-plugin-iface.h" +#include "plugin-info.h" namespace UkuiSearch { class SearchPluginManager : public QObject { Q_OBJECT + + QStringList m_defaultPluginOrder = { + "Applications Search", + "Note Search", + "Settings Search", + "Dir Search", + "File Search", + "File Content Search", + "Web Page" + }; + public: bool registerPlugin(SearchPluginIface *plugin); + bool registerExternalPlugin(SearchPluginIface *plugin, const QString &path); + bool reRegisterPlugin(SearchPluginIface *plugin, bool isExternal, const QString &externalPluginPath = QString()); + bool unregisterPlugin(SearchPluginIface *plugin, bool isExternal, const QString &externalPluginPath = QString()); + + //测试用接口 + bool reRegisterPlugin(const QString &pluginName); + bool unregisterPlugin(const QString &pluginName); + bool changePluginPos(const QString &pluginName, int pos); static SearchPluginManager *getInstance(); - const QStringList getPluginIds(); + const QList getPluginIds(); SearchPluginIface *getPlugin(const QString &pluginId); void close(); private: - std::map m_map; - std::map m_plugin_order;//绑定plugin ID和优先级 explicit SearchPluginManager(QObject *parent = nullptr); ~SearchPluginManager(); + void initOrderSettings(); + std::map m_map; + std::map m_plugin_order;//绑定plugin ID和优先级 + + QSettings *m_orderSettings = nullptr; + QStringList m_externalPlugins; + +Q_SIGNALS: + void unregistered(const QString& pluginName); + void reRegistered(const QString& pluginName); + void changePos(const QString& pluginName, int index); }; }