Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtextdocumentfragment.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 "qtextcursor_p.h"
7#include "qtextlist.h"
8#if QT_CONFIG(textmarkdownreader)
10#endif
11#if QT_CONFIG(textmarkdownwriter)
13#endif
14
15#include <qdebug.h>
16#include <qbytearray.h>
17#include <qdatastream.h>
18#include <qdatetime.h>
19
21
22using namespace Qt::StringLiterals;
23
24QTextCopyHelper::QTextCopyHelper(const QTextCursor &_source, const QTextCursor &_destination, bool forceCharFormat, const QTextCharFormat &fmt)
25#if defined(Q_CC_DIAB) // compiler bug
26 : formatCollection(*_destination.d->priv->formatCollection()), originalText((const QString)_source.d->priv->buffer())
27#else
28 : formatCollection(*_destination.d->priv->formatCollection()), originalText(_source.d->priv->buffer())
29#endif
30{
31 src = _source.d->priv;
32 dst = _destination.d->priv;
33 insertPos = _destination.position();
34 this->forceCharFormat = forceCharFormat;
35 primaryCharFormatIndex = convertFormatIndex(fmt);
36 cursor = _source;
37}
38
39int QTextCopyHelper::convertFormatIndex(const QTextFormat &oldFormat, int objectIndexToSet)
40{
41 QTextFormat fmt = oldFormat;
42 if (objectIndexToSet != -1) {
43 fmt.setObjectIndex(objectIndexToSet);
44 } else if (fmt.objectIndex() != -1) {
45 int newObjectIndex = objectIndexMap.value(fmt.objectIndex(), -1);
46 if (newObjectIndex == -1) {
47 QTextFormat objFormat = src->formatCollection()->objectFormat(fmt.objectIndex());
48 Q_ASSERT(objFormat.objectIndex() == -1);
49 newObjectIndex = formatCollection.createObjectIndex(objFormat);
50 objectIndexMap.insert(fmt.objectIndex(), newObjectIndex);
51 }
52 fmt.setObjectIndex(newObjectIndex);
53 }
54 int idx = formatCollection.indexForFormat(fmt);
55 Q_ASSERT(formatCollection.format(idx).type() == oldFormat.type());
56 return idx;
57}
58
59int QTextCopyHelper::appendFragment(int pos, int endPos, int objectIndex)
60{
62 const QTextFragmentData * const frag = fragIt.value();
63
64 Q_ASSERT(objectIndex == -1
65 || (frag->size_array[0] == 1 && src->formatCollection()->format(frag->format).objectIndex() != -1));
66
67 int charFormatIndex;
68 if (forceCharFormat)
69 charFormatIndex = primaryCharFormatIndex;
70 else
71 charFormatIndex = convertFormatIndex(frag->format, objectIndex);
72
73 const int inFragmentOffset = qMax(0, pos - fragIt.position());
74 int charsToCopy = qMin(int(frag->size_array[0] - inFragmentOffset), endPos - pos);
75
76 QTextBlock nextBlock = src->blocksFind(pos + 1);
77
78 int blockIdx = -2;
79 if (nextBlock.position() == pos + 1) {
80 blockIdx = convertFormatIndex(nextBlock.blockFormat());
81 } else if (pos == 0 && insertPos == 0) {
82 dst->setBlockFormat(dst->blocksBegin(), dst->blocksBegin(), convertFormat(src->blocksBegin().blockFormat()).toBlockFormat());
83 dst->setCharFormat(-1, 1, convertFormat(src->blocksBegin().charFormat()).toCharFormat());
84 }
85
86 QString txtToInsert(originalText.constData() + frag->stringPosition + inFragmentOffset, charsToCopy);
87 if (txtToInsert.size() == 1
88 && (txtToInsert.at(0) == QChar::ParagraphSeparator
89 || txtToInsert.at(0) == QTextBeginningOfFrame
90 || txtToInsert.at(0) == QTextEndOfFrame
91 )
92 ) {
93 dst->insertBlock(txtToInsert.at(0), insertPos, blockIdx, charFormatIndex);
94 ++insertPos;
95 } else {
96 if (nextBlock.textList()) {
97 QTextBlock dstBlock = dst->blocksFind(insertPos);
98 if (!dstBlock.textList()) {
99 // insert a new text block with the block and char format from the
100 // source block to make sure that the following text fragments
101 // end up in a list as they should
102 int listBlockFormatIndex = convertFormatIndex(nextBlock.blockFormat());
103 int listCharFormatIndex = convertFormatIndex(nextBlock.charFormat());
104 dst->insertBlock(insertPos, listBlockFormatIndex, listCharFormatIndex);
105 ++insertPos;
106 }
107 }
108 dst->insert(insertPos, txtToInsert, charFormatIndex);
109 const int userState = nextBlock.userState();
110 if (userState != -1)
111 dst->blocksFind(insertPos).setUserState(userState);
112 insertPos += txtToInsert.size();
113 }
114
115 return charsToCopy;
116}
117
118void QTextCopyHelper::appendFragments(int pos, int endPos)
119{
120 Q_ASSERT(pos < endPos);
121
122 while (pos < endPos)
123 pos += appendFragment(pos, endPos);
124}
125
127{
128 if (cursor.hasComplexSelection()) {
129 QTextTable *table = cursor.currentTable();
130 int row_start, col_start, num_rows, num_cols;
131 cursor.selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
132
133 QTextTableFormat tableFormat = table->format();
134 tableFormat.setColumns(num_cols);
135 tableFormat.clearColumnWidthConstraints();
136 const int objectIndex = dst->formatCollection()->createObjectIndex(tableFormat);
137
138 Q_ASSERT(row_start != -1);
139 for (int r = row_start; r < row_start + num_rows; ++r) {
140 for (int c = col_start; c < col_start + num_cols; ++c) {
141 QTextTableCell cell = table->cellAt(r, c);
142 const int rspan = cell.rowSpan();
143 const int cspan = cell.columnSpan();
144 if (rspan != 1) {
145 int cr = cell.row();
146 if (cr != r)
147 continue;
148 }
149 if (cspan != 1) {
150 int cc = cell.column();
151 if (cc != c)
152 continue;
153 }
154
155 // add the QTextBeginningOfFrame
156 QTextCharFormat cellFormat = cell.format();
157 if (r + rspan >= row_start + num_rows) {
158 cellFormat.setTableCellRowSpan(row_start + num_rows - r);
159 }
160 if (c + cspan >= col_start + num_cols) {
161 cellFormat.setTableCellColumnSpan(col_start + num_cols - c);
162 }
163 const int charFormatIndex = convertFormatIndex(cellFormat, objectIndex);
164
165 int blockIdx = -2;
166 const int cellPos = cell.firstPosition();
167 QTextBlock block = src->blocksFind(cellPos);
168 if (block.position() == cellPos) {
169 blockIdx = convertFormatIndex(block.blockFormat());
170 }
171
172 dst->insertBlock(QTextBeginningOfFrame, insertPos, blockIdx, charFormatIndex);
173 ++insertPos;
174
175 // nothing to add for empty cells
176 if (cell.lastPosition() > cellPos) {
177 // add the contents
178 appendFragments(cellPos, cell.lastPosition());
179 }
180 }
181 }
182
183 // add end of table
184 int end = table->lastPosition();
185 appendFragment(end, end+1, objectIndex);
186 } else {
187 appendFragments(cursor.selectionStart(), cursor.selectionEnd());
188 }
189}
190
192 : ref(1), doc(new QTextDocument), importedFromPlainText(false)
193{
194 doc->setUndoRedoEnabled(false);
195
196 if (!_cursor.hasSelection())
197 return;
198
200 p->beginEditBlock();
201 QTextCursor destCursor(doc);
202 QTextCopyHelper(_cursor, destCursor).copy();
203 p->endEditBlock();
204
205 if (_cursor.d)
206 p->mergeCachedResources(_cursor.d->priv);
207}
208
210{
211 if (_cursor.isNull())
212 return;
213
214 QTextDocumentPrivate *destPieceTable = _cursor.d->priv;
215 destPieceTable->beginEditBlock();
216
217 QTextCursor sourceCursor(doc);
218 sourceCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
219 QTextCopyHelper(sourceCursor, _cursor, importedFromPlainText, _cursor.charFormat()).copy();
220
221 destPieceTable->endEditBlock();
222}
223
255
262 : d(nullptr)
263{
264 if (!document)
265 return;
266
267 QTextCursor cursor(const_cast<QTextDocument *>(document));
270}
271
279 : d(nullptr)
280{
281 if (!cursor.hasSelection())
282 return;
283
285}
286
293 : d(rhs.d)
294{
295 if (d)
296 d->ref.ref();
297}
298
305{
306 if (rhs.d)
307 rhs.d->ref.ref();
308 if (d && !d->ref.deref())
309 delete d;
310 d = rhs.d;
311 return *this;
312}
313
318{
319 if (d && !d->ref.deref())
320 delete d;
321}
322
327{
328 return d == nullptr || d->doc == nullptr || QTextDocumentPrivate::get(d->doc)->length() <= 1;
329}
330
343{
344 if (!d)
345 return QString();
346
347 return d->doc->toPlainText();
348}
349
358{
359 if (!d)
360 return QString();
361
362 return d->doc->toRawText();
363}
364
365#ifndef QT_NO_TEXTHTMLPARSER
366
375{
376 if (!d)
377 return QString();
378
380}
381
382#endif // QT_NO_TEXTHTMLPARSER
383
384#if QT_CONFIG(textmarkdownwriter)
385
394QString QTextDocumentFragment::toMarkdown(QTextDocument::MarkdownFeatures features) const
395{
396 if (!d)
397 return QString();
398
399 return d->doc->toMarkdown(features);
400}
401
402#endif // textmarkdownwriter
403
420
421#ifndef QT_NO_TEXTHTMLPARSER
422
424{
425 if (style == QTextListFormat::ListDisc)
427 else if (style == QTextListFormat::ListCircle)
429 return style;
430}
431
433 : indent(0), headingLevel(0), compressNextWhitespace(PreserveWhiteSpace), doc(_doc), importMode(mode)
434{
435 cursor = QTextCursor(doc);
437
438 QString html = _html;
439 const int startFragmentPos = html.indexOf("<!--StartFragment-->"_L1);
440 if (startFragmentPos != -1) {
441 const auto qt3RichTextHeader = "<meta name=\"qrichtext\" content=\"1\" />"_L1;
442
443 // Hack for Qt3
444 const bool hasQtRichtextMetaTag = html.contains(qt3RichTextHeader);
445
446 const int endFragmentPos = html.indexOf("<!--EndFragment-->"_L1);
447 if (startFragmentPos < endFragmentPos)
448 html = html.mid(startFragmentPos, endFragmentPos - startFragmentPos);
449 else
450 html = html.mid(startFragmentPos);
451
452 if (hasQtRichtextMetaTag)
453 html.prepend(qt3RichTextHeader);
454 }
455
457// dumpHtml();
458}
459
461{
462 cursor.beginEditBlock();
463 hasBlock = true;
464 forceBlockMerging = false;
465 compressNextWhitespace = RemoveWhiteSpace;
466 blockTagClosed = false;
467 for (currentNodeIdx = 0; currentNodeIdx < count(); ++currentNodeIdx) {
468 currentNode = &at(currentNodeIdx);
470
471 /*
472 * process each node in three stages:
473 * 1) check if the hierarchy changed and we therefore passed the
474 * equivalent of a closing tag -> we may need to finish off
475 * some structures like tables
476 *
477 * 2) check if the current node is a special node like a
478 * <table>, <ul> or <img> tag that requires special processing
479 *
480 * 3) if the node should result in a QTextBlock create one and
481 * finally insert text that may be attached to the node
482 */
483
484 /* emit 'closing' table blocks or adjust current indent level
485 * if we
486 * 1) are beyond the first node
487 * 2) the current node not being a child of the previous node
488 * means there was a tag closing in the input html
489 */
490 if (currentNodeIdx > 0 && (currentNode->parent != currentNodeIdx - 1)) {
491 const bool lastBlockTagClosed = closeTag();
492 blockTagClosed = blockTagClosed || lastBlockTagClosed;
493 // visually collapse subsequent block tags, but if the element after the closed block tag
494 // is for example an inline element (!isBlock) we have to make sure we start a new paragraph by setting
495 // hasBlock to false.
496 if (blockTagClosed
497 && !currentNode->isBlock()
498 && currentNode->id != Html_unknown)
499 {
500 hasBlock = false;
501 } else if (blockTagClosed && hasBlock) {
502 // when collapsing subsequent block tags we need to clear the block format
503 QTextBlockFormat blockFormat = currentNode->blockFormat;
504 blockFormat.setIndent(indent);
505
506 QTextBlockFormat oldFormat = cursor.blockFormat();
507 if (oldFormat.hasProperty(QTextFormat::PageBreakPolicy)) {
508 QTextFormat::PageBreakFlags pageBreak = oldFormat.pageBreakPolicy();
509 if (pageBreak == QTextFormat::PageBreak_AlwaysAfter)
510 /* We remove an empty paragrah that requested a page break after.
511 moving that request to the next paragraph means we also need to make
512 that a pagebreak before to keep the same visual appearance.
513 */
515 blockFormat.setPageBreakPolicy(pageBreak);
516 }
517
518 cursor.setBlockFormat(blockFormat);
519 }
520 }
521
522 if (currentNode->displayMode == QTextHtmlElement::DisplayNone) {
523 if (currentNode->id == Html_title)
525 // ignore explicitly 'invisible' elements
526 continue;
527 }
528
529 if (processSpecialNodes() == ContinueWithNextNode)
530 continue;
531
532 // make sure there's a block for 'Blah' after <ul><li>foo</ul>Blah
533 if (blockTagClosed
534 && !hasBlock
535 && !currentNode->isBlock()
536 && !currentNode->text.isEmpty() && !currentNode->hasOnlyWhitespace()
537 && currentNode->displayMode == QTextHtmlElement::DisplayInline) {
538
539 QTextBlockFormat block = currentNode->blockFormat;
540 block.setIndent(indent);
541
542 appendBlock(block, currentNode->charFormat);
543
544 blockTagClosed = false;
545 hasBlock = true;
546 }
547
548 if (currentNode->isBlock()) {
549 QTextHtmlImporter::ProcessNodeResult result = processBlockNode();
550 if (result == ContinueWithNextNode) {
551 continue;
552 } else if (result == ContinueWithNextSibling) {
553 currentNodeIdx += currentNode->children.size();
554 continue;
555 }
556 }
557
558 if (currentNode->charFormat.isAnchor()) {
559 const auto names = currentNode->charFormat.anchorNames();
560 if (!names.isEmpty())
561 namedAnchors.append(names.constFirst());
562 }
563
564 if (appendNodeText())
565 hasBlock = false; // if we actually appended text then we don't
566 // have an empty block anymore
567 }
568
569 cursor.endEditBlock();
570}
571
572bool QTextHtmlImporter::appendNodeText()
573{
574 const int initialCursorPosition = cursor.position();
575 QTextCharFormat format = currentNode->charFormat;
576
578 compressNextWhitespace = PreserveWhiteSpace;
579
580 const QString text = currentNode->text;
581
582 QString textToInsert;
583 textToInsert.reserve(text.size());
584
585 for (QChar ch : text) {
586 if (ch.isSpace()
587 && ch != QChar::Nbsp
588 && ch != QChar::ParagraphSeparator) {
589
590 if (wsm == QTextHtmlParserNode::WhiteSpacePreLine && (ch == u'\n' || ch == u'\r'))
591 compressNextWhitespace = PreserveWhiteSpace;
592
593 if (compressNextWhitespace == CollapseWhiteSpace)
594 compressNextWhitespace = RemoveWhiteSpace; // allow this one, and remove the ones coming next.
595 else if (compressNextWhitespace == RemoveWhiteSpace)
596 continue;
597
599 || textEditMode
600 ) {
601 if (ch == u'\n') {
602 if (textEditMode)
603 continue;
604 } else if (ch == u'\r') {
605 continue;
606 }
607 } else if (wsm != QTextHtmlParserNode::WhiteSpacePreWrap) {
608 compressNextWhitespace = RemoveWhiteSpace;
609 if (wsm == QTextHtmlParserNode::WhiteSpacePreLine && (ch == u'\n' || ch == u'\r'))
610 { }
612 ch = QChar::Nbsp;
613 else
614 ch = u' ';
615 }
616 } else {
617 compressNextWhitespace = PreserveWhiteSpace;
618 }
619
620 if (ch == u'\n'
621 || ch == QChar::ParagraphSeparator) {
622
623 if (!textToInsert.isEmpty()) {
624 if (wsm == QTextHtmlParserNode::WhiteSpacePreLine && textToInsert.at(textToInsert.size() - 1) == u' ')
625 textToInsert = textToInsert.chopped(1);
626 cursor.insertText(textToInsert, format);
627 textToInsert.clear();
628 }
629
631
632 if (fmt.hasProperty(QTextFormat::BlockBottomMargin)) {
633 QTextBlockFormat tmp = fmt;
635 cursor.setBlockFormat(tmp);
636 }
637
638 fmt.clearProperty(QTextFormat::BlockTopMargin);
639 appendBlock(fmt, cursor.charFormat());
640 } else {
641 if (!namedAnchors.isEmpty()) {
642 if (!textToInsert.isEmpty()) {
643 cursor.insertText(textToInsert, format);
644 textToInsert.clear();
645 }
646
647 format.setAnchor(true);
648 format.setAnchorNames(namedAnchors);
649 cursor.insertText(ch, format);
650 namedAnchors.clear();
651 format.clearProperty(QTextFormat::IsAnchor);
652 format.clearProperty(QTextFormat::AnchorName);
653 } else {
654 textToInsert += ch;
655 }
656 }
657 }
658
659 if (!textToInsert.isEmpty()) {
660 cursor.insertText(textToInsert, format);
661 }
662
663 return cursor.position() != initialCursorPosition;
664}
665
666QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processSpecialNodes()
667{
668 switch (currentNode->id) {
669 case Html_body:
670 if (currentNode->charFormat.background().style() != Qt::NoBrush) {
672 fmt.setBackground(currentNode->charFormat.background());
674 const_cast<QTextHtmlParserNode *>(currentNode)->charFormat.clearProperty(QTextFormat::BackgroundBrush);
675 }
676 compressNextWhitespace = RemoveWhiteSpace;
677 break;
678
679 case Html_ol:
680 case Html_ul: {
681 QTextListFormat::Style style = currentNode->listStyle;
682
683 if (currentNode->id == Html_ul && !currentNode->hasOwnListStyle && currentNode->parent) {
684 const QTextHtmlParserNode *n = &at(currentNode->parent);
685 while (n) {
686 if (n->id == Html_ul) {
687 style = nextListStyle(currentNode->listStyle);
688 }
689 if (n->parent)
690 n = &at(n->parent);
691 else
692 n = nullptr;
693 }
694 }
695
696 QTextListFormat listFmt;
697 listFmt.setStyle(style);
698 if (!currentNode->textListNumberPrefix.isNull())
699 listFmt.setNumberPrefix(currentNode->textListNumberPrefix);
700 if (!currentNode->textListNumberSuffix.isNull())
701 listFmt.setNumberSuffix(currentNode->textListNumberSuffix);
702 if (currentNode->listStart != 1)
703 listFmt.setStart(currentNode->listStart);
704
705 ++indent;
706 if (currentNode->hasCssListIndent)
707 listFmt.setIndent(currentNode->cssListIndent);
708 else
709 listFmt.setIndent(indent);
710
711 List l;
712 l.format = listFmt;
713 l.listNode = currentNodeIdx;
714 lists.append(l);
715 compressNextWhitespace = RemoveWhiteSpace;
716
717 // broken html: <ul>Text here<li>Foo
718 const QString simpl = currentNode->text.simplified();
719 if (simpl.isEmpty() || simpl.at(0).isSpace())
720 return ContinueWithNextNode;
721 break;
722 }
723
724 case Html_table: {
725 Table t = scanTable(currentNodeIdx);
726 tables.append(t);
727 hasBlock = false;
728 compressNextWhitespace = RemoveWhiteSpace;
729 return ContinueWithNextNode;
730 }
731
732 case Html_tr:
733 return ContinueWithNextNode;
734
735 case Html_img: {
737 fmt.setName(currentNode->imageName);
738 if (!currentNode->text.isEmpty())
739 fmt.setProperty(QTextFormat::ImageTitle, currentNode->text);
740 if (!currentNode->imageAlt.isEmpty())
741 fmt.setProperty(QTextFormat::ImageAltText, currentNode->imageAlt);
742
743 fmt.merge(currentNode->charFormat);
744
745 if (currentNode->imageWidth != -1)
746 fmt.setWidth(currentNode->imageWidth);
747 if (currentNode->imageHeight != -1)
748 fmt.setHeight(currentNode->imageHeight);
749
750 cursor.insertImage(fmt, QTextFrameFormat::Position(currentNode->cssFloat));
751
753 cursor.mergeCharFormat(currentNode->charFormat);
755 compressNextWhitespace = CollapseWhiteSpace;
756
757 hasBlock = false;
758 return ContinueWithNextNode;
759 }
760
761 case Html_hr: {
762 QTextBlockFormat blockFormat = currentNode->blockFormat;
763 blockFormat.setTopMargin(topMargin(currentNodeIdx));
764 blockFormat.setBottomMargin(bottomMargin(currentNodeIdx));
766 if (hasBlock && importMode == ImportToDocument)
767 cursor.mergeBlockFormat(blockFormat);
768 else
769 appendBlock(blockFormat);
770 hasBlock = false;
771 compressNextWhitespace = RemoveWhiteSpace;
772 return ContinueWithNextNode;
773 }
774
775 case Html_h1:
776 headingLevel = 1;
777 break;
778 case Html_h2:
779 headingLevel = 2;
780 break;
781 case Html_h3:
782 headingLevel = 3;
783 break;
784 case Html_h4:
785 headingLevel = 4;
786 break;
787 case Html_h5:
788 headingLevel = 5;
789 break;
790 case Html_h6:
791 headingLevel = 6;
792 break;
793
794 default: break;
795 }
796
797 return ContinueWithCurrentNode;
798}
799
800// returns true if a block tag was closed
801bool QTextHtmlImporter::closeTag()
802{
803 const QTextHtmlParserNode *closedNode = &at(currentNodeIdx - 1);
804 const int endDepth = depth(currentNodeIdx) - 1;
805 int depth = this->depth(currentNodeIdx - 1);
806 bool blockTagClosed = false;
807
808 while (depth > endDepth) {
809 Table *t = nullptr;
810 if (!tables.isEmpty())
811 t = &tables.last();
812
813 switch (closedNode->id) {
814 case Html_tr:
815 if (t && !t->isTextFrame) {
816 ++t->currentRow;
817
818 // for broken html with rowspans but missing tr tags
819 while (!t->currentCell.atEnd() && t->currentCell.row < t->currentRow)
820 ++t->currentCell;
821 }
822
823 blockTagClosed = true;
824 break;
825
826 case Html_table:
827 if (!t)
828 break;
829 indent = t->lastIndent;
830
831 tables.resize(tables.size() - 1);
832 t = nullptr;
833
834 if (tables.isEmpty()) {
835 cursor = doc->rootFrame()->lastCursorPosition();
836 } else {
837 t = &tables.last();
838 if (t->isTextFrame)
839 cursor = t->frame->lastCursorPosition();
840 else if (!t->currentCell.atEnd())
841 cursor = t->currentCell.cell().lastCursorPosition();
842 }
843
844 // we don't need an extra block after tables, so we don't
845 // claim to have closed one for the creation of a new one
846 // in import()
847 blockTagClosed = false;
848 compressNextWhitespace = RemoveWhiteSpace;
849 break;
850
851 case Html_th:
852 case Html_td:
853 if (t && !t->isTextFrame)
854 ++t->currentCell;
855 blockTagClosed = true;
856 compressNextWhitespace = RemoveWhiteSpace;
857 break;
858
859 case Html_ol:
860 case Html_ul:
861 if (lists.isEmpty())
862 break;
863 lists.resize(lists.size() - 1);
864 --indent;
865 blockTagClosed = true;
866 break;
867
868 case Html_br:
869 compressNextWhitespace = RemoveWhiteSpace;
870 break;
871
872 case Html_div:
873 if (cursor.position() > 0) {
874 const QChar curChar = cursor.document()->characterAt(cursor.position() - 1);
875 if (!closedNode->children.isEmpty() && curChar != QChar::LineSeparator) {
876 blockTagClosed = true;
877 }
878 }
879 break;
880 case Html_h1:
881 case Html_h2:
882 case Html_h3:
883 case Html_h4:
884 case Html_h5:
885 case Html_h6:
886 headingLevel = 0;
887 blockTagClosed = true;
888 break;
889 default:
890 if (closedNode->isBlock())
891 blockTagClosed = true;
892 break;
893 }
894
895 closedNode = &at(closedNode->parent);
896 --depth;
897 }
898
899 return blockTagClosed;
900}
901
902QTextHtmlImporter::Table QTextHtmlImporter::scanTable(int tableNodeIdx)
903{
904 Table table;
905 table.columns = 0;
906
907 QList<QTextLength> columnWidths;
908
909 int tableHeaderRowCount = 0;
910 QList<int> rowNodes;
911 rowNodes.reserve(at(tableNodeIdx).children.size());
912 for (int row : at(tableNodeIdx).children) {
913 switch (at(row).id) {
914 case Html_tr:
915 rowNodes += row;
916 break;
917 case Html_thead:
918 case Html_tbody:
919 case Html_tfoot:
920 for (int potentialRow : at(row).children) {
921 if (at(potentialRow).id == Html_tr) {
922 rowNodes += potentialRow;
923 if (at(row).id == Html_thead)
924 ++tableHeaderRowCount;
925 }
926 }
927 break;
928 default: break;
929 }
930 }
931
932 QList<RowColSpanInfo> rowColSpans;
933 QList<RowColSpanInfo> rowColSpanForColumn;
934
935 int effectiveRow = 0;
936 for (int row : std::as_const(rowNodes)) {
937 int colsInRow = 0;
938
939 for (int cell : at(row).children) {
940 if (at(cell).isTableCell()) {
941 // skip all columns with spans from previous rows
942 while (colsInRow < rowColSpanForColumn.size()) {
943 const RowColSpanInfo &spanInfo = rowColSpanForColumn.at(colsInRow);
944
945 if (spanInfo.row + spanInfo.rowSpan > effectiveRow) {
946 Q_ASSERT(spanInfo.col == colsInRow);
947 colsInRow += spanInfo.colSpan;
948 } else
949 break;
950 }
951
952 const QTextHtmlParserNode &c = at(cell);
953 const int currentColumn = colsInRow;
954 colsInRow += c.tableCellColSpan;
955
956 RowColSpanInfo spanInfo;
957 spanInfo.row = effectiveRow;
958 spanInfo.col = currentColumn;
959 spanInfo.colSpan = c.tableCellColSpan;
960 spanInfo.rowSpan = c.tableCellRowSpan;
961 if (spanInfo.colSpan > 1 || spanInfo.rowSpan > 1)
962 rowColSpans.append(spanInfo);
963
964 columnWidths.resize(qMax(columnWidths.size(), colsInRow));
965 rowColSpanForColumn.resize(columnWidths.size());
966 for (int i = currentColumn; i < currentColumn + c.tableCellColSpan; ++i) {
967 if (columnWidths.at(i).type() == QTextLength::VariableLength) {
968 QTextLength w = c.width;
969 if (c.tableCellColSpan > 1 && w.type() != QTextLength::VariableLength)
970 w = QTextLength(w.type(), w.value(100.) / c.tableCellColSpan);
971 columnWidths[i] = w;
972 }
973 rowColSpanForColumn[i] = spanInfo;
974 }
975 }
976 }
977
978 table.columns = qMax(table.columns, colsInRow);
979
980 ++effectiveRow;
981 }
982 table.rows = effectiveRow;
983
984 table.lastIndent = indent;
985 indent = 0;
986
987 if (table.rows == 0 || table.columns == 0)
988 return table;
989
991 const QTextHtmlParserNode &node = at(tableNodeIdx);
992
993 if (!node.isTextFrame) {
994 QTextTableFormat tableFmt;
995 tableFmt.setCellSpacing(node.tableCellSpacing);
996 tableFmt.setCellPadding(node.tableCellPadding);
998 tableFmt.setAlignment(node.blockFormat.alignment());
999 tableFmt.setColumns(table.columns);
1000 tableFmt.setColumnWidthConstraints(columnWidths);
1001 tableFmt.setHeaderRowCount(tableHeaderRowCount);
1002 tableFmt.setBorderCollapse(node.borderCollapse);
1003 fmt = tableFmt;
1004 }
1005
1006 fmt.setTopMargin(topMargin(tableNodeIdx));
1007 fmt.setBottomMargin(bottomMargin(tableNodeIdx));
1008 fmt.setLeftMargin(leftMargin(tableNodeIdx)
1009 + table.lastIndent * 40 // ##### not a good emulation
1010 );
1011 fmt.setRightMargin(rightMargin(tableNodeIdx));
1012
1013 // compatibility
1014 if (qFuzzyCompare(fmt.leftMargin(), fmt.rightMargin())
1015 && qFuzzyCompare(fmt.leftMargin(), fmt.topMargin())
1016 && qFuzzyCompare(fmt.leftMargin(), fmt.bottomMargin()))
1017 fmt.setProperty(QTextFormat::FrameMargin, fmt.leftMargin());
1018
1019 fmt.setBorderStyle(node.borderStyle);
1020 fmt.setBorderBrush(node.borderBrush);
1021 fmt.setBorder(node.tableBorder);
1022 fmt.setWidth(node.width);
1023 fmt.setHeight(node.height);
1025 fmt.setPageBreakPolicy(node.blockFormat.pageBreakPolicy());
1026
1028 fmt.setLayoutDirection(node.blockFormat.layoutDirection());
1029 if (node.charFormat.background().style() != Qt::NoBrush)
1030 fmt.setBackground(node.charFormat.background());
1031 fmt.setPosition(QTextFrameFormat::Position(node.cssFloat));
1032
1033 if (node.isTextFrame) {
1034 if (node.isRootFrame) {
1035 table.frame = cursor.currentFrame();
1036 table.frame->setFrameFormat(fmt);
1037 } else
1038 table.frame = cursor.insertFrame(fmt);
1039
1040 table.isTextFrame = true;
1041 } else {
1042 const int oldPos = cursor.position();
1043 QTextTable *textTable = cursor.insertTable(table.rows, table.columns, fmt.toTableFormat());
1044 table.frame = textTable;
1045
1046 for (int i = 0; i < rowColSpans.size(); ++i) {
1047 const RowColSpanInfo &nfo = rowColSpans.at(i);
1048 textTable->mergeCells(nfo.row, nfo.col, nfo.rowSpan, nfo.colSpan);
1049 }
1050
1051 table.currentCell = TableCellIterator(textTable);
1052 cursor.setPosition(oldPos); // restore for caption support which needs to be inserted right before the table
1053 }
1054 return table;
1055}
1056
1057QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode()
1058{
1059 QTextBlockFormat block;
1060 QTextCharFormat charFmt;
1061 bool modifiedBlockFormat = true;
1062 bool modifiedCharFormat = true;
1063
1064 if (currentNode->isTableCell() && !tables.isEmpty()) {
1065 Table &t = tables.last();
1066 if (!t.isTextFrame && !t.currentCell.atEnd()) {
1067 QTextTableCell cell = t.currentCell.cell();
1068 if (cell.isValid()) {
1070 if (topPadding(currentNodeIdx) >= 0)
1071 fmt.setTopPadding(topPadding(currentNodeIdx));
1072 if (bottomPadding(currentNodeIdx) >= 0)
1073 fmt.setBottomPadding(bottomPadding(currentNodeIdx));
1074 if (leftPadding(currentNodeIdx) >= 0)
1075 fmt.setLeftPadding(leftPadding(currentNodeIdx));
1076 if (rightPadding(currentNodeIdx) >= 0)
1077 fmt.setRightPadding(rightPadding(currentNodeIdx));
1078#ifndef QT_NO_CSSPARSER
1079 if (tableCellBorder(currentNodeIdx, QCss::TopEdge) > 0)
1080 fmt.setTopBorder(tableCellBorder(currentNodeIdx, QCss::TopEdge));
1081 if (tableCellBorder(currentNodeIdx, QCss::RightEdge) > 0)
1082 fmt.setRightBorder(tableCellBorder(currentNodeIdx, QCss::RightEdge));
1083 if (tableCellBorder(currentNodeIdx, QCss::BottomEdge) > 0)
1084 fmt.setBottomBorder(tableCellBorder(currentNodeIdx, QCss::BottomEdge));
1085 if (tableCellBorder(currentNodeIdx, QCss::LeftEdge) > 0)
1086 fmt.setLeftBorder(tableCellBorder(currentNodeIdx, QCss::LeftEdge));
1088 fmt.setTopBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::TopEdge));
1090 fmt.setRightBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::RightEdge));
1092 fmt.setBottomBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge));
1094 fmt.setLeftBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge));
1095 if (tableCellBorderBrush(currentNodeIdx, QCss::TopEdge) != Qt::NoBrush)
1096 fmt.setTopBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::TopEdge));
1097 if (tableCellBorderBrush(currentNodeIdx, QCss::RightEdge) != Qt::NoBrush)
1098 fmt.setRightBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::RightEdge));
1099 if (tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge) != Qt::NoBrush)
1100 fmt.setBottomBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge));
1101 if (tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge) != Qt::NoBrush)
1102 fmt.setLeftBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge));
1103#endif
1104
1105 cell.setFormat(fmt);
1106
1107 cursor.setPosition(cell.firstPosition());
1108 }
1109 }
1110 hasBlock = true;
1111 compressNextWhitespace = RemoveWhiteSpace;
1112
1113 if (currentNode->charFormat.background().style() != Qt::NoBrush) {
1114 charFmt.setBackground(currentNode->charFormat.background());
1115 cursor.mergeBlockCharFormat(charFmt);
1116 }
1117 }
1118
1119 if (hasBlock) {
1120 block = cursor.blockFormat();
1121 charFmt = cursor.blockCharFormat();
1122 modifiedBlockFormat = false;
1123 modifiedCharFormat = false;
1124 }
1125
1126 // collapse
1127 {
1128 qreal tm = qreal(topMargin(currentNodeIdx));
1129 if (tm > block.topMargin()) {
1130 block.setTopMargin(tm);
1131 modifiedBlockFormat = true;
1132 }
1133 }
1134
1135 int bottomMargin = this->bottomMargin(currentNodeIdx);
1136
1137 // for list items we may want to collapse with the bottom margin of the
1138 // list.
1139 const QTextHtmlParserNode *parentNode = currentNode->parent ? &at(currentNode->parent) : nullptr;
1140 if ((currentNode->id == Html_li || currentNode->id == Html_dt || currentNode->id == Html_dd)
1141 && parentNode
1142 && (parentNode->isListStart() || parentNode->id == Html_dl)
1143 && (parentNode->children.last() == currentNodeIdx)) {
1144 bottomMargin = qMax(bottomMargin, this->bottomMargin(currentNode->parent));
1145 }
1146
1147 if (block.bottomMargin() != bottomMargin) {
1149 modifiedBlockFormat = true;
1150 }
1151
1152 {
1153 const qreal lm = leftMargin(currentNodeIdx);
1154 const qreal rm = rightMargin(currentNodeIdx);
1155
1156 if (block.leftMargin() != lm) {
1157 block.setLeftMargin(lm);
1158 modifiedBlockFormat = true;
1159 }
1160 if (block.rightMargin() != rm) {
1161 block.setRightMargin(rm);
1162 modifiedBlockFormat = true;
1163 }
1164 }
1165
1166 if (currentNode->id != Html_li
1167 && indent != 0
1168 && (lists.isEmpty()
1169 || !hasBlock
1170 || !lists.constLast().list
1171 || lists.constLast().list->itemNumber(cursor.block()) == -1
1172 )
1173 ) {
1174 block.setIndent(indent);
1175 modifiedBlockFormat = true;
1176 }
1177
1178 if (headingLevel) {
1179 block.setHeadingLevel(headingLevel);
1180 modifiedBlockFormat = true;
1181 }
1182
1183 if (currentNode->blockFormat.propertyCount() > 0) {
1184 modifiedBlockFormat = true;
1185 block.merge(currentNode->blockFormat);
1186 }
1187
1188 if (currentNode->charFormat.propertyCount() > 0) {
1189 modifiedCharFormat = true;
1190 charFmt.merge(currentNode->charFormat);
1191 }
1192
1193 // ####################
1194 // block.setFloatPosition(node->cssFloat);
1195
1198 block.setNonBreakableLines(true);
1199 modifiedBlockFormat = true;
1200 }
1201
1202 if (currentNode->charFormat.background().style() != Qt::NoBrush && !currentNode->isTableCell()) {
1203 block.setBackground(currentNode->charFormat.background());
1204 modifiedBlockFormat = true;
1205 }
1206
1207 if (hasBlock && (!currentNode->isEmptyParagraph || forceBlockMerging)) {
1208 if (modifiedBlockFormat)
1209 cursor.setBlockFormat(block);
1210 if (modifiedCharFormat)
1211 cursor.setBlockCharFormat(charFmt);
1212 } else {
1213 if (currentNodeIdx == 1 && cursor.position() == 0 && currentNode->isEmptyParagraph) {
1214 cursor.setBlockFormat(block);
1215 cursor.setBlockCharFormat(charFmt);
1216 } else {
1217 appendBlock(block, charFmt);
1218 }
1219 }
1220
1221 if (currentNode->userState != -1)
1222 cursor.block().setUserState(currentNode->userState);
1223
1224 if (currentNode->id == Html_li && !lists.isEmpty()) {
1225 List &l = lists.last();
1226 if (l.list) {
1227 l.list->add(cursor.block());
1228 } else {
1229 l.list = cursor.createList(l.format);
1230 const qreal listTopMargin = topMargin(l.listNode);
1231 if (listTopMargin > block.topMargin()) {
1232 block.setTopMargin(listTopMargin);
1233 cursor.mergeBlockFormat(block);
1234 }
1235 }
1236 if (hasBlock) {
1238 fmt.setIndent(currentNode->blockFormat.indent());
1239 cursor.mergeBlockFormat(fmt);
1240 }
1241 }
1242
1243 forceBlockMerging = false;
1244 if (currentNode->id == Html_body || currentNode->id == Html_html)
1245 forceBlockMerging = true;
1246
1247 if (currentNode->isEmptyParagraph) {
1248 hasBlock = false;
1249 return ContinueWithNextSibling;
1250 }
1251
1252 hasBlock = true;
1253 blockTagClosed = false;
1254 return ContinueWithCurrentNode;
1255}
1256
1257void QTextHtmlImporter::appendBlock(const QTextBlockFormat &format, QTextCharFormat charFmt)
1258{
1259 if (!namedAnchors.isEmpty()) {
1260 charFmt.setAnchor(true);
1261 charFmt.setAnchorNames(namedAnchors);
1262 namedAnchors.clear();
1263 }
1264
1265 cursor.insertBlock(format, charFmt);
1266
1268 compressNextWhitespace = RemoveWhiteSpace;
1269}
1270
1285{
1288
1289 QTextHtmlImporter importer(res.d->doc, html, QTextHtmlImporter::ImportToFragment, resourceProvider);
1290 importer.import();
1291 return res;
1292}
1293
1294#endif // QT_NO_TEXTHTMLPARSER
1295
1296#if QT_CONFIG(textmarkdownreader)
1297
1311QTextDocumentFragment QTextDocumentFragment::fromMarkdown(const QString &markdown, QTextDocument::MarkdownFeatures features)
1312{
1315
1316 QTextMarkdownImporter(res.d->doc, features).import(markdown);
1317 return res;
1318}
1319
1320#endif // textmarkdownreader
1321
bool ref() noexcept
bool deref() noexcept
Qt::BrushStyle style() const
Returns the brush style.
Definition qbrush.h:120
\inmodule QtCore
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
T & last()
Definition qlist.h:648
void resize(qsizetype size)
Definition qlist.h:403
void append(parameter_type t)
Definition qlist.h:458
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
Definition qstring.h:1325
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1246
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:994
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QString simplified() const &
Definition qstring.h:451
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1369
QString & prepend(QChar c)
Definition qstring.h:478
qreal bottomMargin() const
Returns the paragraph's bottom margin.
qreal topMargin() const
Returns the paragraph's top margin.
void setLeftMargin(qreal margin)
Sets the paragraph's left margin.
Qt::Alignment alignment() const
Returns the paragraph's alignment.
void setPageBreakPolicy(PageBreakFlags flags)
void setBottomMargin(qreal margin)
Sets the paragraph's bottom margin.
PageBreakFlags pageBreakPolicy() const
void setNonBreakableLines(bool b)
If b is true, the lines in the paragraph are treated as non-breakable; otherwise they are breakable.
void setRightMargin(qreal margin)
Sets the paragraph's right margin.
void setIndent(int indent)
Sets the paragraph's indentation.
int indent() const
Returns the paragraph's indent.
qreal leftMargin() const
Returns the paragraph's left margin.
void setHeadingLevel(int alevel)
qreal rightMargin() const
Returns the paragraph's right margin.
void setTopMargin(qreal margin)
Sets the paragraph's top margin.
\reentrant
void setUserState(int state)
QTextBlockFormat blockFormat() const
Returns the QTextBlockFormat that describes block-specific properties.
int position() const
Returns the index of the block's first character within the document.
bool isAnchor() const
Returns true if the text is formatted as an anchor; otherwise returns false.
QStringList anchorNames() const
void setTableCellRowSpan(int tableCellRowSpan)
QTextCopyHelper(const QTextCursor &_source, const QTextCursor &_destination, bool forceCharFormat=false, const QTextCharFormat &fmt=QTextCharFormat())
QTextDocumentPrivate * priv
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
void setBlockCharFormat(const QTextCharFormat &format)
Sets the block char format of the current block (or all blocks that are contained in the selection) t...
QTextBlockFormat blockFormat() const
Returns the block format of the block the cursor is in.
QTextDocument * document() const
QTextCharFormat charFormat() const
Returns the format of the character immediately before the cursor position().
QTextBlock block() const
Returns the block that contains the cursor.
QTextCharFormat blockCharFormat() const
Returns the block character format of the block the cursor is in.
void beginEditBlock()
Indicates the start of a block of editing operations on the document that should appear as a single o...
void setPosition(int pos, MoveMode mode=MoveAnchor)
Moves the cursor to the absolute position in the document specified by pos using a MoveMode specified...
int selectionStart() const
Returns the start of the selection or position() if the cursor doesn't have a selection.
bool movePosition(MoveOperation op, MoveMode=MoveAnchor, int n=1)
Moves the cursor by performing the given operation n times, using the specified mode,...
void setBlockFormat(const QTextBlockFormat &format)
Sets the block format of the current block (or all blocks that are contained in the selection) to for...
void mergeBlockCharFormat(const QTextCharFormat &modifier)
Modifies the block char format of the current block (or all blocks that are contained in the selectio...
void mergeCharFormat(const QTextCharFormat &modifier)
Merges the cursor's current character format with the properties described by format modifier.
int selectionEnd() const
Returns the end of the selection or position() if the cursor doesn't have a selection.
void selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
If the selection spans over table cells, firstRow is populated with the number of the first row in th...
void insertText(const QString &text)
Inserts text at the current position, using the current character format.
void insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void insertBlock()
Inserts a new empty block at the cursor position() with the current blockFormat() and charFormat().
void endEditBlock()
Indicates the end of a block of editing operations on the document that should appear as a single ope...
void mergeBlockFormat(const QTextBlockFormat &modifier)
Modifies the block format of the current block (or all blocks that are contained in the selection) wi...
bool hasComplexSelection() const
Returns true if the cursor contains a selection that is not simply a range from selectionStart() to s...
QTextTable * insertTable(int rows, int cols, const QTextTableFormat &format)
Creates a new table with the given number of rows and columns in the specified format,...
QTextTable * currentTable() const
Returns a pointer to the current table if the cursor position() is inside a block that is part of a t...
QTextFrame * insertFrame(const QTextFrameFormat &format)
Inserts a frame with the given format at the current cursor position(), moves the cursor position() i...
int position() const
Returns the absolute position of the cursor within the document.
QTextFrame * currentFrame() const
Returns a pointer to the current frame.
QTextList * createList(const QTextListFormat &format)
Creates and returns a new list with the given format, and makes the current paragraph the cursor is i...
void insert(QTextCursor &cursor) const
QTextDocumentFragmentPrivate(const QTextCursor &cursor=QTextCursor())
QString toPlainText() const
This function returns the same as toRawText(), but will replace some unicode characters with ASCII al...
QTextDocumentFragment & operator=(const QTextDocumentFragment &rhs)
Assigns the other fragment to this fragment.
QTextDocumentFragment()
Constructs an empty QTextDocumentFragment.
bool isEmpty() const
Returns true if the fragment is empty; otherwise returns false.
static QTextDocumentFragment fromHtml(const QString &html, const QTextDocument *resourceProvider=nullptr)
~QTextDocumentFragment()
Destroys the document fragment.
static QTextDocumentFragment fromPlainText(const QString &plainText)
Returns a document fragment that contains the given plainText.
QString toRawText() const
Returns the document fragment's text as raw text (i.e.
QString buffer() const
static const QTextDocumentPrivate * get(const QTextDocument *document)
FragmentMap::ConstIterator FragmentIterator
\reentrant \inmodule QtGui
QString toRawText() const
Returns the raw text contained in the document without any formatting information.
QChar characterAt(int pos) const
void setUndoRedoEnabled(bool enable)
QString toPlainText() const
Returns the plain text contained in the document.
QTextFrame * rootFrame() const
Returns the document's root frame.
void setMetaInformation(MetaInformation info, const QString &)
Sets the document's meta information of the type specified by info to the given string.
int indexForFormat(const QTextFormat &f)
int createObjectIndex(const QTextFormat &f)
QTextFormat format(int idx) const
\reentrant
Definition qtextformat.h:90
QTextCharFormat toCharFormat() const
Returns this format as a character format.
QBrush background() const
Returns the brush used to paint the document's background.
QTextBlockFormat toBlockFormat() const
Returns this format as a block format.
Qt::LayoutDirection layoutDirection() const
Returns the document's layout direction.
@ BlockTrailingHorizontalRulerWidth
void setBackground(const QBrush &brush)
Sets the brush use to paint the document's background to the brush specified.
void setProperty(int propertyId, const QVariant &value)
Sets the property specified by the propertyId to the given value.
QTextTableCellFormat toTableCellFormat() const
int propertyCount() const
bool hasProperty(int propertyId) const
Returns true if the text format has a property with the given propertyId; otherwise returns false.
void setObjectIndex(int object)
Sets the format object's object index.
int type() const
Returns the type of this format.
void clearProperty(int propertyId)
Clears the value of the property given by propertyId.
void merge(const QTextFormat &other)
Merges the other format with this format; where there are conflicts the other format takes precedence...
@ PageBreak_AlwaysBefore
@ PageBreak_AlwaysAfter
Position
This enum describes how a frame is located relative to the surrounding text.
void setFrameFormat(const QTextFrameFormat &format)
Sets the frame's format.
QTextFrameFormat frameFormat() const
Returns the frame's format.
Definition qtextobject.h:89
QTextCursor lastCursorPosition() const
Returns the last cursor position inside the frame.
QString toHtml(ExportMode mode=ExportEntireDocument)
Returns the document in HTML format.
QTextHtmlImporter(QTextDocument *_doc, const QString &html, ImportMode mode, const QTextDocument *resourceProvider=nullptr)
QTextFrameFormat::BorderStyle tableCellBorderStyle(int i, int edge) const
QBrush tableCellBorderBrush(int i, int edge) const
qreal tableCellBorder(int i, int edge) const
int topMargin(int i) const
int topPadding(int i) const
int leftMargin(int i) const
int rightMargin(int i) const
int bottomPadding(int i) const
int leftPadding(int i) const
int bottomMargin(int i) const
const QTextDocument * resourceProvider
int rightPadding(int i) const
void setName(const QString &name)
Sets the name of the image.
\reentrant
Definition qtextformat.h:45
void setStyle(Style style)
Sets the list format's style.
Style
This enum describes the symbols used to decorate list items:
void import(const QString &markdown)
void setTopPadding(qreal padding)
\reentrant
Definition qtexttable.h:19
QTextCharFormat format() const
Returns the cell's character format.
int columnSpan() const
Returns the number of columns this cell spans.
int firstPosition() const
int row() const
Returns the number of the row in the table that contains this cell.
int rowSpan() const
Returns the number of rows this cell spans.
void setFormat(const QTextCharFormat &format)
int lastPosition() const
bool isValid() const
Returns true if this is a valid table cell; otherwise returns false.
Definition qtexttable.h:36
int column() const
Returns the number of the column in the table that contains this cell.
void clearColumnWidthConstraints()
Clears the column width constraints for the table.
void setColumns(int columns)
void setCellSpacing(qreal spacing)
Sets the cell spacing for the table.
\reentrant
Definition qtexttable.h:63
void mergeCells(int row, int col, int numRows, int numCols)
QString text
QCursor cursor
@ BottomEdge
@ RightEdge
Combined button and popup list for selecting options.
@ NoBrush
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
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
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
GLfloat GLfloat GLfloat w
[0]
GLboolean r
[2]
GLuint GLuint end
GLenum src
GLenum GLenum dst
GLint ref
GLfloat n
GLint GLsizei GLsizei GLenum format
GLuint res
const GLubyte * c
GLuint GLuint * names
GLdouble GLdouble t
Definition qopenglext.h:243
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLenum GLsizei void * table
GLuint * lists
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QTextBeginningOfFrame
#define QTextEndOfFrame
static QTextListFormat::Style nextListStyle(QTextListFormat::Style style)
@ Html_h2
@ Html_dl
@ Html_th
@ Html_dd
@ Html_tr
@ Html_tbody
@ Html_tfoot
@ Html_h4
@ Html_h5
@ Html_title
@ Html_table
@ Html_div
@ Html_ol
@ Html_ul
@ Html_br
@ Html_thead
@ Html_body
@ Html_unknown
@ Html_td
@ Html_hr
@ Html_li
@ Html_img
@ Html_html
@ Html_h6
@ Html_h1
@ Html_h3
@ Html_dt
double qreal
Definition qtypes.h:187
QVideoFrameFormat::PixelFormat fmt
QObject::connect nullptr
QAction * at
const QByteArray plainText
QTextListFormat::Style listStyle
QTextFrameFormat::BorderStyle borderStyle
QTextCharFormat charFormat
QTextHTMLElements id
QTextBlockFormat blockFormat