Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qtextmarkdownwriter.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6#include "qfontinfo.h"
7#include "qfontmetrics.h"
8#include "qtextdocument_p.h"
9#include "qtextlist.h"
10#include "qtexttable.h"
11#include "qtextcursor.h"
12#include "qtextimagehandler_p.h"
13#include "qloggingcategory.h"
14#if QT_CONFIG(itemmodel)
15#include "qabstractitemmodel.h"
16#endif
17
19
20using namespace Qt::StringLiterals;
21
22Q_LOGGING_CATEGORY(lcMDW, "qt.text.markdown.writer")
23
24static const QChar qtmw_Space = u' ';
25static const QChar qtmw_Tab = u'\t';
26static const QChar qtmw_Newline = u'\n';
27static const QChar qtmw_CarriageReturn = u'\r';
28static const QChar qtmw_LineBreak = u'\x2028';
29static const QChar qtmw_DoubleQuote = u'"';
30static const QChar qtmw_Backtick = u'`';
31static const QChar qtmw_Backslash = u'\\';
32static const QChar qtmw_Period = u'.';
33
35 : m_stream(stream), m_features(features)
36{
37}
38
40{
41 writeFrame(document->rootFrame());
42 return true;
43}
44
45#if QT_CONFIG(itemmodel)
46void QTextMarkdownWriter::writeTable(const QAbstractItemModel *table)
47{
48 QList<int> tableColumnWidths(table->columnCount());
49 for (int col = 0; col < table->columnCount(); ++col) {
50 tableColumnWidths[col] = table->headerData(col, Qt::Horizontal).toString().size();
51 for (int row = 0; row < table->rowCount(); ++row) {
52 tableColumnWidths[col] = qMax(tableColumnWidths[col],
53 table->data(table->index(row, col)).toString().size());
54 }
55 }
56
57 // write the header and separator
58 for (int col = 0; col < table->columnCount(); ++col) {
59 QString s = table->headerData(col, Qt::Horizontal).toString();
60 m_stream << '|' << s << QString(tableColumnWidths[col] - s.size(), qtmw_Space);
61 }
62 m_stream << "|" << Qt::endl;
63 for (int col = 0; col < tableColumnWidths.size(); ++col)
64 m_stream << '|' << QString(tableColumnWidths[col], u'-');
65 m_stream << '|'<< Qt::endl;
66
67 // write the body
68 for (int row = 0; row < table->rowCount(); ++row) {
69 for (int col = 0; col < table->columnCount(); ++col) {
70 QString s = table->data(table->index(row, col)).toString();
71 m_stream << '|' << s << QString(tableColumnWidths[col] - s.size(), qtmw_Space);
72 }
73 m_stream << '|'<< Qt::endl;
74 }
75 m_listInfo.clear();
76}
77#endif
78
80{
82 const QTextTable *table = qobject_cast<const QTextTable*> (frame);
83 QTextFrame::iterator iterator = frame->begin();
84 QTextFrame *child = nullptr;
85 int tableRow = -1;
86 bool lastWasList = false;
87 QList<int> tableColumnWidths;
88 if (table) {
89 tableColumnWidths.resize(table->columns());
90 for (int col = 0; col < table->columns(); ++col) {
91 for (int row = 0; row < table->rows(); ++ row) {
92 QTextTableCell cell = table->cellAt(row, col);
93 int cellTextLen = 0;
94 auto it = cell.begin();
95 while (it != cell.end()) {
96 QTextBlock block = it.currentBlock();
97 if (block.isValid())
98 cellTextLen += block.text().size();
99 ++it;
100 }
101 if (cell.columnSpan() == 1 && tableColumnWidths[col] < cellTextLen)
102 tableColumnWidths[col] = cellTextLen;
103 }
104 }
105 }
106 while (!iterator.atEnd()) {
107 if (iterator.currentFrame() && child != iterator.currentFrame())
108 writeFrame(iterator.currentFrame());
109 else { // no frame, it's a block
110 QTextBlock block = iterator.currentBlock();
111 // Look ahead and detect some cases when we should
112 // suppress needless blank lines, when there will be a big change in block format
113 bool nextIsDifferent = false;
114 bool ending = false;
115 {
116 QTextFrame::iterator next = iterator;
117 ++next;
118 if (next.atEnd()) {
119 nextIsDifferent = true;
120 ending = true;
121 } else {
122 QTextBlockFormat format = iterator.currentBlock().blockFormat();
123 QTextBlockFormat nextFormat = next.currentBlock().blockFormat();
124 if (nextFormat.indent() != format.indent() ||
126 nextIsDifferent = true;
127 }
128 }
129 if (table) {
130 QTextTableCell cell = table->cellAt(block.position());
131 if (tableRow < cell.row()) {
132 if (tableRow == 0) {
133 m_stream << qtmw_Newline;
134 for (int col = 0; col < tableColumnWidths.size(); ++col)
135 m_stream << '|' << QString(tableColumnWidths[col], u'-');
136 m_stream << '|';
137 }
138 m_stream << qtmw_Newline << '|';
139 tableRow = cell.row();
140 }
141 } else if (!block.textList()) {
142 if (lastWasList)
143 m_stream << qtmw_Newline;
144 }
145 int endingCol = writeBlock(block, !table, table && tableRow == 0,
146 nextIsDifferent && !block.textList());
147 m_doubleNewlineWritten = false;
148 if (table) {
149 QTextTableCell cell = table->cellAt(block.position());
150 int paddingLen = -endingCol;
151 int spanEndCol = cell.column() + cell.columnSpan();
152 for (int col = cell.column(); col < spanEndCol; ++col)
153 paddingLen += tableColumnWidths[col];
154 if (paddingLen > 0)
155 m_stream << QString(paddingLen, qtmw_Space);
156 for (int col = cell.column(); col < spanEndCol; ++col)
157 m_stream << "|";
158 } else if (m_fencedCodeBlock && ending) {
159 m_stream << qtmw_Newline << m_linePrefix << QString(m_wrappedLineIndent, qtmw_Space)
160 << m_codeBlockFence << qtmw_Newline << qtmw_Newline;
161 m_codeBlockFence.clear();
162 } else if (m_indentedCodeBlock && nextIsDifferent) {
163 m_stream << qtmw_Newline << qtmw_Newline;
164 } else if (endingCol > 0) {
166 m_stream << qtmw_Newline;
167 } else {
168 m_stream << qtmw_Newline << qtmw_Newline;
169 m_doubleNewlineWritten = true;
170 }
171 }
172 lastWasList = block.textList();
173 }
174 child = iterator.currentFrame();
175 ++iterator;
176 }
177 if (table) {
178 m_stream << qtmw_Newline << qtmw_Newline;
179 m_doubleNewlineWritten = true;
180 }
181 m_listInfo.clear();
182}
183
184QTextMarkdownWriter::ListInfo QTextMarkdownWriter::listInfo(QTextList *list)
185{
186 if (!m_listInfo.contains(list)) {
187 // decide whether this list is loose or tight
188 ListInfo info;
189 info.loose = false;
190 if (list->count() > 1) {
191 QTextBlock first = list->item(0);
192 QTextBlock last = list->item(list->count() - 1);
193 QTextBlock next = first.next();
194 while (next.isValid()) {
195 if (next == last)
196 break;
197 qCDebug(lcMDW) << "next block in list" << list << next.text() << "part of list?" << next.textList();
198 if (!next.textList()) {
199 // If we find a continuation paragraph, this list is "loose"
200 // because it will need a blank line to separate that paragraph.
201 qCDebug(lcMDW) << "decided list beginning with" << first.text() << "is loose after" << next.text();
202 info.loose = true;
203 break;
204 }
205 next = next.next();
206 }
207 }
208 m_listInfo.insert(list, info);
209 return info;
210 }
211 return m_listInfo.value(list);
212}
213
214static int nearestWordWrapIndex(const QString &s, int before)
215{
216 before = qMin(before, s.size());
217 int fragBegin = qMax(before - 15, 0);
218 if (lcMDW().isDebugEnabled()) {
219 QString frag = s.mid(fragBegin, 30);
220 qCDebug(lcMDW) << frag << before;
221 qCDebug(lcMDW) << QString(before - fragBegin, qtmw_Period) + u'<';
222 }
223 for (int i = before - 1; i >= 0; --i) {
224 if (s.at(i).isSpace()) {
225 qCDebug(lcMDW) << QString(i - fragBegin, qtmw_Period) + u'^' << i;
226 return i;
227 }
228 }
229 qCDebug(lcMDW, "not possible");
230 return -1;
231}
232
234{
235 int start = -1, len = s.size();
236 int ret = 0;
237 for (int i = 0; i < len; ++i) {
238 if (s.at(i) == qtmw_Backtick) {
239 if (start < 0)
240 start = i;
241 } else if (start >= 0) {
242 ret = qMax(ret, i - start);
243 start = -1;
244 }
245 }
246 if (s.at(len - 1) == qtmw_Backtick)
247 ret = qMax(ret, len - start);
248 return ret;
249}
250
252{
253 QString sTrimmed = s.trimmed();
254 if (sTrimmed.isEmpty())
255 return;
256 char firstChar = sTrimmed.at(0).toLatin1();
257 if (firstChar == '*' || firstChar == '+' || firstChar == '-') {
258 int i = s.indexOf(QLatin1Char(firstChar));
259 s.insert(i, u'\\');
260 }
261}
262
266};
267
269{
271
272 while (begin < end) {
273 if (*begin == qtmw_Newline) {
274 result.lineEnd = begin;
275 result.nextLineBegin = begin + 1;
276 break;
277 } else if (*begin == qtmw_CarriageReturn) {
278 result.lineEnd = begin;
279 result.nextLineBegin = begin + 1;
280 if (((begin + 1) < end) && begin[1] == qtmw_Newline)
281 ++result.nextLineBegin;
282 break;
283 }
284
285 ++begin;
286 }
287
288 return result;
289}
290
291static bool isBlankLine(const QChar *begin, const QChar *end)
292{
293 while (begin < end) {
294 if (*begin != qtmw_Space && *begin != qtmw_Tab)
295 return false;
296 ++begin;
297 }
298 return true;
299}
300
302{
304 result.reserve(title.size() + 2);
306
307 const QChar *data = title.data();
308 const QChar *end = data + title.size();
309
310 while (data < end) {
311 const auto lineEndPositions = findLineEnd(data, end);
312
313 if (!isBlankLine(data, lineEndPositions.lineEnd)) {
314 while (data < lineEndPositions.nextLineBegin) {
315 if (*data == qtmw_DoubleQuote)
317 result += *data;
318 ++data;
319 }
320 }
321
322 data = lineEndPositions.nextLineBegin;
323 }
324
326 return result;
327}
328
329int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ignoreFormat, bool ignoreEmpty)
330{
331 if (block.text().isEmpty() && ignoreEmpty)
332 return 0;
333 const int ColumnLimit = 80;
334 QTextBlockFormat blockFmt = block.blockFormat();
335 bool missedBlankCodeBlockLine = false;
336 const bool codeBlock = blockFmt.hasProperty(QTextFormat::BlockCodeFence) ||
338 blockFmt.nonBreakableLines();
339 if (m_fencedCodeBlock && !codeBlock) {
340 m_stream << m_linePrefix << m_codeBlockFence << qtmw_Newline;
341 m_fencedCodeBlock = false;
342 m_codeBlockFence.clear();
343 }
344 if (block.textList()) { // it's a list-item
345 auto fmt = block.textList()->format();
346 const int listLevel = fmt.indent();
347 // Negative numbers don't start a list in Markdown, so ignore them.
348 const int start = fmt.start() >= 0 ? fmt.start() : 1;
349 const int number = block.textList()->itemNumber(block) + start;
350 QByteArray bullet = " ";
351 bool numeric = false;
352 switch (fmt.style()) {
354 bullet = "-";
355 m_wrappedLineIndent = 2;
356 break;
358 bullet = "*";
359 m_wrappedLineIndent = 2;
360 break;
362 bullet = "+";
363 m_wrappedLineIndent = 2;
364 break;
371 numeric = true;
372 m_wrappedLineIndent = 4;
373 break;
374 }
375 switch (blockFmt.marker()) {
377 bullet += " [x]";
378 break;
380 bullet += " [ ]";
381 break;
382 default:
383 break;
384 }
385 int indentFirstLine = (listLevel - 1) * (numeric ? 4 : 2);
386 m_wrappedLineIndent += indentFirstLine;
387 if (m_lastListIndent != listLevel && !m_doubleNewlineWritten && listInfo(block.textList()).loose)
388 m_stream << qtmw_Newline;
389 m_lastListIndent = listLevel;
390 QString prefix(indentFirstLine, qtmw_Space);
391 if (numeric) {
392 QString suffix = fmt.numberSuffix();
393 if (suffix.isEmpty())
394 suffix = QString(qtmw_Period);
395 QString numberStr = QString::number(number) + suffix + qtmw_Space;
396 if (numberStr.size() == 3)
397 numberStr += qtmw_Space;
398 prefix += numberStr;
399 } else {
400 prefix += QLatin1StringView(bullet) + qtmw_Space;
401 }
402 m_stream << prefix;
404 m_stream << "- - -\n"; // unambiguous horizontal rule, not an underline under a heading
405 return 0;
406 } else if (codeBlock) {
407 // It's important to preserve blank lines in code blocks. But blank lines in code blocks
408 // inside block quotes are getting preserved anyway (along with the "> " prefix).
410 missedBlankCodeBlockLine = true; // only if we don't get any fragments below
411 if (!m_fencedCodeBlock) {
413 if (fenceChar.isEmpty())
414 fenceChar = "`"_L1;
415 m_codeBlockFence = QString(3, fenceChar.at(0));
417 m_codeBlockFence = QString(m_wrappedLineIndent, qtmw_Space) + m_codeBlockFence;
418 // A block quote can contain an indented code block, but not vice-versa.
419 m_stream << m_linePrefix << m_codeBlockFence
421 m_fencedCodeBlock = true;
422 }
423 wrap = false;
424 } else if (!blockFmt.indent()) {
425 m_wrappedLineIndent = 0;
426 m_linePrefix.clear();
429 QString quoteMarker = QStringLiteral("> ");
430 m_linePrefix.reserve(level * 2);
431 for (int i = 0; i < level; ++i)
432 m_linePrefix += quoteMarker;
433 }
435 // A block quote can contain an indented code block, but not vice-versa.
436 m_linePrefix += QString(4, qtmw_Space);
437 m_indentedCodeBlock = true;
438 }
439 }
440 if (blockFmt.headingLevel())
441 m_stream << QByteArray(blockFmt.headingLevel(), '#') << ' ';
442 else
443 m_stream << m_linePrefix;
444
445 QString wrapIndentString = m_linePrefix + QString(m_wrappedLineIndent, qtmw_Space);
446 // It would be convenient if QTextStream had a lineCharPos() accessor,
447 // to keep track of how many characters (not bytes) have been written on the current line,
448 // but it doesn't. So we have to keep track with this col variable.
449 int col = wrapIndentString.size();
450 bool mono = false;
451 bool startsOrEndsWithBacktick = false;
452 bool bold = false;
453 bool italic = false;
454 bool underline = false;
455 bool strikeOut = false;
456 QString backticks(qtmw_Backtick);
457 for (QTextBlock::Iterator frag = block.begin(); !frag.atEnd(); ++frag) {
458 missedBlankCodeBlockLine = false;
459 QString fragmentText = frag.fragment().text();
460 while (fragmentText.endsWith(qtmw_Newline))
461 fragmentText.chop(1);
462 if (block.textList()) { // <li>first line</br>continuation</li>
463 QString newlineIndent =
464 QString(qtmw_Newline) + QString(m_wrappedLineIndent, qtmw_Space);
465 fragmentText.replace(QString(qtmw_LineBreak), newlineIndent);
466 } else if (blockFmt.indent() > 0) { // <li>first line<p>continuation</p></li>
467 m_stream << QString(m_wrappedLineIndent, qtmw_Space);
468 } else {
469 fragmentText.replace(qtmw_LineBreak, qtmw_Newline);
470 }
471 startsOrEndsWithBacktick |=
472 fragmentText.startsWith(qtmw_Backtick) || fragmentText.endsWith(qtmw_Backtick);
473 QTextCharFormat fmt = frag.fragment().charFormat();
474 if (fmt.isImageFormat()) {
475 QTextImageFormat ifmt = fmt.toImageFormat();
477 if (desc.isEmpty())
478 desc = "image"_L1;
479 QString s = "!["_L1 + desc + "]("_L1 + ifmt.name();
481 if (!title.isEmpty())
483 s += u')';
484 if (wrap && col + s.size() > ColumnLimit) {
485 m_stream << qtmw_Newline << wrapIndentString;
486 col = m_wrappedLineIndent;
487 }
488 m_stream << s;
489 col += s.size();
490 } else if (fmt.hasProperty(QTextFormat::AnchorHref)) {
491 const auto href = fmt.property(QTextFormat::AnchorHref).toString();
492 const bool hasToolTip = fmt.hasProperty(QTextFormat::TextToolTip);
493 QString s;
494 if (!hasToolTip && href == fragmentText && !QUrl(href, QUrl::StrictMode).scheme().isEmpty()) {
495 s = u'<' + href + u'>';
496 } else {
497 s = u'[' + fragmentText + "]("_L1 + href;
498 if (hasToolTip) {
499 s += qtmw_Space;
500 s += createLinkTitle(fmt.property(QTextFormat::TextToolTip).toString());
501 }
502 s += u')';
503 }
504 if (wrap && col + s.size() > ColumnLimit) {
505 m_stream << qtmw_Newline << wrapIndentString;
506 col = m_wrappedLineIndent;
507 }
508 m_stream << s;
509 col += s.size();
510 } else {
511 QFontInfo fontInfo(fmt.font());
512 bool monoFrag = fontInfo.fixedPitch() || fmt.fontFixedPitch();
513 QString markers;
514 if (!ignoreFormat) {
515 if (monoFrag != mono && !m_indentedCodeBlock && !m_fencedCodeBlock) {
516 if (monoFrag)
517 backticks =
518 QString(adjacentBackticksCount(fragmentText) + 1, qtmw_Backtick);
519 markers += backticks;
520 if (startsOrEndsWithBacktick)
521 markers += qtmw_Space;
522 mono = monoFrag;
523 }
524 if (!blockFmt.headingLevel() && !mono) {
525 if (fontInfo.bold() != bold) {
526 markers += "**"_L1;
527 bold = fontInfo.bold();
528 }
529 if (fontInfo.italic() != italic) {
530 markers += u'*';
531 italic = fontInfo.italic();
532 }
533 if (fontInfo.strikeOut() != strikeOut) {
534 markers += "~~"_L1;
535 strikeOut = fontInfo.strikeOut();
536 }
537 if (fontInfo.underline() != underline) {
538 // Markdown doesn't support underline, but the parser will treat a single underline
539 // the same as a single asterisk, and the marked fragment will be rendered in italics.
540 // That will have to do.
541 markers += u'_';
542 underline = fontInfo.underline();
543 }
544 }
545 }
546 if (wrap && col + markers.size() * 2 + fragmentText.size() > ColumnLimit) {
547 int i = 0;
548 const int fragLen = fragmentText.size();
549 bool breakingLine = false;
550 while (i < fragLen) {
551 if (col >= ColumnLimit) {
552 m_stream << qtmw_Newline << wrapIndentString;
553 col = m_wrappedLineIndent;
554 while (i < fragLen && fragmentText[i].isSpace())
555 ++i;
556 }
557 int j = i + ColumnLimit - col;
558 if (j < fragLen) {
559 int wi = nearestWordWrapIndex(fragmentText, j);
560 if (wi < 0) {
561 j = fragLen;
562 } else if (wi >= i) {
563 j = wi;
564 breakingLine = true;
565 }
566 } else {
567 j = fragLen;
568 breakingLine = false;
569 }
570 QString subfrag = fragmentText.mid(i, j - i);
571 if (!i) {
572 m_stream << markers;
573 col += markers.size();
574 }
575 if (col == m_wrappedLineIndent)
576 maybeEscapeFirstChar(subfrag);
577 m_stream << subfrag;
578 if (breakingLine) {
579 m_stream << qtmw_Newline << wrapIndentString;
580 col = m_wrappedLineIndent;
581 } else {
582 col += subfrag.size();
583 }
584 i = j + 1;
585 }
586 } else {
587 m_stream << markers << fragmentText;
588 col += markers.size() + fragmentText.size();
589 }
590 }
591 }
592 if (mono) {
593 if (startsOrEndsWithBacktick) {
594 m_stream << qtmw_Space;
595 col += 1;
596 }
597 m_stream << backticks;
598 col += backticks.size();
599 }
600 if (bold) {
601 m_stream << "**";
602 col += 2;
603 }
604 if (italic) {
605 m_stream << "*";
606 col += 1;
607 }
608 if (underline) {
609 m_stream << "_";
610 col += 1;
611 }
612 if (strikeOut) {
613 m_stream << "~~";
614 col += 2;
615 }
616 if (missedBlankCodeBlockLine)
617 m_stream << qtmw_Newline;
618 return col;
619}
620
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qchar.h:48
constexpr char toLatin1() const noexcept
Returns the Latin-1 character equivalent to the QChar, or 0.
Definition qchar.h:457
\reentrant
Definition qfontinfo.h:14
bool italic() const
Returns the italic value of the matched window system font.
Definition qfont.cpp:2871
bool fixedPitch() const
Returns the fixed pitch value of the matched window system font.
Definition qfont.cpp:2982
bool bold() const
Returns true if weight() would return a value greater than QFont::Normal; otherwise returns false.
Definition qfontinfo.h:32
bool strikeOut() const
Returns the strikeout value of the matched window system font.
Definition qfont.cpp:2972
bool underline() const
Returns the underline value of the matched window system font.
Definition qfont.cpp:2944
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
qsizetype count() const noexcept
Definition qlist.h:387
void resize(qsizetype size)
Definition qlist.h:392
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:356
bool contains(const Key &key) const
Definition qmap.h:340
void clear()
Definition qmap.h:288
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
Definition qstring.h:1173
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6180
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1095
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QString trimmed() const &
Definition qstring.h:380
int headingLevel() const
MarkerType marker() const
bool nonBreakableLines() const
Returns true if the lines in the paragraph are non-breakable; otherwise returns false.
int indent() const
Returns the paragraph's indent.
\reentrant
iterator begin() const
Returns a text block iterator pointing to the beginning of the text block.
QTextBlockFormat blockFormat() const
Returns the QTextBlockFormat that describes block-specific properties.
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
int position() const
Returns the index of the block's first character within the document.
QString text() const
Returns the block's contents as plain text.
QTextList * textList() const
If the block represents a list item, returns the list that the item belongs to; otherwise returns \nu...
\reentrant \inmodule QtGui
QString stringProperty(int propertyId) const
Returns the value of the property given by propertyId; if the property isn't of QMetaType::QString ty...
@ BlockTrailingHorizontalRulerWidth
int intProperty(int propertyId) const
Returns the value of the property specified by propertyId.
bool hasProperty(int propertyId) const
Returns true if the text format has a property with the given propertyId; otherwise returns false.
QVariant property(int propertyId) const
Returns the property specified by the given propertyId.
\reentrant
Definition qtextobject.h:81
QString name() const
Returns the name of the image.
\reentrant
Definition qtextlist.h:18
int itemNumber(const QTextBlock &) const
Returns the index of the list item that corresponds to the given block.
QTextListFormat format() const
Returns the list's format.
Definition qtextlist.h:37
bool writeAll(const QTextDocument *document)
int writeBlock(const QTextBlock &block, bool table, bool ignoreFormat, bool ignoreEmpty)
void writeFrame(const QTextFrame *frame)
\inmodule QtCore
\reentrant
Definition qtexttable.h:19
int columnSpan() const
Returns the number of columns this cell spans.
QTextFrame::iterator end() const
Returns a frame iterator pointing to the end of the table's cell.
int row() const
Returns the number of the row in the table that contains this cell.
int column() const
Returns the number of the column in the table that contains this cell.
QTextFrame::iterator begin() const
Returns a frame iterator pointing to the beginning of the table's cell.
\reentrant
Definition qtexttable.h:63
\inmodule QtCore
Definition qurl.h:94
@ StrictMode
Definition qurl.h:98
QSet< QString >::iterator it
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
@ Horizontal
Definition qnamespace.h:98
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
EGLStreamKHR stream
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum GLuint GLint level
GLboolean r
[2]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLint first
GLfloat n
GLint GLsizei GLsizei GLenum format
GLenum GLsizei len
GLdouble GLdouble t
Definition qopenglext.h:243
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLenum GLenum GLsizei void * table
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
static QT_BEGIN_NAMESPACE QAsn1Element wrap(quint8 type, const QAsn1Element &child)
#define QStringLiteral(str)
static const QChar qtmw_Backtick
static const QChar qtmw_Backslash
static const QChar qtmw_DoubleQuote
static const QChar qtmw_CarriageReturn
static int nearestWordWrapIndex(const QString &s, int before)
static const QChar qtmw_Newline
static int adjacentBackticksCount(const QString &s)
static QString createLinkTitle(const QString &title)
static bool isBlankLine(const QChar *begin, const QChar *end)
static const QChar qtmw_Tab
static void maybeEscapeFirstChar(QString &s)
static const QChar qtmw_Period
static LineEndPositions findLineEnd(const QChar *begin, const QChar *end)
static const QChar qtmw_Space
static const QChar qtmw_LineBreak
@ desc
QVideoFrameFormat::PixelFormat fmt
QList< int > list
[14]
QFileInfo info(fileName)
[8]
QString title
[35]
QLayoutItem * child
[0]
QFrame frame
[0]
\inmodule QtCore \reentrant
Definition qchar.h:17