📄 qtextdocumentfragment.cpp
字号:
case Html_ol: case Html_ul: if (lists.isEmpty()) break; lists.resize(lists.size() - 1); --indent; blockTagClosed = true; break; case Html_br: compressNextWhitespace = true; break; case Html_div: if (closedNode->children.isEmpty()) break; // fall through default: if (closedNode->isBlock()) blockTagClosed = true; break; } closedNode = &at(closedNode->parent); --depth; } return blockTagClosed;}QTextHtmlImporter::Table QTextHtmlImporter::scanTable(int tableNodeIdx){ Table table; table.columns = 0; QVector<QTextLength> columnWidths; int tableHeaderRowCount = 0; QVector<int> rowNodes; rowNodes.reserve(at(tableNodeIdx).children.count()); foreach (int row, at(tableNodeIdx).children) switch (at(row).id) { case Html_tr: rowNodes += row; break; case Html_thead: case Html_tbody: case Html_tfoot: foreach (int potentialRow, at(row).children) if (at(potentialRow).id == Html_tr) { rowNodes += potentialRow; if (at(row).id == Html_thead) ++tableHeaderRowCount; } break; default: break; } QVector<RowColSpanInfo> rowColSpans; QVector<RowColSpanInfo> rowColSpanForColumn; int effectiveRow = 0; foreach (int row, rowNodes) { int colsInRow = 0; foreach (int cell, at(row).children) if (at(cell).isTableCell()) { // skip all columns with spans from previous rows while (colsInRow < rowColSpanForColumn.size()) { const RowColSpanInfo &spanInfo = rowColSpanForColumn[colsInRow]; if (spanInfo.row + spanInfo.rowSpan > effectiveRow) { Q_ASSERT(spanInfo.col == colsInRow); colsInRow += spanInfo.colSpan; } else break; } const QTextHtmlParserNode &c = at(cell); const int currentColumn = colsInRow; colsInRow += c.tableCellColSpan; RowColSpanInfo spanInfo; spanInfo.row = effectiveRow; spanInfo.col = currentColumn; spanInfo.colSpan = c.tableCellColSpan; spanInfo.rowSpan = c.tableCellRowSpan; if (spanInfo.colSpan > 1 || spanInfo.rowSpan > 1) rowColSpans.append(spanInfo); columnWidths.resize(qMax(columnWidths.count(), colsInRow)); rowColSpanForColumn.resize(columnWidths.size()); for (int i = currentColumn; i < currentColumn + c.tableCellColSpan; ++i) { if (columnWidths.at(i).type() == QTextLength::VariableLength) columnWidths[i] = c.width; rowColSpanForColumn[i] = spanInfo; } } table.columns = qMax(table.columns, colsInRow); ++effectiveRow; } table.rows = effectiveRow; table.lastIndent = indent; indent = 0; if (table.rows == 0 || table.columns == 0) return table; QTextFrameFormat fmt; const QTextHtmlParserNode &node = at(tableNodeIdx); if (!node.isTextFrame) { QTextTableFormat tableFmt; tableFmt.setCellSpacing(node.tableCellSpacing); tableFmt.setCellPadding(node.tableCellPadding); if (node.blockFormat.hasProperty(QTextFormat::BlockAlignment)) tableFmt.setAlignment(node.blockFormat.alignment()); tableFmt.setColumns(table.columns); tableFmt.setColumnWidthConstraints(columnWidths); tableFmt.setHeaderRowCount(tableHeaderRowCount); fmt = tableFmt; } fmt.setTopMargin(topMargin(tableNodeIdx)); fmt.setBottomMargin(bottomMargin(tableNodeIdx)); fmt.setLeftMargin(leftMargin(tableNodeIdx) + table.lastIndent * 40 // ##### not a good emulation ); fmt.setRightMargin(rightMargin(tableNodeIdx)); // compatibility if (qFuzzyCompare(fmt.leftMargin(), fmt.rightMargin()) && qFuzzyCompare(fmt.leftMargin(), fmt.topMargin()) && qFuzzyCompare(fmt.leftMargin(), fmt.bottomMargin())) fmt.setProperty(QTextFormat::FrameMargin, fmt.leftMargin()); fmt.setBorderStyle(node.borderStyle); fmt.setBorderBrush(node.borderBrush); fmt.setBorder(node.tableBorder); fmt.setWidth(node.width); fmt.setHeight(node.height); if (node.blockFormat.hasProperty(QTextFormat::PageBreakPolicy)) fmt.setPageBreakPolicy(node.blockFormat.pageBreakPolicy()); if (node.blockFormat.hasProperty(QTextFormat::LayoutDirection)) fmt.setLayoutDirection(node.blockFormat.layoutDirection()); if (node.charFormat.background().style() != Qt::NoBrush) fmt.setBackground(node.charFormat.background()); fmt.setPosition(QTextFrameFormat::Position(node.cssFloat)); if (node.isTextFrame) { if (node.isRootFrame) { table.frame = cursor.currentFrame(); table.frame->setFrameFormat(fmt); } else table.frame = cursor.insertFrame(fmt); table.isTextFrame = true; } else { const int oldPos = cursor.position(); QTextTable *textTable = cursor.insertTable(table.rows, table.columns, fmt.toTableFormat()); table.frame = textTable; for (int i = 0; i < rowColSpans.count(); ++i) { const RowColSpanInfo &nfo = rowColSpans.at(i); textTable->mergeCells(nfo.row, nfo.col, nfo.rowSpan, nfo.colSpan); } table.currentCell = TableCellIterator(textTable); cursor.setPosition(oldPos); // restore for caption support which needs to be inserted right before the table } return table;}QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode(){ QTextBlockFormat block; QTextCharFormat charFmt; bool modifiedBlockFormat = true; bool modifiedCharFormat = true; if (currentNode->isTableCell() && !tables.isEmpty()) { Table &t = tables.last(); if (!t.isTextFrame && !t.currentCell.atEnd()) { const QTextTableCell cell = t.currentCell.cell(); if (cell.isValid()) cursor.setPosition(cell.firstPosition()); } hasBlock = true; compressNextWhitespace = true; if (currentNode->charFormat.background().style() != Qt::NoBrush) { charFmt.setBackground(currentNode->charFormat.background()); cursor.mergeBlockCharFormat(charFmt); } } if (hasBlock) { block = cursor.blockFormat(); charFmt = cursor.blockCharFormat(); modifiedBlockFormat = false; modifiedCharFormat = false; } // collapse { qreal tm = qreal(topMargin(currentNodeIdx)); if (tm > block.topMargin()) { block.setTopMargin(tm); modifiedBlockFormat = true; } } int bottomMargin = this->bottomMargin(currentNodeIdx); // for list items we may want to collapse with the bottom margin of the // list. const QTextHtmlParserNode *parentNode = currentNode->parent ? &at(currentNode->parent) : 0; if ((currentNode->id == Html_li || currentNode->id == Html_dt || currentNode->id == Html_dd) && parentNode && (parentNode->isListStart() || parentNode->id == Html_dl) && (parentNode->children.last() == currentNodeIdx)) { bottomMargin = qMax(bottomMargin, this->bottomMargin(currentNode->parent)); } if (block.bottomMargin() != bottomMargin) { block.setBottomMargin(bottomMargin); modifiedBlockFormat = true; } { const qreal lm = leftMargin(currentNodeIdx); const qreal rm = rightMargin(currentNodeIdx); if (block.leftMargin() != lm) { block.setLeftMargin(lm); modifiedBlockFormat = true; } if (block.rightMargin() != rm) { block.setRightMargin(rm); modifiedBlockFormat = true; } } if (currentNode->id != Html_li && indent != 0 && (lists.isEmpty() || !hasBlock || !lists.last().list || lists.last().list->itemNumber(cursor.block()) == -1 ) ) { block.setIndent(indent); modifiedBlockFormat = true; } if (currentNode->blockFormat.propertyCount() > 0) { modifiedBlockFormat = true; block.merge(currentNode->blockFormat); } if (currentNode->charFormat.propertyCount() > 0) { modifiedCharFormat = true; charFmt.merge(currentNode->charFormat); } // #################### // block.setFloatPosition(node->cssFloat); if (wsm == QTextHtmlParserNode::WhiteSpacePre) { block.setNonBreakableLines(true); modifiedBlockFormat = true; } if (currentNode->charFormat.background().style() != Qt::NoBrush && !currentNode->isTableCell()) { block.setBackground(currentNode->charFormat.background()); modifiedBlockFormat = true; } if (hasBlock && (!currentNode->isEmptyParagraph || forceBlockMerging)) { if (modifiedBlockFormat) cursor.setBlockFormat(block); if (modifiedCharFormat) cursor.setBlockCharFormat(charFmt); } else { if (currentNodeIdx == 1 && cursor.position() == 0 && currentNode->isEmptyParagraph) { cursor.setBlockFormat(block); cursor.setBlockCharFormat(charFmt); } else { appendBlock(block, charFmt); } } if (currentNode->userState != -1) cursor.block().setUserState(currentNode->userState); if (currentNode->id == Html_li && !lists.isEmpty()) { List &l = lists.last(); if (l.list) { l.list->add(cursor.block()); } else { l.list = cursor.createList(l.format); const qreal listTopMargin = topMargin(l.listNode); if (listTopMargin > block.topMargin()) { block.setTopMargin(listTopMargin); cursor.mergeBlockFormat(block); } } if (hasBlock) { QTextBlockFormat fmt; fmt.setIndent(0); cursor.mergeBlockFormat(fmt); } } forceBlockMerging = false; if (currentNode->id == Html_body || currentNode->id == Html_html) forceBlockMerging = true; if (currentNode->isEmptyParagraph) { hasBlock = false; return ContinueWithNextNode; } hasBlock = true; blockTagClosed = false; return ContinueWithCurrentNode;}void QTextHtmlImporter::appendBlock(const QTextBlockFormat &format, QTextCharFormat charFmt){ if (!namedAnchors.isEmpty()) { charFmt.setAnchor(true); charFmt.setAnchorNames(namedAnchors); namedAnchors.clear(); } cursor.insertBlock(format, charFmt); if (!isPreservingWhitespaceMode(wsm)) compressNextWhitespace = true;}/*! \fn QTextDocumentFragment QTextDocumentFragment::fromHtml(const QString &text) Returns a QTextDocumentFragment based on the arbitrary piece of HTML in the given \a text. The formatting is preserved as much as possible; for example, "<b>bold</b>" will become a document fragment with the text "bold" with a bold character format.*/QTextDocumentFragment QTextDocumentFragment::fromHtml(const QString &html){ return fromHtml(html, 0);}/*! \fn QTextDocumentFragment QTextDocumentFragment::fromHtml(const QString &text, const QTextDocument *resourceProvider) \since 4.2 Returns a QTextDocumentFragment based on the arbitrary piece of HTML in the given \a text. The formatting is preserved as much as possible; for example, "<b>bold</b>" will become a document fragment with the text "bold" with a bold character format. If the provided HTML contains references to external resources such as imported style sheets, then they will be loaded through the \a resourceProvider.*/QTextDocumentFragment QTextDocumentFragment::fromHtml(const QString &html, const QTextDocument *resourceProvider){ QTextDocumentFragment res; res.d = new QTextDocumentFragmentPrivate; QTextHtmlImporter importer(res.d->doc, html, QTextHtmlImporter::ImportToFragment, resourceProvider); importer.import(); return res;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -