Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions src/widgets/dcrumbedit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,22 +554,33 @@
QWidget* widgetRight;
};

QSizeF CrumbObjectInterface::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format)

Check warning on line 557 in src/widgets/dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'intrinsicSize' is never used.

Check warning on line 557 in src/widgets/dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

The function 'intrinsicSize' is never used.
{
Q_UNUSED(doc)
Q_UNUSED(posInDocument)

const DCrumbTextFormat crumb_format(format);
const QFontMetricsF font_metrics(crumb_format.font());
int radius = crumb_format.backgroundRadius();

if (crumb_format.tagColor().isValid())
return QSizeF(font_metrics.horizontalAdvance(crumb_format.text()) + font_metrics.height() + radius + 2, font_metrics.height() + 2);
if (crumb_format.tagColor().isValid()) {
qreal width = font_metrics.horizontalAdvance(crumb_format.text())
+ font_metrics.height() + radius + 2;
// 限制单个 crumb 不超过文档可用内容宽度,避免超宽标记撑开文档导致水平滚动条。
// 超宽时由 drawObject 做省略显示。仅对带标记颜色的 crumb 生效(本 issue 场景)。
const qreal textWidth = doc->textWidth();
if (textWidth > 0) {
const qreal avail = textWidth - 2 * doc->documentMargin();
if (avail > 0 && width > avail)
width = avail;
}
return QSizeF(width, font_metrics.height() + 2);
}

return QSizeF(font_metrics.horizontalAdvance(crumb_format.text()) + 2 * radius + 2, font_metrics.height() + 2 + TopMargin *2);
return QSizeF(font_metrics.horizontalAdvance(crumb_format.text()) + 2 * radius + 2,
font_metrics.height() + 2 + TopMargin * 2);
}

void CrumbObjectInterface::drawObject(QPainter *painter, const QRectF &rect,

Check warning on line 583 in src/widgets/dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'drawObject' is never used.

Check warning on line 583 in src/widgets/dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

The function 'drawObject' is never used.
QTextDocument *doc, int posInDocument, const QTextFormat &format)
{
Q_UNUSED(doc)
Expand All @@ -582,24 +593,32 @@

QPainterPath background_path;
QPainterPath tag_path;
const QRectF tag_rect(new_rect.x() + 2, new_rect.y() + 2, font_metrics.height() - 4, font_metrics.height() - 4);
const QRectF tag_rect(new_rect.x() + 2, new_rect.y() + 2,
font_metrics.height() - 4, font_metrics.height() - 4);

tag_path.addEllipse(tag_rect);
background_path.addRoundedRect(new_rect, radius, crumb_format.backgroundRadius());

painter->setRenderHint(QPainter::Antialiasing);
// 极窄宽度下色块可能超出收缩后的矩形,裁剪兜底防绘制越界
painter->save();
painter->setClipRect(new_rect);
painter->fillPath(background_path, backgroundBrush(new_rect, crumb_format.background()));

if (crumb_format.tagColor().isValid()) {
painter->fillPath(tag_path, crumb_format.tagColor());

painter->setPen(crumb_format.textColor());
painter->drawText(new_rect.adjusted(tag_rect.width() + 2, 0, -radius, 0),
crumb_format.text(), Qt::AlignVCenter | Qt::AlignRight);
const QRectF textRect = new_rect.adjusted(tag_rect.width() + 2, 0, -radius, 0);
// intrinsicSize 已将超宽 crumb 收缩到可用宽度,此处按实际可用宽度省略文字
QString displayText = crumb_format.text();
if (font_metrics.horizontalAdvance(displayText) > textRect.width())
displayText = font_metrics.elidedText(displayText, Qt::ElideRight, textRect.width());
painter->drawText(textRect, displayText, Qt::AlignVCenter | Qt::AlignLeft);
} else {
painter->setPen(crumb_format.textColor());
painter->drawText(new_rect, Qt::AlignCenter, crumb_format.text());
}
painter->restore();
}

QBrush CrumbObjectInterface::backgroundBrush(const QRect &rect, const QBrush &brush)
Expand Down
71 changes: 71 additions & 0 deletions tests/testcases/widgets/ut_dcrumbedit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
// SPDX-License-Identifier: LGPL-3.0-or-later

#include <gtest/gtest.h>
#include <QTest>

Check warning on line 6 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTest> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 6 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QTest> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QClipboard>

Check warning on line 7 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QClipboard> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 7 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QClipboard> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QMimeData>

Check warning on line 8 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMimeData> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 8 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QMimeData> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QTextDocument>

