fix(frontend):结果列表中未被截断的项不再显示tooltip

This commit is contained in:
iaom 2024-03-04 17:55:42 +08:00
parent 1f39efe2b6
commit ebcf3bd305
12 changed files with 240 additions and 92 deletions

View File

@ -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

View File

@ -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:"<<pluginId<<"Repalce result. name ="<<info.name;
this->beginResetModel();
m_items.replace(m_plugin_id_list.lastIndexOf(pluginId), info);
delete m_items.takeAt(m_pluginIdList.lastIndexOf(pluginId));
m_items.insert(m_pluginIdList.lastIndexOf(pluginId), new OneResult(info));
this->endResetModel();
return;
}
this->beginResetModel();
// qDebug()<<"plugin ID:"<<pluginId<<"Got a result. name ="<<info.name;
m_plugin_id_list.append(pluginId);
m_items.append(info);
QVector<SearchPluginIface::ResultInfo> result_info_list_tmp;
m_pluginIdList.append(pluginId);
m_items.append(new OneResult(info));
QVector<OneResult *> result_info_list_tmp;
QVector<QString> plugin_id_list_tmp;
QList<PluginInfo> infoList = SearchPluginManager::getInstance()->getPluginIds();
QVector<QString> orders(infoList.length());
for (const PluginInfo& info : infoList) {
@ -148,15 +128,15 @@ void BestListModel::appendInfo(const QString &pluginId, const SearchPluginIface:
orders.removeAll("");
Q_FOREACH (const QString& plugin, orders) {
if (m_plugin_id_list.contains(plugin)) {
result_info_list_tmp.append(m_items.at(m_plugin_id_list.lastIndexOf(plugin)));
if (m_pluginIdList.contains(plugin)) {
result_info_list_tmp.append(m_items.at(m_pluginIdList.lastIndexOf(plugin)));
plugin_id_list_tmp.append(plugin);
}
}
m_items.clear();
m_items.swap(result_info_list_tmp);
m_plugin_id_list.clear();
m_plugin_id_list.swap(plugin_id_list_tmp);
m_pluginIdList.clear();
m_pluginIdList.swap(plugin_id_list_tmp);
this->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;
}

View File

@ -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<SearchPluginIface::ResultInfo> m_items;
QVector<QString> m_plugin_id_list;
QVector<QString> m_plugin_action_key_list;
QVector<OneResult *> m_items;
QVector<QString> m_pluginIdList;
QVector<QString> m_pluginActionKeyList;
bool m_isExpanded = false;
};
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* Authors: iaom <zhangpengfei@kylinos.cn>
*/
#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;
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* Authors: iaom <zhangpengfei@kylinos.cn>
*/
#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

View File

@ -1,4 +1,4 @@
/*
/*
*
* Copyright (C) 2020, KylinSoft Co., Ltd.
*
@ -18,6 +18,7 @@
* Authors: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#include <QMetaEnum>
#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<int, QByteArray> SearchResultModel::roleNames() const
{
QHash<int, QByteArray> 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;
}

View File

@ -22,6 +22,7 @@
#define SEARCHRESULTMODEL_H
#include <QAbstractItemModel>
#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<int, QByteArray> 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<SearchPluginIface::ResultInfo> m_items;
QVector<OneResult*> m_items;
QString m_plugin_id;
SearchResultManager * m_search_manager = nullptr;
bool m_isExpanded = false;

View File

@ -17,6 +17,7 @@
*
*
*/
#include <QToolTip>
#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<QHelpEvent*>(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);
}

View File

@ -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();

View File

@ -22,6 +22,8 @@
#include <QApplication>
#include <QPen>
#include <QStyleFactory>
#include <QTreeView>
#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<QTreeView *>(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) {

View File

@ -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;

View File

@ -17,6 +17,7 @@
*
*
*/
#include <QToolTip>
#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<QHelpEvent*>(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);
}