Skip to content

Commit ff908af

Browse files
Kakueeendeepin-bot[bot]
authored andcommitted
refactor: replace QFontMetrics with QFontMetricsF and consolidate text
elision 1. Migrate from QFontMetrics to QFontMetricsF for higher precision in width calculations, removing Qt5 compatibility code. 2. Remove the unused `drawHighlightedText` function from HighlightUtils, as the delegate now directly uses `smartElideWithTracking` and `buildFormatRanges`. 3. Refactor GrandSearchListDelegate to use HighlightUtils for text elision and highlighting with position tracking, replacing old QTextDocument-based approach. 4. This ensures consistent handling of font metrics across different scaling factors and improves keyword visibility during elision. Log: Optimized text elision and highlighting algorithm for more accurate width calculations. Influence: 1. Verify that list item names and matched context text are displayed correctly with proper truncation and ellipsis. 2. Test keyword highlighting: ensure matched keywords remain visible after text truncation. 3. Test with various font sizes and DPI scaling to confirm width calculation accuracy. 4. Verify that the web searcher special marker character (e.g., last character) is preserved during truncation. 5. Test dark/light theme to ensure highlight colors remain appropriate. 6. Verify that no crash or regression occurs when keywords are empty or text is very short. refactor: 使用 QFontMetricsF 替换 QFontMetrics,统一文本省略逻辑 1. 将宽度计算从 QFontMetrics 迁移到 QFontMetricsF,以获得更高精度,并移 除 Qt5 兼容代码。 2. 移除 HighlightUtils 中未使用的 `drawHighlightedText` 函数,因为代理现 在直接使用 `smartElideWithTracking` 和 `buildFormatRanges`。 3. 重构 GrandSearchListDelegate,使用 HighlightUtils 进行带有位置追踪的 文本省略和高亮,替换旧的基于 QTextDocument 的方法。 4. 确保在不同缩放因子下字体度量处理的统一,并提高省略时关键词的可见性。 Log: 优化文本省略和高亮算法,使得宽度计算更精确。 Influence: 1. 验证列表项名称和匹配上下文文本显示是否正确,包括正确的截断和省略号。 2. 测试关键词高亮:确保省略后匹配的关键词仍然可见。 3. 在不同字体大小和 DPI 缩放下测试,确认宽度计算准确性。 4. 验证 Web 搜索器特殊标记字符(如最后一个字符)在截断时被保留。 5. 测试暗色/亮色主题,确保高亮颜色正确。 6. 验证当关键词为空或文本很短时不会出现崩溃或回归问题。 BUG: https://pms.uniontech.com/bug-view-365101.html BUG: https://pms.uniontech.com/bug-view-365311.html
1 parent d5d38aa commit ff908af

3 files changed

Lines changed: 92 additions & 169 deletions

File tree

src/global/widgets/highlightutils.cpp

Lines changed: 31 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,22 @@
55
#include "highlightutils.h"
66

77
#include <QPainter>
8-
#include <QFontMetrics>
8+
#include <QFontMetricsF>
99
#include <QRegularExpression>
1010
#include <QPalette>
11+
#include <QFont>
1112
#include <algorithm>
1213

