From bf5171572189f77e6f81b1d6e9c18df061a922ff Mon Sep 17 00:00:00 2001 From: iaom Date: Mon, 4 Mar 2024 17:55:42 +0800 Subject: [PATCH] =?UTF-8?q?fix(frontend):=E7=BB=93=E6=9E=9C=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E4=B8=AD=E6=9C=AA=E8=A2=AB=E6=88=AA=E6=96=AD=E7=9A=84?= =?UTF-8?q?=E9=A1=B9=E4=B8=8D=E5=86=8D=E6=98=BE=E7=A4=BAtooltip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/CMakeLists.txt | 1 + frontend/model/best-list-model.cpp | 115 +++++++++++-------------- frontend/model/best-list-model.h | 13 ++- frontend/model/one-result.cpp | 41 +++++++++ frontend/model/one-result.h | 43 +++++++++ frontend/model/search-result-model.cpp | 50 ++++++++--- frontend/model/search-result-model.h | 11 ++- frontend/view/best-list-view.cpp | 15 ++++ frontend/view/best-list-view.h | 8 +- frontend/view/result-view-delegate.cpp | 19 +++- frontend/view/result-view-delegate.h | 1 + frontend/view/result-view.cpp | 15 ++++ 12 files changed, 240 insertions(+), 92 deletions(-) create mode 100644 frontend/model/one-result.cpp create mode 100644 frontend/model/one-result.h diff --git a/frontend/CMakeLists.txt b/frontend/CMakeLists.txt index f22d309..75ba0d7 100644 --- a/frontend/CMakeLists.txt +++ b/frontend/CMakeLists.txt @@ -42,6 +42,7 @@ set(UKUI_SEARCH_SRC model/best-list-model.cpp model/best-list-model.h model/search-result-manager.cpp model/search-result-manager.h model/search-result-model.cpp model/search-result-model.h + model/one-result.cpp model/one-result.h search-app-widget-plugin/search.cpp search-app-widget-plugin/search.h ukui-search-dbus-service.cpp ukui-search-dbus-service.h ukui-search-gui.cpp ukui-search-gui.h diff --git a/frontend/model/best-list-model.cpp b/frontend/model/best-list-model.cpp index fe3c8ab..8fd7a82 100644 --- a/frontend/model/best-list-model.cpp +++ b/frontend/model/best-list-model.cpp @@ -25,7 +25,6 @@ using namespace UkuiSearch; BestListModel::BestListModel(QObject *parent) : QAbstractItemModel(parent) { - initConnections(); } QModelIndex BestListModel::index(int row, int column, const QModelIndex &parent) const @@ -55,29 +54,32 @@ int BestListModel::columnCount(const QModelIndex &parent) const QVariant BestListModel::data(const QModelIndex &index, int role) const { switch(role) { - case Qt::DecorationRole: { - return m_items.at(index.row()).icon; + case Qt::DecorationRole: { + return m_items.at(index.row())->info().icon; + } + case Qt::DisplayRole: { + return m_items.at(index.row())->info().name; + } + case Qt::ToolTipRole: { + return m_items.at(index.row())->info().toolTip; + } + case AdditionalRoles::ShowToolTip: { + return m_items.at(index.row())->showToolTip(); + } + + default: + return {}; } - case Qt::DisplayRole: { - return m_items.at(index.row()).name; - } - case Qt::ToolTipRole: { - return m_items.at(index.row()).toolTip; - } - default: - return QVariant(); - } - return QVariant(); } const SearchPluginIface::ResultInfo &BestListModel::getInfo(const QModelIndex &index) { - return m_items.at(index.row()); + return m_items.at(index.row())->info(); } const QString &BestListModel::getPluginInfo(const QModelIndex &index) { - return m_plugin_id_list.at(index.row()); + return m_pluginIdList.at(index.row()); } void BestListModel::setExpanded(const bool &is_expanded) @@ -93,47 +95,25 @@ const bool &BestListModel::isExpanded() return m_isExpanded; } -QStringList BestListModel::getActions(const QModelIndex &index) -{ -// if (m_item->m_result_info_list.length() > index.row() && index.row() >= 0) -// return m_item->m_result_info_list.at(index.row()).actionList; - Q_UNUSED(index) - return QStringList(); -} - -QString BestListModel::getKey(const QModelIndex &index) -{ - if (m_items.length() > index.row() && index.row() >= 0) - return m_items.at(index.row()).actionKey; - return NULL; -} - void BestListModel::appendInfo(const QString &pluginId, const SearchPluginIface::ResultInfo &info) { - if (m_plugin_action_key_list.contains(info.actionKey)) { -// qDebug() << "plugin ID:" << pluginId << "name:" << info.name << "action key:" << info.actionKey << "is same with pre-result!"; - return; - } else { - m_plugin_action_key_list.append(info.actionKey); - } - if (m_plugin_id_list.contains(pluginId)) { - if (info.name == m_items.at(m_plugin_id_list.lastIndexOf(pluginId)).name) { + if (m_pluginIdList.contains(pluginId)) { + if (info.actionKey == m_items.at(m_pluginIdList.lastIndexOf(pluginId))->info().actionKey) { return; } -// qDebug()<<"plugin ID:"<endResetModel(); Q_EMIT this->itemListChanged(m_items.length()); @@ -165,12 +145,12 @@ void BestListModel::appendInfo(const QString &pluginId, const SearchPluginIface: void BestListModel::removeInfo(const QString &pluginId) { this->beginResetModel(); - int index = m_plugin_id_list.lastIndexOf(pluginId); + int index = m_pluginIdList.lastIndexOf(pluginId); if (index == -1) { return; } m_items.removeAt(index); - m_plugin_id_list.removeAll(pluginId); + m_pluginIdList.removeAll(pluginId); this->endResetModel(); Q_EMIT this->itemListChanged(m_items.length()); } @@ -178,19 +158,19 @@ void BestListModel::removeInfo(const QString &pluginId) void BestListModel::moveInfo(const QString &pluginName, const int pos) { this->beginResetModel(); - int index = m_plugin_id_list.lastIndexOf(pluginName); + int index = m_pluginIdList.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); + m_pluginIdList.removeAll(pluginName); + if (pos > m_pluginIdList.size()) { + m_pluginIdList.append(pluginName); } else { - m_plugin_id_list.insert(pos - 1, pluginName); + m_pluginIdList.insert(pos - 1, pluginName); } - SearchPluginIface::ResultInfo info = m_items.at(index); + OneResult *info = m_items.at(index); m_items.removeAt(index); if (pos > m_items.size()) { m_items.append(info); @@ -205,21 +185,30 @@ void BestListModel::startSearch(const QString &keyword) Q_UNUSED(keyword) if (!m_items.isEmpty()) { this->beginResetModel(); - m_plugin_id_list.clear(); - m_plugin_action_key_list.clear(); + m_pluginIdList.clear(); + m_pluginActionKeyList.clear(); + qDeleteAll(m_items); m_items.clear(); this->endResetModel(); Q_EMIT this->itemListChanged(m_items.length()); } } -void BestListModel::initConnections() -{ - -} - BestListModel::~BestListModel() { + qDeleteAll(m_items); m_items.clear(); m_items.squeeze(); } + +bool BestListModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if(!index.isValid() || index.row() >= m_items.length()) { + return false; + } + if(role == ShowToolTip) { + m_items.at(index.row())->setShowToolTip(value.toBool()); + return true; + } + return false; +} diff --git a/frontend/model/best-list-model.h b/frontend/model/best-list-model.h index b70a0b8..dc745fb 100644 --- a/frontend/model/best-list-model.h +++ b/frontend/model/best-list-model.h @@ -40,6 +40,7 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; const SearchPluginIface::ResultInfo & getInfo(const QModelIndex&); const QString & getPluginInfo(const QModelIndex&); @@ -47,13 +48,10 @@ public: void setExpanded(const bool&); const bool &isExpanded(); - QStringList getActions(const QModelIndex &); - QString getKey(const QModelIndex &); - public Q_SLOTS: void appendInfo(const QString &, const SearchPluginIface::ResultInfo &); void removeInfo(const QString &); - void moveInfo(const QString &pluginName, const int pos); + void moveInfo(const QString &pluginName, int pos); void startSearch(const QString &); Q_SIGNALS: @@ -61,10 +59,9 @@ Q_SIGNALS: void itemListChanged(const int&); private: - void initConnections(); - QVector m_items; - QVector m_plugin_id_list; - QVector m_plugin_action_key_list; + QVector m_items; + QVector m_pluginIdList; + QVector m_pluginActionKeyList; bool m_isExpanded = false; }; } diff --git a/frontend/model/one-result.cpp b/frontend/model/one-result.cpp new file mode 100644 index 0000000..d21a5dd --- /dev/null +++ b/frontend/model/one-result.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ + +#include "one-result.h" + +using namespace UkuiSearch; + +UkuiSearch::OneResult::OneResult(const UkuiSearch::SearchPluginIface::ResultInfo &ri) : m_info(ri) +{ +} + +void OneResult::setShowToolTip(bool show) +{ + m_showToolTip = show; +} + +bool OneResult::showToolTip() const +{ + return m_showToolTip; +} + +const SearchPluginIface::ResultInfo &OneResult::info() const +{ + return m_info; +} diff --git a/frontend/model/one-result.h b/frontend/model/one-result.h new file mode 100644 index 0000000..12c3874 --- /dev/null +++ b/frontend/model/one-result.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#ifndef UKUI_SEARCH_ONE_RESULT_H +#define UKUI_SEARCH_ONE_RESULT_H + +#include "search-plugin-iface.h" +namespace UkuiSearch { +Q_NAMESPACE +enum AdditionalRoles { + ShowToolTip = Qt::UserRole + 1, +}; +Q_ENUM_NS(AdditionalRoles) + +class OneResult { +public: + explicit OneResult(const SearchPluginIface::ResultInfo &ri); + + void setShowToolTip(bool show); + [[nodiscard]] bool showToolTip() const; + [[nodiscard]] const SearchPluginIface::ResultInfo &info() const; + +private: + SearchPluginIface::ResultInfo m_info; + bool m_showToolTip = true; +}; +} +#endif //UKUI_SEARCH_ONE_RESULT_H diff --git a/frontend/model/search-result-model.cpp b/frontend/model/search-result-model.cpp index 474770f..fcf9dbb 100644 --- a/frontend/model/search-result-model.cpp +++ b/frontend/model/search-result-model.cpp @@ -1,4 +1,4 @@ -/* + /* * * Copyright (C) 2020, KylinSoft Co., Ltd. * @@ -18,6 +18,7 @@ * Authors: zhangjiaping * */ +#include #include "search-result-model.h" using namespace UkuiSearch; @@ -63,30 +64,32 @@ QVariant SearchResultModel::data(const QModelIndex &index, int role) const } switch(role) { case Qt::DecorationRole: { - return m_items.at(index.row()).icon; + return m_items.at(index.row())->info().icon; } case Qt::DisplayRole: { - return m_items.at(index.row()).name; + return m_items.at(index.row())->info().name; } case Qt::ToolTipRole: { - return m_items.at(index.row()).toolTip; + return m_items.at(index.row())->info().toolTip; + } + case AdditionalRoles::ShowToolTip: { + return m_items.at(index.row())->showToolTip(); } default: - return QVariant(); + return {}; } - return QVariant(); } void SearchResultModel::appendInfo(const SearchPluginIface::ResultInfo &info)//TODO 代码逻辑可尝试梳理优化 { if (m_items.length() > 5 //搜索结果大于5个并且搜索结果处于收起状态时只存储数据无需刷新UI and !m_isExpanded) { - m_items.append(info); + m_items.append(new OneResult(info)); return; } if (m_items.length() > 50 and m_isExpanded) {//搜索结果大于50个并且搜索结果处于展开状态时只存储数据并启动定时,500ms刷新一次UI - m_items.append(info); + m_items.append(new OneResult(info)); if (!m_timer->isActive()) { m_timer->start(); } @@ -94,12 +97,12 @@ void SearchResultModel::appendInfo(const SearchPluginIface::ResultInfo &info)//T } // this->beginResetModel(); beginInsertRows(QModelIndex(), m_items.length(), m_items.length()); - m_items.append(info); + m_items.append(new OneResult(info)); // this->endResetModel(); endInsertRows(); Q_EMIT this->itemListChanged(m_items.length()); if (m_plugin_id != "Web Page") { - Q_EMIT this->sendBestListData(m_plugin_id, m_items.at(0)); + Q_EMIT this->sendBestListData(m_plugin_id, m_items.at(0)->info()); } } @@ -126,7 +129,7 @@ void SearchResultModel::initConnections() const SearchPluginIface::ResultInfo &SearchResultModel::getInfo(const QModelIndex &index) { - return m_items.at(index.row()); + return m_items.at(index.row())->info(); } void SearchResultModel::setExpanded(const bool &is_expanded) @@ -151,6 +154,7 @@ void SearchResultModel::refresh() void SearchResultModel::stopSearchSlot() { beginResetModel(); + qDeleteAll(m_items); m_items.clear(); m_items.squeeze(); endResetModel(); @@ -159,6 +163,30 @@ void SearchResultModel::stopSearchSlot() SearchResultModel::~SearchResultModel() { + qDeleteAll(m_items); m_items.clear(); m_items.squeeze(); } + + QHash SearchResultModel::roleNames() const + { + QHash roles = QAbstractItemModel::roleNames(); + QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles")); + + for (int i = 0; i < e.keyCount(); ++i) { + roles.insert(e.value(i), e.key(i)); + } + return roles; + } + + bool SearchResultModel::setData(const QModelIndex &index, const QVariant &value, int role) + { + if(!index.isValid() || index.row() >= m_items.length()) { + return false; + } + if(role == ShowToolTip) { + m_items.at(index.row())->setShowToolTip(value.toBool()); + return true; + } + return false; + } diff --git a/frontend/model/search-result-model.h b/frontend/model/search-result-model.h index c9e92cd..f5d9a3e 100644 --- a/frontend/model/search-result-model.h +++ b/frontend/model/search-result-model.h @@ -22,6 +22,7 @@ #define SEARCHRESULTMODEL_H #include #include "search-result-manager.h" +#include "one-result.h" #define NUM_LIMIT_SHOWN_DEFAULT 5 @@ -31,14 +32,16 @@ class SearchResultModel : public QAbstractItemModel { Q_OBJECT public: - SearchResultModel(const QString &plugin_id); - ~SearchResultModel(); + explicit SearchResultModel(const QString &plugin_id); + ~SearchResultModel() override; + QHash roleNames() const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; -// bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + const SearchPluginIface::ResultInfo & getInfo(const QModelIndex&); void setExpanded(const bool&); const bool &isExpanded(); @@ -56,7 +59,7 @@ Q_SIGNALS: private: void initConnections(); - QVector m_items; + QVector m_items; QString m_plugin_id; SearchResultManager * m_search_manager = nullptr; bool m_isExpanded = false; diff --git a/frontend/view/best-list-view.cpp b/frontend/view/best-list-view.cpp index 9991c56..97f3673 100644 --- a/frontend/view/best-list-view.cpp +++ b/frontend/view/best-list-view.cpp @@ -17,6 +17,7 @@ * * */ +#include #include "best-list-view.h" #define MAIN_MARGINS 0,0,0,0 #define MAIN_SPACING 0 @@ -247,6 +248,20 @@ bool BestListView::viewportEvent(QEvent *event) QApplication::sendEvent(parent(), &me); return true; } + if(event->type() == QEvent::ToolTip) { + auto* helpEvent = dynamic_cast(event); + QModelIndex index = indexAt(helpEvent->pos()); + if (!index.isValid()) { + return false; + } + + if (index.data(AdditionalRoles::ShowToolTip).toBool()) { + QToolTip::showText(helpEvent->globalPos(), index.data(Qt::ToolTipRole).toString(), this, visualRect(index)); + } else { + QToolTip::hideText(); + } + return true; + } return QTreeView::viewportEvent(event); } diff --git a/frontend/view/best-list-view.h b/frontend/view/best-list-view.h index 2acb63e..7e94829 100644 --- a/frontend/view/best-list-view.h +++ b/frontend/view/best-list-view.h @@ -55,10 +55,10 @@ public Q_SLOTS: const bool &isExpanded(); protected: - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent * event); - void mouseMoveEvent(QMouseEvent *event); - bool viewportEvent(QEvent *event); + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent * event) override; + void mouseMoveEvent(QMouseEvent *event) override; + bool viewportEvent(QEvent *event) override; private: void initConnections(); diff --git a/frontend/view/result-view-delegate.cpp b/frontend/view/result-view-delegate.cpp index fc55b02..dd4f7b5 100644 --- a/frontend/view/result-view-delegate.cpp +++ b/frontend/view/result-view-delegate.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include "search-result-model.h" using namespace UkuiSearch; static ResultItemStyle *global_instance_of_item_style = nullptr; @@ -44,7 +46,7 @@ void ResultViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op initStyleOption(&opt, index); opt.displayAlignment = Qt::Alignment(Qt::AlignLeft|Qt::AlignVCenter); - QString text = opt.text; + QString originalText = opt.text; opt.text = QString(); QStyle *style = opt.widget->style(); @@ -52,9 +54,22 @@ void ResultViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, opt.widget); QFontMetrics fontMetrics(opt.font); - text = fontMetrics.elidedText(text, Qt::ElideRight, textRect.width() - m_textDoc->documentMargin() - 1); //富余5px的宽度 + QString text = fontMetrics.elidedText(originalText, Qt::ElideRight, textRect.width() - m_textDoc->documentMargin() - 1); //富余5px的宽度 + + //无需显示tooltip时,将状态位写回model + auto view = qobject_cast(this->parent()); + if(text == originalText && originalText == index.data(Qt::ToolTipRole).toString()) { + if(view) { + view->model()->setData(index, false, AdditionalRoles::ShowToolTip); + } + } else { + if(view) { + view->model()->setData(index, true, AdditionalRoles::ShowToolTip); + } + } opt.text = text; + painter->save(); if(opt.state & QStyle::State_Selected) { diff --git a/frontend/view/result-view-delegate.h b/frontend/view/result-view-delegate.h index d11d324..9dec1f2 100644 --- a/frontend/view/result-view-delegate.h +++ b/frontend/view/result-view-delegate.h @@ -54,6 +54,7 @@ public: explicit ResultViewDelegate(QObject *parent = nullptr); ~ResultViewDelegate() = default; void setSearchKeyword(const QString &); + protected: void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; diff --git a/frontend/view/result-view.cpp b/frontend/view/result-view.cpp index d548f5b..ac66df9 100644 --- a/frontend/view/result-view.cpp +++ b/frontend/view/result-view.cpp @@ -17,6 +17,7 @@ * * */ +#include #include "result-view.h" #define MAIN_MARGINS 0,0,0,0 #define MAIN_SPACING 0 @@ -416,6 +417,20 @@ bool ResultView::viewportEvent(QEvent *event) QApplication::sendEvent(parent(), &me); return true; } + if(event->type() == QEvent::ToolTip) { + auto* helpEvent = dynamic_cast(event); + QModelIndex index = indexAt(helpEvent->pos()); + if (!index.isValid()) { + return false; + } + + if (index.data(AdditionalRoles::ShowToolTip).toBool()) { + QToolTip::showText(helpEvent->globalPos(), index.data(Qt::ToolTipRole).toString(), this, visualRect(index)); + } else { + QToolTip::hideText(); + } + return true; + } return QTreeView::viewportEvent(event); }