Complete some API & Optimize ui.

This commit is contained in:
zhangjiaping 2021-05-25 19:42:40 +08:00
parent f1af679133
commit 93692a3469
15 changed files with 357 additions and 55 deletions

View File

@ -56,6 +56,7 @@ void ShowMoreLabel::initUi() {
m_layout->setAlignment(Qt::AlignRight);
m_layout->addWidget(m_textLabel);
m_textLabel->setPalette(pal);
m_textLabel->setCursor(QCursor(Qt::PointingHandCursor));
// m_layout->addWidget(m_loadingIconLabel);
}
@ -64,9 +65,11 @@ bool ShowMoreLabel::eventFilter(QObject *watched, QEvent *event) {
if(event->type() == QEvent::MouseButtonPress) {
if(! m_timer->isActive()) {
if(!m_isOpen) {
m_textLabel->setText(tr("Retract"));
m_isOpen = true;
Q_EMIT this->showMoreClicked();
} else {
m_textLabel->setText(tr("Show More..."));
m_isOpen = false;
Q_EMIT this->retractClicked();
}

View File

@ -229,6 +229,12 @@ void ItemWidget::initUi(HomePageItemShape shape, const QString& name, const QIco
}
}
/**
* @brief ItemWidget::eventFilter
* @param watched
* @param event
* @return
*/
bool ItemWidget::eventFilter(QObject *watched, QEvent *event) {
if(watched == this) {
if(event->type() == QEvent::MouseButtonPress) {

View File

@ -66,6 +66,7 @@ void HomePage::appendSection(HomePageSection *section)
//以下为homepage各版块的信息获取的回调
//NEW_TODO
//获取快速打开应用的列表
QVector<HomePageItem> get_quickly_cb()
{
@ -114,18 +115,25 @@ QVector<HomePageItem> get_commonly_cb()
void HomePage::registerSections()
{
//快速打开
HomePageSection *quickly_section = new HomePageSection(tr("Open Quickly"), HomePageItemShape::Square, m_widget);
quickly_section->setItems(get_quickly_cb());
if (quickly_section->length())
this->appendSection(quickly_section);
createSection(tr("Open Quickly"), HomePageItemShape::Square, get_quickly_cb());
//最近打开
HomePageSection *recently_section = new HomePageSection(tr("Recently Opened"), HomePageItemShape::Bar, m_widget);
recently_section->setItems(get_recently_cb());
if (recently_section->length())
this->appendSection(recently_section);
createSection(tr("Recently Opened"), HomePageItemShape::Bar, get_recently_cb());
//常用应用
HomePageSection *commonly_section = new HomePageSection(tr("Commonly Used"), HomePageItemShape::Square, m_widget);
commonly_section->setItems(get_commonly_cb());
if (commonly_section->length())
this->appendSection(commonly_section);
createSection(tr("Commonly Used"), HomePageItemShape::Square, get_commonly_cb());
}
void HomePage::createSection(const QString &section_name, const HomePageItemShape &shape, QVector<HomePageItem> items)
{
HomePageSection *section = new HomePageSection(section_name, shape, m_widget);
section->setItems(items);
if (section->length())
this->appendSection(section);
connect(section, &HomePageSection::requestAction, this, [ = ](const QString &key, const QString &action, const QString &pluginId) {
SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(pluginId);
if (plugin) {
plugin->openAction(action, key);
} else {
qWarning()<<"Get plugin failed!";
}
});
}

View File

@ -24,6 +24,7 @@
#include <QScrollArea>
#include "home-page-section.h"
#include "file-utils.h"
#include "pluginmanage/search-plugin-manager.h"
namespace Zeeker {
class HomePage : public QScrollArea
@ -40,6 +41,7 @@ private:
QVBoxLayout * m_mainLyt = nullptr;
void registerSections();
void createSection(const QString &, const HomePageItemShape &, QVector<HomePageItem>);
Q_SIGNALS:
};

View File

@ -33,6 +33,9 @@ using namespace Zeeker;
#define NAME_LABEL_WIDTH 280
#define ICON_SIZE QSize(96, 96)
#define LINE_STYLE "QFrame{background: rgba(0,0,0,0.2);}"
#define ACTION_NORMAL_COLOR QColor(55, 144, 250, 255)
#define ACTION_HOVER_COLOR QColor(64, 169, 251, 255)
#define ACTION_PRESS_COLOR QColor(41, 108, 217, 255)
ResultArea::ResultArea(QWidget *parent) : QScrollArea(parent)
{
@ -110,6 +113,7 @@ void DetailArea::initUi()
DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent)
{
initUi();
clear();
}
QString escapeHtml(const QString & str) {
@ -131,21 +135,22 @@ void DetailWidget::setWidgetInfo(const QString &plugin_name, const SearchPluginI
m_nameFrame->show();
m_line_1->show();
if (info.description.length() > 0) {
//NEW_TODO
//NEW_TODO 样式待优化
clearLayout(m_descFrameLyt);
Q_FOREACH (SearchPluginIface::DescriptionInfo desc, info.description) {
QLabel * descLabel = new QLabel(m_descFrame);
descLabel->setTextFormat(Qt::PlainText);
descLabel->setWordWrap(true);
QString show_desc = desc.key + ": " + desc.value;
descLabel->setText(show_desc);
m_descFrameLyt->addWidget(descLabel);
}
m_descFrame->show();
m_line_2->show();
}
clearLayout(m_actionFrameLyt);
Q_FOREACH (auto action, info.actionMap) {
//NEW_TODO
QLabel * actionLabel = new QLabel(m_actionFrame);
actionLabel->setText(action);
Q_FOREACH (auto action, info.actionList) {
ActionLabel * actionLabel = new ActionLabel(action, info.key, plugin_name, m_actionFrame);
m_actionFrameLyt->addWidget(actionLabel);
}
m_actionFrame->show();
@ -179,6 +184,7 @@ void DetailWidget::initUi()
m_nameLabel = new QLabel(m_nameFrame);
m_nameLabel->setMaximumWidth(NAME_LABEL_WIDTH);
m_pluginLabel = new QLabel(m_nameFrame);
m_pluginLabel->setEnabled(false);
m_nameFrameLyt->addWidget(m_nameLabel);
m_nameFrameLyt->addStretch();
m_nameFrameLyt->addWidget(m_pluginLabel);
@ -239,3 +245,48 @@ void DetailWidget::clearLayout(QLayout *layout)
}
child = NULL;
}
ActionLabel::ActionLabel(const QString &action, const QString &key, const QString &plugin, QWidget *parent) : QLabel(parent)
{
m_action = action;
m_key = key;
m_plugin = plugin;
this->initUi();
this->installEventFilter(this);
}
void ActionLabel::initUi()
{
this->setText(m_action);
QPalette pal = palette();
pal.setColor(QPalette::WindowText, ACTION_NORMAL_COLOR);
pal.setColor(QPalette::Light, ACTION_HOVER_COLOR);
pal.setColor(QPalette::Dark, ACTION_PRESS_COLOR);
this->setPalette(pal);
this->setForegroundRole(QPalette::WindowText);
this->setCursor(QCursor(Qt::PointingHandCursor));
}
bool ActionLabel::eventFilter(QObject *watched, QEvent *event)
{
if (watched == this) {
if(event->type() == QEvent::MouseButtonPress) {
this->setForegroundRole(QPalette::Dark);
return true;
} else if(event->type() == QEvent::MouseButtonRelease) {
SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_plugin);
if (plugin)
plugin->openAction(m_action, m_key);
else
qWarning()<<"Get plugin failed!";
this->setForegroundRole(QPalette::Light);
return true;
} else if(event->type() == QEvent::Enter) {
this->setForegroundRole(QPalette::Light);
return true;
} else if(event->type() == QEvent::Leave) {
this->setForegroundRole(QPalette::WindowText);
return true;
}
}
}

View File

@ -91,6 +91,23 @@ private:
Q_SIGNALS:
void setWidgetInfo(const QString&, const SearchPluginIface::ResultInfo&);
};
class ActionLabel : public QLabel
{
Q_OBJECT
public:
ActionLabel(const QString &action, const QString &key, const QString &plugin, QWidget *parent = nullptr);
~ActionLabel() = default;
private:
void initUi();
QString m_action;
QString m_key;
QString m_plugin;
protected:
bool eventFilter(QObject *, QEvent *);
};
}
#endif // SEARCHPAGESECTION_H

View File

@ -32,7 +32,11 @@ SearchResultManager::SearchResultManager(const QString& plugin_id, QObject *pare
void SearchResultManager::startSearch(const QString &keyword)
{
//NEW_TODO 加锁?停止线程?重新搜索?
stopSearch();
// stopSearch();
qDebug()<<m_plugin_id<<"------------------>start by others";
if(! m_get_result_thread->isRunning()) {
m_get_result_thread->start();
}
m_result_queue->clear();
SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_plugin_id);
// plugin->KeywordSearch(keyword, m_result_queue);
@ -46,34 +50,31 @@ void SearchResultManager::startSearch(const QString &keyword)
desc_1.key = "描述";
desc_1.value = "控制面板搜索插件";
desc.append(desc_1);
QMap<QString,QString> actions;
actions.insert("ukcc-search","打开");
QStringList actions;
actions.append("打开");
test_info.description = desc;
test_info.actionMap = actions;
test_info.actionList = actions;
m_result_queue->append(test_info);
} else {
test_info.icon = QIcon::fromTheme("ukui-control-center");
test_info.name = "文件";
test_info.icon = QIcon::fromTheme("unknown");
test_info.name = "文件12345abcde.txt";
QVector<SearchPluginIface::DescriptionInfo> desc;
SearchPluginIface::DescriptionInfo desc_1;
SearchPluginIface::DescriptionInfo desc_2;
desc_1.key = "描述";
desc_1.value = "一个文件";
desc_2.key = "路径";
desc_2.value = "一个路径";
desc_2.value = "一个路径/a/b/c/d/e/fffffff/文件12345abcde.txt";
desc.append(desc_1);
desc.append(desc_2);
QMap<QString,QString> actions;
actions.insert("file1","打开");
actions.insert("file2","复制路径");
QStringList actions;
actions.append("打开");
actions.append("复制路径");
test_info.description = desc;
test_info.actionMap = actions;
test_info.actionList = actions;
m_result_queue->append(test_info);
}
/********************测试用数据********************/
qWarning()<<m_plugin_id<<"------------------>start by others";
m_get_result_thread->start();
}
/**
@ -82,9 +83,9 @@ void SearchResultManager::startSearch(const QString &keyword)
void SearchResultManager::stopSearch()
{
if(m_get_result_thread->isRunning()) {
qWarning()<<m_plugin_id<<"-------------->stopped by others";
m_get_result_thread->requestInterruption();
m_get_result_thread->quit();
qDebug()<<m_plugin_id<<"-------------->stopped by others";
m_get_result_thread->stop();
// m_get_result_thread->quit();
}
}
@ -98,6 +99,12 @@ ReceiveResultThread::ReceiveResultThread(QQueue<SearchPluginIface::ResultInfo> *
m_result_queue = result_queue;
}
void ReceiveResultThread::stop()
{
this->requestInterruption();
this->quit();
}
//NEW_TODO 还未对队列加锁
void ReceiveResultThread::run()
{

View File

@ -34,13 +34,13 @@ class ReceiveResultThread : public QThread {
public:
ReceiveResultThread(QQueue<SearchPluginIface::ResultInfo> * result_queue, QObject * parent = nullptr);
~ReceiveResultThread() = default;
void stop();
protected:
void run() override;
private:
QQueue<SearchPluginIface::ResultInfo> * m_result_queue;
Q_SIGNALS:
void gotResultInfo(const SearchPluginIface::ResultInfo&);

View File

@ -79,14 +79,23 @@ QVariant SearchResultModel::data(const QModelIndex &index, int role) const
void SearchResultModel::appendInfo(const SearchPluginIface::ResultInfo &info)
{
this->beginResetModel();
qWarning()<<"Got a result. name ="<<info.name;
qDebug()<<"Got a result. name ="<<info.name;
m_item->m_result_info_list.append(info);
this->endResetModel();
}
void SearchResultModel::startSearch(const QString &keyword)
{
if (!m_item->m_result_info_list.isEmpty()) {
this->beginResetModel();
m_item->m_result_info_list.clear();
this->endResetModel();
}
m_search_manager->startSearch(keyword);
}
void SearchResultModel::initConnections()
{
connect(this, &SearchResultModel::startSearch, m_search_manager, &SearchResultManager::startSearch);
connect(this, &SearchResultModel::stopSearch, m_search_manager, &SearchResultManager::stopSearch);
connect(m_search_manager, &SearchResultManager::gotResultInfo, this, &SearchResultModel::appendInfo);
}

View File

@ -51,9 +51,9 @@ public:
public Q_SLOTS:
void appendInfo(const SearchPluginIface::ResultInfo &);
void startSearch(const QString &);
Q_SIGNALS:
void startSearch(const QString &);
void stopSearch();
private:

View File

@ -0,0 +1,81 @@
#include "result-view-delegate.h"
using namespace Zeeker;
ResultViewDelegate::ResultViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
{
}
void ResultViewDelegate::setSearchKeyword(const QString &regFindKeyWords)
{
m_regFindKeyWords.clear();
m_regFindKeyWords = regFindKeyWords;
}
void ResultViewDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const {
QStyleOptionViewItemV4 optionV4 = option;
initStyleOption(&optionV4, index);
QStyle *style = optionV4.widget ? optionV4.widget->style() : QApplication::style();
optionV4.text = QString();
style->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter); //绘制非文本区域内容
if(index.model()->data(index, Qt::DisplayRole).toString().isEmpty()) return;
QTextDocument doc;
doc.setHtml(getHtmlText(painter, option, index)); //提取富文本
QAbstractTextDocumentLayout::PaintContext ctx;
if(optionV4.state & QStyle::State_Selected)
ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText));
QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &optionV4);
textRect.adjust(0, -5, 0, 0);
painter->save();
painter->translate(textRect.topLeft());
painter->setClipRect(textRect.translated(-textRect.topLeft()));
doc.documentLayout()->draw(painter, ctx); //绘制文本区域内容
painter->restore();
}
QString ResultViewDelegate::getHtmlText(QPainter *painter, const QStyleOptionViewItem &itemOption, const QModelIndex &index) const
{
int indexFindLeft = 0;
QString indexString = index.model()->data(index, Qt::DisplayRole).toString();
QFont ft(painter->font().family(), GlobalSettings::getInstance()->getValue(FONT_SIZE_KEY).toInt());
QFontMetrics fm(ft);
QString indexColString = fm.elidedText(indexString, Qt::ElideRight, itemOption.rect.width() - 30); //当字体超过Item的长度时显示为省略号
QString htmlString;
if((indexColString.toUpper()).contains((m_regFindKeyWords.toUpper()))) {
indexFindLeft = indexColString.toUpper().indexOf(m_regFindKeyWords.toUpper()); //得到查找字体在当前整个Item字体中的位置
htmlString = escapeHtml(indexColString.left(indexFindLeft)) + "<b>" + escapeHtml(indexColString.mid(indexFindLeft, m_regFindKeyWords.length())) + "</b>" + escapeHtml(indexColString.right(indexColString.length() - indexFindLeft - m_regFindKeyWords.length()));
} else {
bool boldOpenned = false;
for(int i = 0; i < indexColString.length(); i++) {
if((m_regFindKeyWords.toUpper()).contains(QString(indexColString.at(i)).toUpper())) {
if(! boldOpenned) {
boldOpenned = true;
htmlString.append(QString("<b>"));
}
htmlString.append(escapeHtml(QString(indexColString.at(i))));
} else {
if(boldOpenned) {
boldOpenned = false;
htmlString.append(QString("</b>"));
}
htmlString.append(escapeHtml(QString(indexColString.at(i))));
}
}
}
// qDebug()<<indexColString<<"---->"<<htmlString;
return htmlString;
}
QString ResultViewDelegate::escapeHtml(const QString &str) const
{
QString temp = str;
temp.replace("<", "&lt;");
temp.replace(">", "&gt;");
return temp;
}

View File

@ -0,0 +1,46 @@
/*
*
* Copyright (C) 2020, 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: zhangjiaping <zhangjiaping@kylinos.cn>
*
*/
#ifndef RESULTVIEWDELEGATE_H
#define RESULTVIEWDELEGATE_H
#include <QStyledItemDelegate>
#include <QPainter>
#include <QStyle>
#include <QTextDocument>
#include <QAbstractTextDocumentLayout>
#include "global-settings.h"
namespace Zeeker {
class ResultViewDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
explicit ResultViewDelegate(QObject *parent = nullptr);
~ResultViewDelegate() = default;
void setSearchKeyword(const QString &);
private:
QString m_regFindKeyWords = 0;
void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override;
QString getHtmlText(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const;
QString escapeHtml(const QString&) const;
};
}
#endif // RESULTVIEWDELEGATE_H

View File

@ -22,6 +22,24 @@ void ResultWidget::setEnabled(const bool &enabled)
m_enabled = enabled;
}
/**
* @brief ResultWidget::expandListSlot
*/
void ResultWidget::expandListSlot()
{
//NEW_TODO
qWarning()<<"List will be expanded!";
}
/**
* @brief ResultWidget::reduceListSlot
*/
void ResultWidget::reduceListSlot()
{
//NEW_TODO
qWarning()<<"List will be reduced!";
}
void ResultWidget::initUi()
{
m_mainLyt = new QVBoxLayout(this);
@ -35,9 +53,10 @@ void ResultWidget::initUi()
m_resultView = new ResultView(m_plugin_id, this);
//NEW_TODO
//NEW_TODO 当列表条目大于n时显示
m_showMoreLabel = new ShowMoreLabel(this);
m_showMoreLabel->setFixedHeight(UNFOLD_LABEL_HEIGHT);
// m_showMoreLabel->hide();
m_mainLyt->addWidget(m_titleLabel);
m_mainLyt->addWidget(m_resultView);
@ -48,9 +67,17 @@ void ResultWidget::initUi()
void ResultWidget::initConnections()
{
connect(this, &ResultWidget::startSearch, m_resultView, &ResultView::startSearch);
connect(this, &ResultWidget::startSearch, this, [ = ]() {
m_showMoreLabel->resetLabel();
});
connect(this, &ResultWidget::stopSearch, m_resultView, &ResultView::stopSearch);
connect(this, &ResultWidget::stopSearch, this, [ = ]() {
m_showMoreLabel->resetLabel();
});
connect(m_resultView, &ResultView::currentRowChanged, this, &ResultWidget::currentRowChanged);
connect(this, &ResultWidget::clearSelectedRow, m_resultView, &ResultView::clearSelectedRow);
connect(m_showMoreLabel, &ShowMoreLabel::showMoreClicked, this, &ResultWidget::expandListSlot);
connect(m_showMoreLabel, &ShowMoreLabel::retractClicked, this, &ResultWidget::reduceListSlot);
}
ResultView::ResultView(const QString &plugin_id, QWidget *parent) : QTreeView(parent)
@ -66,6 +93,8 @@ ResultView::ResultView(const QString &plugin_id, QWidget *parent) : QTreeView(pa
this->setModel(m_model);
initConnections();
m_plugin_id = plugin_id;
m_style_delegate = new ResultViewDelegate(this);
this->setItemDelegate(m_style_delegate);
}
bool ResultView::isSelected()
@ -82,23 +111,55 @@ void ResultView::clearSelectedRow()
}
}
/**
* @brief ResultView::onRowDoubleClickedSlot
* @param index
*/
void ResultView::onRowDoubleClickedSlot(const QModelIndex &index)
{
const SearchPluginIface::ResultInfo &info = m_model->getInfo(index);
SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_plugin_id);
try {
if (plugin) {
if (!info.actionList.isEmpty()) {
plugin->openAction(info.actionList.at(0), info.key);
} else {
throw -2;
}
} else {
throw -1;
}
} catch(int e) {
qWarning()<<"Open failed, reason="<<e;
}
}
/**
* @brief ResultView::onRowSelectedSlot
* @param selected
* @param deselected
*/
void ResultView::onRowSelectedSlot(const QItemSelection &selected, const QItemSelection &deselected)
{
//NEW_TODO
m_is_selected = true;
Q_EMIT this->currentRowChanged(m_plugin_id, m_model->getInfo(this->currentIndex()));
m_is_selected = false;
if(!selected.isEmpty()) {
QRegion region = visualRegionForSelection(selected);
QRect rect = region.boundingRect();
// Q_EMIT this->currentSelectPos(mapToParent(rect.topLeft()));
}
}
void ResultView::initConnections()
{
connect(this, &ResultView::startSearch, m_model, &SearchResultModel::startSearch);
// connect(this, &ResultView::startSearch, m_model, &SearchResultModel::startSearch);
connect(this, &ResultView::startSearch, [ = ](const QString &keyword) {
m_style_delegate->setSearchKeyword(keyword);
m_model->startSearch(keyword);
});
connect(this, &ResultView::stopSearch, m_model, &SearchResultModel::stopSearch);
connect(this->selectionModel(), &QItemSelectionModel::selectionChanged, this, [ = ](const QItemSelection & selected, const QItemSelection & deselected) {
//NEW_TODO 处理选中事件
m_is_selected = true;
Q_EMIT this->currentRowChanged(m_plugin_id, m_model->getInfo(this->currentIndex()));
m_is_selected = false;
if(!selected.isEmpty()) {
QRegion region = visualRegionForSelection(selected);
QRect rect = region.boundingRect();
// Q_EMIT this->currentSelectPos(mapToParent(rect.topLeft()));
}
});
connect(this, &ResultView::activated, this, [ = ](const QModelIndex & index) {
//NEW_TODO 处理双击打开事件
});
connect(this->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ResultView::onRowSelectedSlot);
connect(this, &ResultView::activated, this, &ResultView::onRowDoubleClickedSlot);
}

View File

@ -6,6 +6,7 @@
#include "search-result-model.h"
#include "show-more-label.h"
#include "title-label.h"
#include "result-view-delegate.h"
namespace Zeeker {
@ -19,12 +20,15 @@ public:
public Q_SLOTS:
void clearSelectedRow();
void onRowDoubleClickedSlot(const QModelIndex &);
void onRowSelectedSlot(const QItemSelection &, const QItemSelection &);
private:
void initConnections();
SearchResultModel * m_model = nullptr;
QString m_plugin_id;
bool m_is_selected = false;
ResultViewDelegate * m_style_delegate = nullptr;
Q_SIGNALS:
void startSearch(const QString &);
@ -41,6 +45,11 @@ public:
~ResultWidget() = default;
QString pluginId();
void setEnabled(const bool&);
public Q_SLOTS:
void expandListSlot();
void reduceListSlot();
private:
QString m_plugin_id;
bool m_enabled = true;

View File

@ -1,7 +1,9 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/result-view-delegate.h \
$$PWD/result-view.h \
SOURCES += \
$$PWD/result-view-delegate.cpp \
$$PWD/result-view.cpp \