1314
namespace HighlightUtils {
1415

15-
static int charWidth(const QFontMetrics &fm, QChar ch)
16+
static double charWidth(const QFontMetricsF &fm, QChar ch)
1617
{
17-
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
18-
return fm.width(ch);
19-
#else
2018
return fm.horizontalAdvance(ch);
21-
#endif
2219
}
2320

24-
static int textWidth(const QFontMetrics &fm, const QString &text)
21+
static double textWidth(const QFontMetricsF &fm, const QString &text)
2522
{
26-
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
27-
return fm.width(text);
28-
#else
2923
return fm.horizontalAdvance(text);
30-
#endif
3124
}
3225

3326
QVector<MatchRange> findMatchRanges(const QString &text, const QStringList &keywords)
@@ -58,16 +51,16 @@ QVector<MatchRange> findMatchRanges(const QString &text, const QStringList &keyw
5851
}
5952

6053
static ElideResult buildWindowElide(const QString &text, int keepStart, int keepEnd,
61-
int maxWidth, const QFontMetrics &fm)
54+
int maxWidth, const QFontMetricsF &fm)
6255
{
6356
ElideResult result;
6457
const QString ellipsis = QStringLiteral("");
65-
int ellipsisWidth = charWidth(fm, QChar(0x2026));
58+
double ellipsisWidth = charWidth(fm, QChar(0x2026));
6659

6760
bool needLeft = (keepStart > 0);
6861
bool needRight = (keepEnd < text.length());
6962
int numEllipsis = (needLeft ? 1 : 0) + (needRight ? 1 : 0);
70-
int budget = maxWidth - numEllipsis * ellipsisWidth;
63+
double budget = maxWidth - numEllipsis * ellipsisWidth;
7164
if (budget <= 0) {
7265
result.text = ellipsis;
7366
result.origPositions = { -1 };
@@ -76,10 +69,10 @@ static ElideResult buildWindowElide(const QString &text, int keepStart, int keep
7669

7770
int keepLen = keepEnd - keepStart;
7871
int trimLeft = 0, trimRight = 0;
79-
int w = textWidth(fm, text.mid(keepStart, keepLen));
72+
double w = textWidth(fm, text.mid(keepStart, keepLen));
8073
while (w > budget && keepLen > 0) {
81-
int lNext = charWidth(fm, text[keepStart + trimLeft]);
82-
int rNext = charWidth(fm, text[keepEnd - 1 - trimRight]);
74+
double lNext = charWidth(fm, text[keepStart + trimLeft]);
75+
double rNext = charWidth(fm, text[keepEnd - 1 - trimRight]);
8376
if (trimRight >= keepLen - trimLeft - 1) {
8477
w -= lNext;
8578
++trimLeft;
@@ -116,11 +109,11 @@ static ElideResult buildWindowElide(const QString &text, int keepStart, int keep
116109
}
117110

118111
ElideResult smartElideWithTracking(const QString &text, int maxWidth,
119-
const QFontMetrics &fm,
112+
const QFontMetricsF &fm,
120113
const QVector<MatchRange> &matchRanges)
121114
{
122115
const QString ellipsis = QStringLiteral("");
123-
int ellipsisWidth = charWidth(fm, QChar(0x2026));
116+
double ellipsisWidth = charWidth(fm, QChar(0x2026));
124117

125118
if (textWidth(fm, text) <= maxWidth) {
126119
ElideResult result;
@@ -152,9 +145,9 @@ ElideResult smartElideWithTracking(const QString &text, int maxWidth,
152145
bool needLeft = (keepStart > 0);
153146
bool needRight = (keepEnd < text.length());
154147
int numEllipsis = (needLeft ? 1 : 0) + (needRight ? 1 : 0);
155-
int budget = maxWidth - numEllipsis * ellipsisWidth;
148+
double budget = maxWidth - numEllipsis * ellipsisWidth;
156149

157-
int keptWidth = textWidth(fm, text.mid(keepStart, keepEnd - keepStart));
150+
double keptWidth = textWidth(fm, text.mid(keepStart, keepEnd - keepStart));
158151
if (keptWidth > budget)
159152
break;
160153

@@ -163,20 +156,20 @@ ElideResult smartElideWithTracking(const QString &text, int maxWidth,
163156

164157
bool expanded = false;
165158
if (keepStart > 0) {
166-
int cw = charWidth(fm, text[keepStart - 1]);
159+
double cw = charWidth(fm, text[keepStart - 1]);
167160
int newNeedLeft = (keepStart - 1 > 0);
168161
int newNumEllipsis = (newNeedLeft ? 1 : 0) + (needRight ? 1 : 0);
169-
int newBudget = maxWidth - newNumEllipsis * ellipsisWidth;
162+
double newBudget = maxWidth - newNumEllipsis * ellipsisWidth;
170163
if (keptWidth + cw <= newBudget) {
171164
--keepStart;
172165
expanded = true;
173166
}
174167
}
175168
if (!expanded && keepEnd < text.length()) {
176-
int cw = charWidth(fm, text[keepEnd]);
169+
double cw = charWidth(fm, text[keepEnd]);
177170
int newNeedRight = (keepEnd + 1 < text.length());
178171
int newNumEllipsis = (needLeft ? 1 : 0) + (newNeedRight ? 1 : 0);
179-
int newBudget = maxWidth - newNumEllipsis * ellipsisWidth;
172+
double newBudget = maxWidth - newNumEllipsis * ellipsisWidth;
180173
if (keptWidth + cw <= newBudget) {
181174
++keepEnd;
182175
expanded = true;
@@ -190,14 +183,14 @@ ElideResult smartElideWithTracking(const QString &text, int maxWidth,
190183
}
191184

192185
ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
193-
int maxWidth, const QFontMetrics &fm)
186+
int maxWidth, const QFontMetricsF &fm)
194187
{
195188
ElideResult result;
196189
if (text.isEmpty())
197190
return result;
198191

199192
const QString ellipsis = QStringLiteral("");
200-
int ellipsisWidth = charWidth(fm, QChar(0x2026));
193+
double ellipsisWidth = charWidth(fm, QChar(0x2026));
201194

202195
if (textWidth(fm, text) <= maxWidth) {
203196
result.text = text;
@@ -213,14 +206,14 @@ ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
213206
return result;
214207
}
215208

216-
int availWidth = maxWidth - ellipsisWidth;
209+
double availWidth = maxWidth - ellipsisWidth;
217210

218211
switch (mode) {
219212
case Qt::ElideRight: {
220-
int w = 0;
213+
double w = 0;
221214
int keep = 0;
222215
for (int i = 0; i < text.length(); ++i) {
223-
int cw = charWidth(fm, text[i]);
216+
double cw = charWidth(fm, text[i]);
224217
if (w + cw > availWidth)
225218
break;
226219
w += cw;
@@ -241,7 +234,7 @@ ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
241234
int tail = tryChars - head;
242235
if (head < 0 || tail < 0 || head + tail > total)
243236
continue;
244-
int w = textWidth(fm, text.left(head)) + textWidth(fm, text.right(tail));
237+
double w = textWidth(fm, text.left(head)) + textWidth(fm, text.right(tail));
245238
if (w <= availWidth) {
246239
bestKeep = tryChars;
247240
break;
@@ -264,10 +257,10 @@ ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
264257
break;
265258
}
266259
case Qt::ElideLeft: {
267-
int w = 0;
260+
double w = 0;
268261
int keep = 0;
269262
for (int i = text.length() - 1; i >= 0; --i) {
270-
int cw = charWidth(fm, text[i]);
263+
double cw = charWidth(fm, text[i]);
271264
if (w + cw > availWidth)
272265
break;
273266
w += cw;
@@ -293,11 +286,11 @@ ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
293286
}
294287

295288
QVector<QTextLayout::FormatRange> buildFormatRanges(
296-
const QString &displayText,
297-
const QVector<int> &origPosMapping,
298-
const QString &originalText,
299-
const QStringList &keywords,
300-
const QTextCharFormat &format)
289+
const QString &displayText,
290+
const QVector<int> &origPosMapping,
291+
const QString &originalText,
292+
const QStringList &keywords,
293+
const QTextCharFormat &format)
301294
{
302295
QVector<QTextLayout::FormatRange> ranges;
303296

@@ -373,72 +366,4 @@ QTextCharFormat defaultHighlightFormat(const QFont &baseFont, const QPalette &pa
373366
return fmt;
374367
}
375368

376-
void drawHighlightedText(QPainter *painter, const QString &text,
377-
const QStringList &keywords,
378-
const QFont &font, const QColor &textColor,
379-
const QColor &highlightColor,
380-
const QRect &rect, Qt::Alignment alignment)
381-
{
382-
if (text.isEmpty())
383-
return;
384-
385-
QFontMetrics fm(font);
386-
int maxWidth = rect.width();
387-
388-
// Elide
389-
QVector<MatchRange> matchRanges = findMatchRanges(text, keywords);
390-
ElideResult elideResult;
391-
392-
if (!matchRanges.isEmpty()) {
393-
elideResult = smartElideWithTracking(text, maxWidth, fm, matchRanges);
394-
}
395-
if (elideResult.text.isEmpty()) {
396-
elideResult = elideWithTracking(text, Qt::ElideRight, maxWidth, fm);
397-
}
398-
399-
const QString &displayText = elideResult.text;
400-
const QVector<int> &origPosMapping = elideResult.origPositions;
401-
402-
// Build format ranges for keywords
403-
QVector<QTextLayout::FormatRange> formats;
404-
if (!keywords.isEmpty()) {
405-
QTextCharFormat fmt;
406-
fmt.setFont(font);
407-
fmt.setFontWeight(QFont::DemiBold);
408-
fmt.setForeground(highlightColor);
409-
410-
// Create a temporary palette with our desired highlight color
411-
QPalette tempPalette;
412-
tempPalette.setColor(QPalette::BrightText, highlightColor);
413-
414-
formats = buildFormatRanges(displayText, origPosMapping, text, keywords, fmt);
415-
}
416-
417-
// Setup QTextLayout
418-
QTextLayout layout;
419-
layout.setText(displayText);
420-
layout.setFont(font);
421-
layout.setFormats(formats);
422-
423-
layout.beginLayout();
424-
QTextLine line = layout.createLine();
425-
if (line.isValid())
426-
line.setLineWidth(maxWidth);
427-
layout.endLayout();
428-
429-
// Vertical alignment
430-
int textHeight = fm.height();
431-
int y = rect.y();
432-
if (alignment & Qt::AlignVCenter)
433-
y += (rect.height() - textHeight) / 2;
434-
else if (alignment & Qt::AlignBottom)
435-
y += rect.height() - textHeight;
436-
437-
painter->save();
438-
painter->setPen(textColor);
439-
painter->translate(rect.x(), y);
440-
layout.draw(painter, QPointF(0, 0));
441-
painter->restore();
442-
}
443-
444369
} // namespace HighlightUtils

src/global/widgets/highlightutils.h

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#ifndef HIGHLIGHTUTILS_H
66
#define HIGHLIGHTUTILS_H
77

8-
#include <QFontMetrics>
8+
#include <QFontMetricsF>
99
#include <QTextLayout>
1010
#include <QString>
1111
#include <QStringList>
@@ -15,12 +15,14 @@ class QTextCharFormat;
1515

1616
namespace HighlightUtils {
1717

18-
struct MatchRange {
18+
struct MatchRange
19+
{
1920
int start;
2021
int end; // exclusive
2122
};
2223

23-
struct ElideResult {
24+
struct ElideResult
25+
{
2426
QString text;
2527
QVector<int> origPositions; // text[i] -> original char position, -1 for ellipsis char
2628
};
@@ -30,33 +32,25 @@ QVector<MatchRange> findMatchRanges(const QString &text, const QStringList &keyw
3032

3133
// Standard elide with position tracking
3234
ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
33-
int maxWidth, const QFontMetrics &fm);
35+
int maxWidth, const QFontMetricsF &fm);
3436

3537
// Smart elide that keeps keyword matches visible
3638
ElideResult smartElideWithTracking(const QString &text, int maxWidth,
37-
const QFontMetrics &fm,
39+
const QFontMetricsF &fm,
3840
const QVector<MatchRange> &matchRanges);
3941

4042
// Build QTextLayout format ranges for keyword highlighting
4143
// If origPosMapping is empty, matches are found directly in displayText
4244
// Otherwise, matches are found in originalText and mapped to display positions via origPosMapping
4345
QVector<QTextLayout::FormatRange> buildFormatRanges(
44-
const QString &displayText,
45-
const QVector<int> &origPosMapping,
46-
const QString &originalText,
47-
const QStringList &keywords,
48-
const QTextCharFormat &format);
46+
const QString &displayText,
47+
const QVector<int> &origPosMapping,
48+
const QString &originalText,
49+
const QStringList &keywords,
50+
const QTextCharFormat &format);
4951

5052
// Convenience: create a default highlight format (DemiBold + BrightText foreground)
5153
QTextCharFormat defaultHighlightFormat(const QFont &baseFont, const QPalette &palette);
52-
53-
// Render a highlighted, elided text using QTextLayout at a given rect
54-
void drawHighlightedText(QPainter *painter, const QString &text,
55-
const QStringList &keywords,
56-
const QFont &font, const QColor &textColor,
57-
const QColor &highlightColor,
58-
const QRect &rect, Qt::Alignment alignment = Qt::AlignVCenter | Qt::AlignLeft);
59-
6054
} // namespace HighlightUtils
6155

62-
#endif // HIGHLIGHTUTILS_H
56+
#endif // HIGHLIGHTUTILS_H

0 commit comments

Comments
 (0)