VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/objects/UIRichTextString.cpp

Last change on this file was 103362, checked in by vboxsync, 3 months ago

FE/Qt: bugref:10450: Get rid of QRegExp which is a part of Qt5 legacy API; This is necessary to get rid of Qt5 support lib.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mergeinfo set to (toggle deleted branches)
    /branches/VBox-3.0/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp58652,​70973
    /branches/VBox-3.2/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp66309,​66318
    /branches/VBox-4.0/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp70873
    /branches/VBox-4.1/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp74233
    /branches/VBox-4.2/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91503-91504,​91506-91508,​91510,​91514-91515,​91521
    /branches/VBox-4.3/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91223
    /branches/VBox-4.3/trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91223
    /branches/dsen/gui/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp79076-79078,​79089,​79109-79110,​79112-79113,​79127-79130,​79134,​79141,​79151,​79155,​79157-79159,​79193,​79197
    /branches/dsen/gui2/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp79562-79569,​79572-79573,​79578,​79581-79582,​79590-79591,​79598-79599,​79602-79603,​79605-79606,​79632,​79635,​79637,​79644
    /branches/dsen/gui3/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp79645-79692
    /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp79225,​79271
File size: 8.1 KB
Line 
1/* $Id: UIRichTextString.cpp 103362 2024-02-14 16:50:56Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIRichTextString class implementation.
4 */
5
6/*
7 * Copyright (C) 2015-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QApplication>
30#include <QPalette>
31#include <QRegularExpression>
32
33/* GUI includes: */
34#include "UIRichTextString.h"
35
36/* Other VBox includes: */
37#include "iprt/assert.h"
38
39
40const QString UIRichTextString::s_strAny = QString("[\\s\\S]*");
41const QMap<UIRichTextString::Type, QString> UIRichTextString::s_patterns = populatePatterns();
42const QMap<UIRichTextString::Type, bool> UIRichTextString::s_doPatternHasMeta = populatePatternHasMeta();
43
44UIRichTextString::UIRichTextString(Type enmType /* = Type_None */)
45 : m_enmType(enmType)
46 , m_strString(QString())
47 , m_strStringMeta(QString())
48{
49}
50
51UIRichTextString::UIRichTextString(const QString &strString, Type enmType /* = Type_None */, const QString &strStringMeta /* = QString() */)
52 : m_enmType(enmType)
53 , m_strString(strString)
54 , m_strStringMeta(strStringMeta)
55{
56 //printf("Creating new UIRichTextString with string=\"%s\" and string-meta=\"%s\"\n",
57 // m_strString.toUtf8().constData(), m_strStringMeta.toUtf8().constData());
58 parse();
59}
60
61UIRichTextString::~UIRichTextString()
62{
63 /* Erase the map: */
64 qDeleteAll(m_strings.begin(), m_strings.end());
65 m_strings.clear();
66}
67
68QString UIRichTextString::toString() const
69{
70 /* Add own string first: */
71 QString strString = m_strString;
72
73 /* Add all the strings of children finally: */
74 foreach (const int &iPosition, m_strings.keys())
75 strString.insert(iPosition, m_strings.value(iPosition)->toString());
76
77 /* Return result: */
78 return strString;
79}
80
81QVector<QTextLayout::FormatRange> UIRichTextString::formatRanges(int iShift /* = 0 */) const
82{
83 /* Prepare format range list: */
84 QVector<QTextLayout::FormatRange> ranges;
85
86 /* Add own format range first: */
87 QTextLayout::FormatRange range;
88 range.start = iShift;
89 range.length = toString().size();
90 range.format = textCharFormat(m_enmType);
91 /* Enable anchor if present: */
92 if (!m_strAnchor.isNull())
93 {
94 range.format.setAnchorHref(m_strAnchor);
95 /* Highlight anchor if hovered: */
96 if (range.format.anchorHref() == m_strHoveredAnchor)
97 range.format.setForeground(qApp->palette().color(QPalette::Link));
98 }
99 ranges.append(range);
100
101 /* Add all the format ranges of children finally: */
102 foreach (const int &iPosition, m_strings.keys())
103 ranges.append(m_strings.value(iPosition)->formatRanges(iShift + iPosition));
104
105 /* Return result: */
106 return ranges;
107}
108
109void UIRichTextString::setHoveredAnchor(const QString &strHoveredAnchor)
110{
111 /* Define own hovered anchor first: */
112 m_strHoveredAnchor = strHoveredAnchor;
113
114 /* Propagate hovered anchor to children finally: */
115 foreach (const int &iPosition, m_strings.keys())
116 m_strings.value(iPosition)->setHoveredAnchor(m_strHoveredAnchor);
117}
118
119void UIRichTextString::parse()
120{
121 /* Assign the meta to anchor directly for now,
122 * will do a separate parsing when there will
123 * be more than one type of meta: */
124 if (!m_strStringMeta.isNull())
125 m_strAnchor = m_strStringMeta;
126
127 /* Parse the passed QString with all the known patterns: */
128 foreach (const Type &enmPattern, s_patterns.keys())
129 {
130 /* Get the current pattern: */
131 const QString strPattern = s_patterns.value(enmPattern);
132
133 /* Recursively parse the string: */
134 int iMaxLevel = 0;
135 do
136 {
137 /* Search for the maximum level of the current pattern: */
138 iMaxLevel = searchForMaxLevel(m_strString, strPattern, strPattern);
139 //printf(" Maximum level for the pattern \"%s\" is %d.\n",
140 // strPattern.toUtf8().constData(), iMaxLevel);
141 /* If current pattern of at least level 1 is found: */
142 if (iMaxLevel > 0)
143 {
144 /* Compose full pattern of the corresponding level: */
145 const QString strFullPattern = composeFullPattern(strPattern, strPattern, iMaxLevel);
146 //printf(" Full pattern: %s\n", strFullPattern.toUtf8().constData());
147 QRegularExpression re(strFullPattern);
148 re.setPatternOptions(QRegularExpression::InvertedGreedinessOption);
149 const QRegularExpressionMatch mt = re.match(m_strString);
150 const int iPosition = mt.capturedStart();
151 AssertReturnVoid(iPosition != -1);
152 /* Cut the found string: */
153 m_strString.remove(iPosition, mt.capturedLength());
154 /* And paste that string as our child: */
155 const bool fPatterHasMeta = s_doPatternHasMeta.value(enmPattern);
156 const QString strSubString = !fPatterHasMeta ? mt.captured(1) : mt.captured(2);
157 const QString strSubMeta = !fPatterHasMeta ? QString() : mt.captured(1);
158 m_strings.insert(iPosition, new UIRichTextString(strSubString, enmPattern, strSubMeta));
159 }
160 }
161 while (iMaxLevel > 0);
162 }
163}
164
165/* static */
166QMap<UIRichTextString::Type, QString> UIRichTextString::populatePatterns()
167{
168 QMap<Type, QString> patterns;
169 patterns.insert(Type_Anchor, QString("<a href=([^>]+)>(%1)</a>"));
170 patterns.insert(Type_Bold, QString("<b>(%1)</b>"));
171 patterns.insert(Type_Italic, QString("<i>(%1)</i>"));
172 return patterns;
173}
174
175/* static */
176QMap<UIRichTextString::Type, bool> UIRichTextString::populatePatternHasMeta()
177{
178 QMap<Type, bool> patternHasMeta;
179 patternHasMeta.insert(Type_Anchor, true);
180 patternHasMeta.insert(Type_Bold, false);
181 patternHasMeta.insert(Type_Italic, false);
182 return patternHasMeta;
183}
184
185/* static */
186int UIRichTextString::searchForMaxLevel(const QString &strString, const QString &strPattern,
187 const QString &strCurrentPattern, int iCurrentLevel /* = 0 */)
188{
189 QRegularExpression re(strCurrentPattern.arg(s_strAny));
190 re.setPatternOptions(QRegularExpression::InvertedGreedinessOption);
191 const QRegularExpressionMatch mt = re.match(strString);
192 if (mt.hasMatch())
193 return searchForMaxLevel(strString, strPattern,
194 strCurrentPattern.arg(s_strAny + strPattern + s_strAny),
195 iCurrentLevel + 1);
196 return iCurrentLevel;
197}
198
199/* static */
200QString UIRichTextString::composeFullPattern(const QString &strPattern,
201 const QString &strCurrentPattern, int iCurrentLevel)
202{
203 if (iCurrentLevel > 1)
204 return composeFullPattern(strPattern,
205 strCurrentPattern.arg(s_strAny + strPattern + s_strAny),
206 iCurrentLevel - 1);
207 return strCurrentPattern.arg(s_strAny);
208}
209
210/* static */
211QTextCharFormat UIRichTextString::textCharFormat(Type enmType)
212{
213 QTextCharFormat format;
214 switch (enmType)
215 {
216 case Type_Anchor:
217 {
218 format.setAnchor(true);
219 break;
220 }
221 case Type_Bold:
222 {
223 QFont font = format.font();
224 font.setBold(true);
225 format.setFont(font);
226 break;
227 }
228 case Type_Italic:
229 {
230 QFont font = format.font();
231 font.setItalic(true);
232 format.setFont(font);
233 break;
234 }
235
236 case Type_None: break; /* Shut up MSC */
237 }
238 return format;
239}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use