From 2bedd95d9be68c2ce0849b358cc8b4c72b69b2b2 Mon Sep 17 00:00:00 2001 From: chenhongtao Date: Thu, 24 Aug 2023 15:04:41 +0800 Subject: [PATCH] chore: move elideText logic to itemdata Log: --- CMakeLists.txt | 2 +- dde-clipboard/itemdata.cpp | 98 +++++++++++++++++++++ dde-clipboard/itemdata.h | 20 ++++- dde-clipboard/itemdelegate.cpp | 44 ++-------- dde-clipboard/itemwidget.cpp | 11 ++- dde-clipboard/itemwidget.h | 2 +- dde-clipboard/pixmaplabel.cpp | 115 ++----------------------- dde-clipboard/pixmaplabel.h | 24 ++---- tests/dde-clipboard/ut_itemwidget.cpp | 2 +- tests/dde-clipboard/ut_pixmaplabel.cpp | 78 ----------------- 10 files changed, 147 insertions(+), 249 deletions(-) delete mode 100644 tests/dde-clipboard/ut_pixmaplabel.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f0005b3..88134c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(BIN_NAME dde-clipboard) project(${BIN_NAME}) #set(CMAKE_VERBOSE_MAKEFILE ON) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) diff --git a/dde-clipboard/itemdata.cpp b/dde-clipboard/itemdata.cpp index e9c2976..b7ffbd8 100644 --- a/dde-clipboard/itemdata.cpp +++ b/dde-clipboard/itemdata.cpp @@ -3,12 +3,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "itemdata.h" +#include "constants.h" #include #include #include #include +#include + #include static inline QString textUriListLiteral() { return QStringLiteral("text/uri-list"); } @@ -95,6 +98,7 @@ ItemData::ItemData(const QByteArray &buf) m_enable = true; m_iconDataList = info.m_iconDataList; m_formatMap = info.m_formatMap; + m_text_list = elideText(m_text, QSizeF(ItemWidth - ContentMargin * 2, ItemHeight - ItemTitleHeight), QTextOption::WrapAnywhere, QApplication::font(), Qt::ElideMiddle, 0); } QString ItemData::title() @@ -179,6 +183,24 @@ const QList &ItemData::IconDataList() return m_iconDataList; } +QSize ItemData::sizeHint(int fontHeight) +{ + if (m_type == Text) { + return QSize(ItemWidth, itemHeight(fontHeight) + ItemMargin); + } + + return QSize(ItemWidth, ItemHeight + ItemMargin); +} + +int ItemData::itemHeight(int fontHeight) +{ + if (m_type == Text) { + auto length = m_text_list.length() > 4 ? 4 : m_text_list.length(); + return length * fontHeight + ItemTitleHeight + ItemStatusBarHeight + TextContentTopMargin; + } + return ItemHeight; +} + /*! * \~chinese \name remove * \~chinese \brief 将当前剪切块数据移除,调用此函数会发出ItemData::destroy的信号 @@ -201,3 +223,79 @@ const QSize &ItemData::pixSize() const { return m_pixSize; } + +QStringList ItemData::elideText(const QString &text, const QSizeF &size, + QTextOption::WrapMode wordWrap, const QFont &font, + Qt::TextElideMode mode, qreal lineHeight, int flags) +{ + QTextLayout textLayout(text); + + textLayout.setFont(font); + + QStringList lines; + + elideText(&textLayout, size, wordWrap, mode, lineHeight, flags, &lines); + + return lines; +} + +void ItemData::elideText(QTextLayout *layout, const QSizeF &size, QTextOption::WrapMode wordWrap, + Qt::TextElideMode mode, qreal lineHeight, int flags, QStringList *lines) +{ + qreal height = 0; + QPointF offset(0, 0); + + QString text = layout->engine()->hasFormats() ? layout->engine()->block.text() : layout->text(); + QTextOption &text_option = *const_cast(&layout->textOption()); + + text_option.setWrapMode(wordWrap); + + if (flags & Qt::AlignRight) + text_option.setAlignment(Qt::AlignRight); + else if (flags & Qt::AlignHCenter) + text_option.setAlignment(Qt::AlignHCenter); + + // dont paint + layout->engine()->ignoreBidi = true; + layout->beginLayout(); + + QTextLine line = layout->createLine(); + + while (line.isValid()) { + height += lineHeight; + + if (height + lineHeight > size.height()) { + const QString &end_str = layout->engine()->elidedText(mode, qRound(size.width()), flags, line.textStart()); + + layout->endLayout(); + layout->setText(end_str); + + if (layout->engine()->block.docHandle()) { + const_cast(layout->engine()->block.document())->setPlainText(end_str); + } + + text_option.setWrapMode(QTextOption::NoWrap); + layout->beginLayout(); + line = layout->createLine(); + line.setLineWidth(size.width() - 1); + text = end_str; + } else { + line.setLineWidth(size.width()); + } + + line.setPosition(offset); + offset.setY(offset.y() + lineHeight); + + if (lines) { + lines->append(text.mid(line.textStart(), line.textLength())); + } + + if (height + lineHeight > size.height()) + break; + + line = layout->createLine(); + } + + layout->endLayout(); +} + diff --git a/dde-clipboard/itemdata.h b/dde-clipboard/itemdata.h index dfe6ef3..19a1fe0 100644 --- a/dde-clipboard/itemdata.h +++ b/dde-clipboard/itemdata.h @@ -12,7 +12,7 @@ #include #include #include - +#include #include "constants.h" #include "dbus/iteminfo.h" @@ -34,7 +34,12 @@ class ItemData : public QObject const QList &urls(); // 文件链接 const QDateTime &time(); // 复制时间 const QString &text(); // 内容预览 + QStringList get_text() const { + return m_text_list; + }; + QSize sizeHint(int height); + int itemHeight(int fontHeight); inline bool dataEnabled() { return m_enable; } void setDataEnabled(bool enable) { m_enable = enable; } @@ -67,6 +72,18 @@ class ItemData : public QObject */ void reborn(ItemData *data); +private: + QStringList elideText(const QString &text, const QSizeF &size, + QTextOption::WrapMode wordWrap, + const QFont &font, + Qt::TextElideMode mode, + qreal lineHeight, + int flags = 0); + + void elideText(QTextLayout *layout, const QSizeF &size, + QTextOption::WrapMode wordWrap, + Qt::TextElideMode mode, qreal lineHeight, + int flags = 0, QStringList *lines = 0); private: QMap m_formatMap; DataType m_type = Unknown; @@ -74,6 +91,7 @@ class ItemData : public QObject QVariant m_variantImage; QSize m_pixSize; QString m_text; + QStringList m_text_list; bool m_enable; QDateTime m_createTime; QList m_iconDataList; diff --git a/dde-clipboard/itemdelegate.cpp b/dde-clipboard/itemdelegate.cpp index 6e81458..996bee4 100644 --- a/dde-clipboard/itemdelegate.cpp +++ b/dde-clipboard/itemdelegate.cpp @@ -3,9 +3,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "itemdelegate.h" -#include "clipboardmodel.h" -#include "itemdata.h" -#include "iteminfo.h" #include "itemwidget.h" #include @@ -16,24 +13,6 @@ DWIDGET_USE_NAMESPACE -static int caculateTextHeight(int width, int height) -{ - static const int textCenterWidth = ItemWidth - ContentMargin * 2; - int extraline = 0; - int over = width % textCenterWidth; - if (over != 0) { - extraline = 1; - } - auto caculated = width / textCenterWidth + extraline; - int toShow = caculated > 4 ? 4 : caculated; - return toShow * height; -} - -static int getItemHeight(int width, int height) -{ - return ItemTitleHeight + ItemStatusBarHeight + TextContentTopMargin + caculateTextHeight(width, height); -} - ItemDelegate::ItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { @@ -59,17 +38,10 @@ QWidget *ItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem QSize ItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { - Q_UNUSED(option); - Q_UNUSED(index); - QPointer data = index.data().value>(); - if (data->type() == DataType::Text) { - QString text = data->text().simplified(); - int height = option.fontMetrics.height(); - int width = option.fontMetrics.horizontalAdvance(text); - return QSize(ItemWidth, ItemMargin + getItemHeight(width, height)); - } - return QSize(ItemWidth, ItemHeight + ItemMargin); + int height = option.fontMetrics.height(); + + return data->sizeHint(height); } void ItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const @@ -77,14 +49,8 @@ void ItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewI Q_UNUSED(index); QRect rect = option.rect; QPointer data = index.data().value>(); - if (data->type() == DataType::Text) { - QString text = data->text().simplified(); - int height = option.fontMetrics.height(); - int width = option.fontMetrics.horizontalAdvance(text); - editor->setGeometry(rect.x() + ItemMargin, rect.y(), ItemWidth, getItemHeight(width, height)); - return; - } - editor->setGeometry(rect.x() + ItemMargin, rect.y(), ItemWidth, ItemHeight); + int height = option.fontMetrics.height(); + editor->setGeometry(rect.x() + ItemMargin, rect.y(), ItemWidth, data->itemHeight(height)); } bool ItemDelegate::eventFilter(QObject *obj, QEvent *event) diff --git a/dde-clipboard/itemwidget.cpp b/dde-clipboard/itemwidget.cpp index a081647..0b421d7 100644 --- a/dde-clipboard/itemwidget.cpp +++ b/dde-clipboard/itemwidget.cpp @@ -50,7 +50,7 @@ ItemWidget::ItemWidget(QPointer data, QWidget *parent) , m_nameLabel(new DLabel(this)) , m_timeLabel(new DLabel(this)) , m_closeButton(new IconButton(this)) - , m_contentLabel(new PixmapLabel(this)) + , m_contentLabel(new PixmapLabel(data,this)) , m_statusLabel(new DLabel(this)) , m_refreshTimer(new QTimer(this)) { @@ -68,12 +68,15 @@ const QString &ItemWidget::text() return m_data->text(); } -void ItemWidget::setText(const QString &text, const QString &length) +void ItemWidget::setTextShown(const QString &length) { QFont font = m_contentLabel->font(); + font.setItalic(true); + m_contentLabel->setFont(font); - m_contentLabel->setText(text); + + m_contentLabel->setText(true); m_statusLabel->setText(length); } @@ -290,7 +293,7 @@ void ItemWidget::initData(QPointer data) setCreateTime(data->time()); switch (data->type()) { case Text: { - setText(data->text(), data->subTitle()); + setTextShown(data->subTitle()); } break; case Image: { diff --git a/dde-clipboard/itemwidget.h b/dde-clipboard/itemwidget.h index a4ca516..2e29f3a 100644 --- a/dde-clipboard/itemwidget.h +++ b/dde-clipboard/itemwidget.h @@ -33,7 +33,7 @@ class ItemWidget : public DWidget * \~chinese \brief 设置剪切块属性的接口 */ const QString& text(); - void setText(const QString &text, const QString &length); + void setTextShown(const QString &length); void setThumnail(const QPixmap &pixmap/*未经处理的原图*/); void setThumnail(const FileIconData &data); diff --git a/dde-clipboard/pixmaplabel.cpp b/dde-clipboard/pixmaplabel.cpp index c04582b..f2b4e2f 100644 --- a/dde-clipboard/pixmaplabel.cpp +++ b/dde-clipboard/pixmaplabel.cpp @@ -14,31 +14,19 @@ #include #include -#include - -PixmapLabel::PixmapLabel(const QList &list, QWidget *parent) - : DLabel(parent) - , m_pixmapList(list) -{ - -} - -PixmapLabel::PixmapLabel(QWidget *parent) +PixmapLabel::PixmapLabel(QPointer data,QWidget *parent) : DLabel(parent) + , m_data(data) + , m_istext(false) { } /*! - * \~chinese \name setText - * \~chinese \brief 设置剪切板中的文字 - * \~chinese \param text 剪切板中需要显示的文字 */ -void PixmapLabel::setText(const QString &text) +void PixmapLabel::setText(bool is_text) { - m_text = text.left(1024);//减少elideText计算消耗 - - update(); + m_istext = is_text; // it label is text } /*! @@ -49,8 +37,6 @@ void PixmapLabel::setText(const QString &text) void PixmapLabel::setPixmapList(const QList &list) { m_pixmapList = list; - - update(); } /*! @@ -71,65 +57,6 @@ QSize PixmapLabel::sizeHint() const return QSize(ItemWidth - ContentMargin * 2, ItemHeight - ItemTitleHeight); } -void PixmapLabel::elideText(QTextLayout *layout, const QSizeF &size, QTextOption::WrapMode wordWrap, - Qt::TextElideMode mode, qreal lineHeight, int flags, QStringList *lines) -{ - qreal height = 0; - QPointF offset(0, 0); - - QString text = layout->engine()->hasFormats() ? layout->engine()->block.text() : layout->text(); - QTextOption &text_option = *const_cast(&layout->textOption()); - - text_option.setWrapMode(wordWrap); - - if (flags & Qt::AlignRight) - text_option.setAlignment(Qt::AlignRight); - else if (flags & Qt::AlignHCenter) - text_option.setAlignment(Qt::AlignHCenter); - - // dont paint - layout->engine()->ignoreBidi = true; - layout->beginLayout(); - - QTextLine line = layout->createLine(); - - while (line.isValid()) { - height += lineHeight; - - if (height + lineHeight > size.height()) { - const QString &end_str = layout->engine()->elidedText(mode, qRound(size.width()), flags, line.textStart()); - - layout->endLayout(); - layout->setText(end_str); - - if (layout->engine()->block.docHandle()) { - const_cast(layout->engine()->block.document())->setPlainText(end_str); - } - - text_option.setWrapMode(QTextOption::NoWrap); - layout->beginLayout(); - line = layout->createLine(); - line.setLineWidth(size.width() - 1); - text = end_str; - } else { - line.setLineWidth(size.width()); - } - - line.setPosition(offset); - offset.setY(offset.y() + lineHeight); - - if (lines) { - lines->append(text.mid(line.textStart(), line.textLength())); - } - - if (height + lineHeight > size.height()) - break; - - line = layout->createLine(); - } - - layout->endLayout(); -} QPair PixmapLabel::getNextValidString(const QStringList &list, int from) { @@ -145,33 +72,6 @@ QPair PixmapLabel::getNextValidString(const QStringList &list, int return QPair("", list.size() - 1); } -/*! - * \~chinese \name elideText - * \~chinese \brief 将文本转换为一定的格式返回 - * \~chinese \param text 文本信息 - * \~chinese \param size 显示文字窗口的大小 - * \~chinese \param wordWrap 控制换行符出现的位置 - * \~chinese \param mode 控制省略文本中省略号“…”的位置 - * \~chinese \param font 字体大小 - * \~chinese \param lineHeight 字符的行高 - * \~chinese \param flags 控制字体的对齐方式 - * \~chinese \return 转换好格式的文本 - */ -QString PixmapLabel::elideText(const QString &text, const QSizeF &size, - QTextOption::WrapMode wordWrap, const QFont &font, - Qt::TextElideMode mode, qreal lineHeight, int flags) -{ - QTextLayout textLayout(text); - - textLayout.setFont(font); - - QStringList lines; - - elideText(&textLayout, size, wordWrap, mode, lineHeight, flags, &lines); - - return lines.join('\n'); -} - void PixmapLabel::paintEvent(QPaintEvent *event) { QPainter painter(this); @@ -217,10 +117,9 @@ void PixmapLabel::paintEvent(QPaintEvent *event) } //draw lines - if (!m_text.isEmpty()) { + if (m_istext) { //drawText - QString t = elideText(m_text.simplified(), size(), QTextOption::WrapAnywhere, font(), Qt::ElideMiddle, 0); - QStringList labelTexts = t.split("\n"); + QStringList labelTexts = m_data->get_text(); int lineNum = labelTexts.length() > 4 ? 4 : labelTexts.length(); int lineHeight = (height() - TextContentTopMargin) / lineNum; for (int i = 0 ; i < lineNum; ++i) { diff --git a/dde-clipboard/pixmaplabel.h b/dde-clipboard/pixmaplabel.h index 2cb1f21..b5898aa 100644 --- a/dde-clipboard/pixmaplabel.h +++ b/dde-clipboard/pixmaplabel.h @@ -4,6 +4,9 @@ #ifndef PIXMAPLABEL_H #define PIXMAPLABEL_H +#include "itemdata.h" + +#include #include #include @@ -18,16 +21,14 @@ class QTextLayout; class PixmapLabel : public DLabel { public: - PixmapLabel(const QList &list, QWidget *parent = nullptr); - explicit PixmapLabel(QWidget *parent = nullptr); + explicit PixmapLabel(QPointer data, QWidget *parent = nullptr); /*! * \~chinese \name text * \~chinese \brief 获取剪切板中的文字 * \~chinese \return 返回剪切板中的文字 */ - const QString &text() {return m_text;} - void setText(const QString &text); + void setText(bool); inline const QList pixmapList() { return m_pixmapList; } void setPixmapList(const QList &list); @@ -35,19 +36,10 @@ class PixmapLabel : public DLabel virtual QSize minimumSizeHint() const override; virtual QSize sizeHint() const override; - QString elideText(const QString &text, const QSizeF &size, - QTextOption::WrapMode wordWrap, - const QFont &font, - Qt::TextElideMode mode, - qreal lineHeight, - int flags = 0); - - void elideText(QTextLayout *layout, const QSizeF &size, - QTextOption::WrapMode wordWrap, - Qt::TextElideMode mode, qreal lineHeight, - int flags = 0, QStringList *lines = 0); private: - QString m_text; + bool m_istext; + + QPointer m_data; QList m_pixmapList; private: diff --git a/tests/dde-clipboard/ut_itemwidget.cpp b/tests/dde-clipboard/ut_itemwidget.cpp index d904aef..e050900 100644 --- a/tests/dde-clipboard/ut_itemwidget.cpp +++ b/tests/dde-clipboard/ut_itemwidget.cpp @@ -100,7 +100,7 @@ TEST_F(TstItemWidget, propertyTest) ItemWidget w(m_imageData); QString text = "abcdefghijklmnopqrstuvwxyz"; - w.setText(text, QString::number(text.length())); + w.setTextShown(QString::number(text.length())); w.setAlpha(120); ASSERT_EQ(w.unHoverAlpha(), 120); diff --git a/tests/dde-clipboard/ut_pixmaplabel.cpp b/tests/dde-clipboard/ut_pixmaplabel.cpp deleted file mode 100644 index 35e90c3..0000000 --- a/tests/dde-clipboard/ut_pixmaplabel.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include -#include "pixmaplabel.h" - -#include -#include -#include - -class TstPixmapLabel : public testing::Test -{ -}; - -TEST_F(TstPixmapLabel, pixmapTest) -{ - QStyle *style = QApplication::style(); - const QPixmap &pix = style->standardPixmap(QStyle::SP_DialogYesButton); - QList list; - list << pix; - - // 只有一张图片 - QScopedPointer pixmapLabel(new PixmapLabel(list)); - pixmapLabel->setPixmapList(list); - pixmapLabel->show(); - QTest::qWait(1); - pixmapLabel->setEnabled(false); - QTest::qWait(1); - - // 两张图片 - list << pix; - QScopedPointer doublePixmapLabel(new PixmapLabel(list)); - pixmapLabel->show(); - QTest::qWait(1); - pixmapLabel->setEnabled(false); - QTest::qWait(1); - - // 三张图片 - list << pix; - QScopedPointer pixmapsLabel(new PixmapLabel(list)); - pixmapsLabel->setPixmapList(list); - pixmapsLabel->show(); - QTest::qWait(1); - pixmapsLabel->setEnabled(false); - QTest::qWait(1); - ASSERT_EQ(pixmapsLabel->pixmapList(), list); - - // 换一种构造函数 - QScopedPointer pixmapsLabelTmp(new PixmapLabel(list)); - pixmapsLabelTmp->show(); - QTest::qWait(1); - ASSERT_EQ(pixmapsLabelTmp->pixmapList(), list); -} - -TEST_F(TstPixmapLabel, coverageTest) -{ - QScopedPointer label(new PixmapLabel()); - - QString text = "abcdefghijklmnopqrstuvwxyz"; - - for (int i = 0; i < 10; ++i) - text += text; - - // 直接设置文本 - label->setText(text); - label->show(); - QTest::qWait(1); - - label->setAlignment(Qt::AlignRight); - label->elideText(text.simplified(), QSize(100,80), QTextOption::WrapAnywhere, qApp->font(), Qt::ElideMiddle, 0); - - label->setAlignment(Qt::AlignHCenter); - label->elideText(text.simplified(), QSize(100,80), QTextOption::WrapAnywhere, qApp->font(), Qt::ElideMiddle, 0); - - label->sizeHint(); - label->minimumSizeHint(); -}