Check warning on line 9 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTextDocument> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 9 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QTextDocument> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QAbstractTextDocumentLayout>

Check warning on line 10 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QAbstractTextDocumentLayout> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 10 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QAbstractTextDocumentLayout> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QPainter>

Check warning on line 11 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPainter> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 11 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QPainter> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QImage>

Check warning on line 12 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QImage> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 12 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QImage> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include "dcrumbedit.h"

Check warning on line 14 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "dcrumbedit.h" not found.

Check warning on line 14 in tests/testcases/widgets/ut_dcrumbedit.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: "dcrumbedit.h" not found.
#include <QDebug>

DWIDGET_USE_NAMESPACE
Expand Down Expand Up @@ -104,3 +108,70 @@
ASSERT_EQ(qApp->clipboard()->text(), "测试1 人物 测试2 儿童 测试3 照片 测试代码调试添加GTest");
delete data;
}

// 验证:容器(文档)可用宽度小于 crumb 固有宽度时,带标记颜色的 crumb 文字会被省略且不溢出框外。
// 对应 issue:放大缩小右侧边栏时预览区标记自适应不好(缩小溢出、放大留白)。
TEST_F(ut_DCrumbedit, tagCrumbElidedAndNoOverflowWhenContainerNarrow)
{
// 创建带标记颜色 + 超长文字的 crumb
DCrumbTextFormat format = edit->makeTextFormat(DCrumbEdit::red);
ASSERT_TRUE(format.tagColor().isValid());

const QString longText = QString::fromUtf8("标记文字").repeated(20); // 远超容器宽度的超长文字
format.setText(longText);
// 用纯色背景/文字,便于按像素检测绘制范围
format.setBackground(QBrush(Qt::yellow));
format.setTextColor(Qt::black);

ASSERT_TRUE(edit->appendCrumb(format));
ASSERT_EQ(edit->crumbList().size(), 1);
ASSERT_EQ(edit->crumbList().first(), longText);

QTextDocument *doc = edit->document();
const QFontMetricsF fm(format.font());
// crumb 固有宽度(与 intrinsicSize 口径一致)
const qreal intrinsicWidth =
fm.horizontalAdvance(longText) + fm.height() + format.backgroundRadius() + 2;
// 将文档可用宽度设为远小于固有宽度,模拟缩小侧边栏
const int narrowWidth = int(intrinsicWidth / 3);
ASSERT_GT(narrowWidth, 0);
ASSERT_LT(qreal(narrowWidth), intrinsicWidth);
doc->setTextWidth(narrowWidth);

// 修复前 intrinsicSize 未限宽,单个超宽 crumb 会撑开文档宽度导致水平滚动条;
// 修复后 idealWidth 应不超出文档可用宽度。
EXPECT_LE(doc->idealWidth(), qreal(narrowWidth))
<< "单个超宽 crumb 撑开了文档宽度(" << doc->idealWidth()
<< " > " << narrowWidth << "),会产生水平滚动条";

// 渲染文档到一张比 narrowWidth 更宽的图片,检测 crumb 是否溢出文档可用宽度
QImage img(int(intrinsicWidth) + 40, 100, QImage::Format_ARGB32);
img.fill(Qt::white);
QPainter p(&img);
QAbstractTextDocumentLayout::PaintContext ctx;
doc->documentLayout()->draw(&p, ctx);
p.end();

// 找出最右侧的非背景像素,crumb 不应溢出到 narrowWidth 右侧(留少量抗锯齿容差)
int rightMostContentX = -1;
for (int y = 0; y < img.height(); ++y) {
for (int x = img.width() - 1; x > rightMostContentX; --x) {
if (img.pixelColor(x, y) != Qt::white) {
rightMostContentX = x;
break;
}
}
}
// 容差 8 像素用于抗锯齿/圆角;无修复时 crumb 会溢出到约 intrinsicWidth 处
EXPECT_LT(rightMostContentX, narrowWidth + 8)
<< "crumb 内容溢出文档可用宽度(" << narrowWidth
<< "),rightMostContentX=" << rightMostContentX;

// 绘制层省略不改变实际 crumb 文本
EXPECT_EQ(edit->crumbList().first(), longText);

// 省略逻辑:对窄宽度做 elidedText 应得到含省略号的较短文本
const QString elided = fm.elidedText(longText, Qt::ElideRight, narrowWidth);
EXPECT_LT(fm.horizontalAdvance(elided), fm.horizontalAdvance(longText));
EXPECT_TRUE(elided.contains(QChar(0x2026))); // 包含省略号 “…”
}
Loading