void KoTextWriter::saveParagraph(const QTextBlock &block, int from, int to) { QString changeName = QString(); QTextBlockFormat blockFormat = block.blockFormat(); int outlineLevel = blockFormat.intProperty(KoParagraphStyle::OutlineLevel); if (outlineLevel > 0) { d->writer->startElement("text:h", false); d->writer->addAttribute("text:outline-level", outlineLevel); } else d->writer->startElement("text:p", false); QString styleName = saveParagraphStyle(block); if (!styleName.isEmpty()) d->writer->addAttribute("text:style-name", styleName); // Write the fragments and their formats QTextCursor cursor(block); QTextCharFormat blockCharFormat = cursor.blockCharFormat(); QTextCharFormat previousCharFormat; QTextBlock::iterator it; for (it = block.begin(); !(it.atEnd()); ++it) { QTextFragment currentFragment = it.fragment(); const int fragmentStart = currentFragment.position(); const int fragmentEnd = fragmentStart + currentFragment.length(); if (to != -1 && fragmentStart >= to) break; if (currentFragment.isValid()) { QTextCharFormat charFormat = currentFragment.charFormat(); QTextCharFormat compFormat = charFormat; bool identical; previousCharFormat.clearProperty(KoCharacterStyle::ChangeTrackerId); compFormat.clearProperty(KoCharacterStyle::ChangeTrackerId); if (previousCharFormat == compFormat) identical = true; else identical = false; if ( d->changeTracker && d->changeTracker->containsInlineChanges(charFormat) && d->changeTracker->elementById(charFormat.property(KoCharacterStyle::ChangeTrackerId).toInt())->isEnabled()) { KoGenChange change; d->changeTracker->saveInlineChange(charFormat.property(KoCharacterStyle::ChangeTrackerId).toInt(), change); changeName = d->sharedData->genChanges().insert(change); d->writer->startElement("text:change-start", false); d->writer->addAttribute("text:change-id", changeName); d->writer->endElement(); } KoInlineObject *inlineObject = d->layout->inlineTextObjectManager()->inlineTextObject(charFormat); if (currentFragment.length() == 1 && inlineObject && currentFragment.text()[0].unicode() == QChar::ObjectReplacementCharacter) { inlineObject->saveOdf(d->context); } else { QString styleName = saveCharacterStyle(charFormat, blockCharFormat); if (charFormat.isAnchor()) { d->writer->startElement("text:a", false); d->writer->addAttribute("xlink:type", "simple"); d->writer->addAttribute("xlink:href", charFormat.anchorHref()); } else if (!styleName.isEmpty() /*&& !identical*/) { d->writer->startElement("text:span", false); d->writer->addAttribute("text:style-name", styleName); } QString text = currentFragment.text(); int spanFrom = fragmentStart >= from ? 0 : from; int spanTo = to == -1 ? fragmentEnd : (fragmentEnd > to ? to : fragmentEnd); if (spanFrom != fragmentStart || spanTo != fragmentEnd) { // avoid mid, if possible d->writer->addTextSpan(text.mid(spanFrom - fragmentStart, spanTo - spanFrom)); } else { d->writer->addTextSpan(text); } if ((!styleName.isEmpty() /*&& !identical*/) || charFormat.isAnchor()) d->writer->endElement(); } // if (inlineObject) if (!changeName.isEmpty()) { d->writer->startElement("text:change-end", false); d->writer->addAttribute("text:change-id",changeName); d->writer->endElement(); changeName=QString(); } previousCharFormat = charFormat; } // if (fragment.valid()) } // foeach(fragment) d->writer->endElement(); }
void QTextDocumentPrivate::setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode) { beginEditBlock(); Q_ASSERT(newFormat.isValid()); int newFormatIdx = -1; if (mode == SetFormatAndPreserveObjectIndices) { QTextCharFormat cleanFormat = newFormat; cleanFormat.clearProperty(QTextFormat::ObjectIndex); newFormatIdx = formats.indexForFormat(cleanFormat); } else if (mode == SetFormat) { newFormatIdx = formats.indexForFormat(newFormat); } if (pos == -1) { if (mode == MergeFormat) { QTextFormat format = formats.format(initialBlockCharFormatIndex); format.merge(newFormat); initialBlockCharFormatIndex = formats.indexForFormat(format); } else if (mode == SetFormatAndPreserveObjectIndices && formats.format(initialBlockCharFormatIndex).objectIndex() != -1) { QTextCharFormat f = newFormat; f.setObjectIndex(formats.format(initialBlockCharFormatIndex).objectIndex()); initialBlockCharFormatIndex = formats.indexForFormat(f); } else { initialBlockCharFormatIndex = newFormatIdx; } ++pos; --length; } const int startPos = pos; const int endPos = pos + length; split(startPos); split(endPos); while (pos < endPos) { FragmentMap::Iterator it = fragments.find(pos); Q_ASSERT(!it.atEnd()); QTextFragmentData *fragment = it.value(); Q_ASSERT(formats.format(fragment->format).type() == QTextFormat::CharFormat); int offset = pos - it.position(); int length = qMin(endPos - pos, int(fragment->size - offset)); int oldFormat = fragment->format; if (mode == MergeFormat) { QTextFormat format = formats.format(fragment->format); format.merge(newFormat); fragment->format = formats.indexForFormat(format); } else if (mode == SetFormatAndPreserveObjectIndices && formats.format(oldFormat).objectIndex() != -1) { QTextCharFormat f = newFormat; f.setObjectIndex(formats.format(oldFormat).objectIndex()); fragment->format = formats.indexForFormat(f); } else { fragment->format = newFormatIdx; } QTextUndoCommand c = { QTextUndoCommand::CharFormatChanged, true, QTextUndoCommand::MoveCursor, oldFormat, 0, pos, { length }, 0 }; appendUndoItem(c); pos += length; Q_ASSERT(pos == (int)(it.position() + fragment->size) || pos >= endPos); } int n = fragments.findNode(startPos - 1); if (n) unite(n); n = fragments.findNode(endPos); if (n) unite(n); QTextBlock blockIt = blocksFind(startPos); QTextBlock endIt = blocksFind(endPos); if (endIt.isValid()) endIt = endIt.next(); for (; blockIt.isValid() && blockIt != endIt; blockIt = blockIt.next()) QTextDocumentPrivate::block(blockIt)->invalidate(); documentChange(startPos, length); endEditBlock(); }
void tst_QTextFormat::resolveFont() { QTextDocument doc; QTextCharFormat fmt; fmt.setProperty(QTextFormat::ForegroundBrush, QColor(Qt::blue)); QCOMPARE(fmt.property(QTextFormat::ForegroundBrush).userType(), qMetaTypeId<QColor>()); QCOMPARE(fmt.property(QTextFormat::ForegroundBrush).value<QColor>(), QColor(Qt::blue)); fmt.setProperty(QTextFormat::FontItalic, true); QTextCursor(&doc).insertText("Test", fmt); QVector<QTextFormat> formats = doc.allFormats(); QCOMPARE(formats.count(), 3); QVERIFY(formats.at(2).type() == QTextFormat::CharFormat); fmt = formats.at(2).toCharFormat(); QVERIFY(!fmt.font().underline()); QVERIFY(fmt.hasProperty(QTextFormat::ForegroundBrush)); QFont f; f.setUnderline(true); doc.setDefaultFont(f); formats = doc.allFormats(); fmt = formats.at(2).toCharFormat(); QVERIFY(fmt.font().underline()); QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); // verify that deleting a non-existent property does not affect the font resolving QVERIFY(!fmt.hasProperty(QTextFormat::BackgroundBrush)); fmt.clearProperty(QTextFormat::BackgroundBrush); QVERIFY(!fmt.hasProperty(QTextFormat::BackgroundBrush)); QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); QVERIFY(fmt.font().underline()); // verify that deleting an existent but font _unrelated_ property does not affect the font resolving QVERIFY(fmt.hasProperty(QTextFormat::ForegroundBrush)); fmt.clearProperty(QTextFormat::ForegroundBrush); QVERIFY(!fmt.hasProperty(QTextFormat::ForegroundBrush)); QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); QVERIFY(fmt.font().underline()); // verify that removing a font property _does_ clear the resolving QVERIFY(fmt.hasProperty(QTextFormat::FontItalic)); fmt.clearProperty(QTextFormat::FontItalic); QVERIFY(!fmt.hasProperty(QTextFormat::FontItalic)); QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); QVERIFY(!fmt.font().underline()); QVERIFY(!fmt.font().italic()); // reset fmt = formats.at(2).toCharFormat(); QVERIFY(fmt.font().underline()); QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); // verify that _setting_ an unrelated property does _not_ affect the resolving QVERIFY(!fmt.hasProperty(QTextFormat::IsAnchor)); fmt.setProperty(QTextFormat::IsAnchor, true); QVERIFY(fmt.hasProperty(QTextFormat::IsAnchor)); QVERIFY(fmt.font().underline()); QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); // verify that setting a _related_ font property does affect the resolving // QVERIFY(!fmt.hasProperty(QTextFormat::FontStrikeOut)); fmt.setProperty(QTextFormat::FontStrikeOut, true); QVERIFY(fmt.hasProperty(QTextFormat::FontStrikeOut)); QVERIFY(!fmt.font().underline()); QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); QVERIFY(fmt.font().strikeOut()); }
QT_BEGIN_NAMESPACE /*! \class QTextTableCell \reentrant \brief The QTextTableCell class represents the properties of a cell in a QTextTable. \ingroup text Table cells are pieces of document structure that belong to a table. The table orders cells into particular rows and columns; cells can also span multiple columns and rows. Cells are usually created when a table is inserted into a document with QTextCursor::insertTable(), but they are also created and destroyed when a table is resized. Cells contain information about their location in a table; you can obtain the row() and column() numbers of a cell, and its rowSpan() and columnSpan(). The format() of a cell describes the default character format of its contents. The firstCursorPosition() and lastCursorPosition() functions are used to obtain the extent of the cell in the document. \sa QTextTable QTextTableFormat */ /*! \fn QTextTableCell::QTextTableCell() Constructs an invalid table cell. \sa isValid() */ /*! \fn QTextTableCell::QTextTableCell(const QTextTableCell &other) Copy constructor. Creates a new QTextTableCell object based on the \a other cell. */ /*! \fn QTextTableCell& QTextTableCell::operator=(const QTextTableCell &other) Assigns the \a other table cell to this table cell. */ /*! \since 4.2 Sets the cell's character format to \a format. This can for example be used to change the background color of the entire cell: QTextTableCell cell = table->cellAt(2, 3); QTextCharFormat format = cell.format(); format.setBackground(Qt::blue); cell.setFormat(format); Note that the cell's row or column span cannot be changed through this function. You have to use QTextTable::mergeCells and QTextTable::splitCell instead. \sa format() */ void QTextTableCell::setFormat(const QTextCharFormat &format) { QTextCharFormat fmt = format; fmt.clearProperty(QTextFormat::ObjectIndex); fmt.setObjectType(QTextFormat::TableCellObject); QTextDocumentPrivate *p = table->docHandle(); QTextDocumentPrivate::FragmentIterator frag(&p->fragmentMap(), fragment); QTextFormatCollection *c = p->formatCollection(); QTextCharFormat oldFormat = c->charFormat(frag->format); fmt.setTableCellRowSpan(oldFormat.tableCellRowSpan()); fmt.setTableCellColumnSpan(oldFormat.tableCellColumnSpan()); p->setCharFormat(frag.position(), 1, fmt, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices); }
bool QTextHtmlImporter::appendNodeText() { const int initialCursorPosition = cursor.position(); QTextCharFormat format = currentNode->charFormat; if(wsm == QTextHtmlParserNode::WhiteSpacePre || wsm == QTextHtmlParserNode::WhiteSpacePreWrap) compressNextWhitespace = PreserveWhiteSpace; QString text = currentNode->text; QString textToInsert; textToInsert.reserve(text.size()); for (int i = 0; i < text.length(); ++i) { QChar ch = text.at(i); if (ch.isSpace() && ch != QChar::Nbsp && ch != QChar::ParagraphSeparator) { if (compressNextWhitespace == CollapseWhiteSpace) compressNextWhitespace = RemoveWhiteSpace; // allow this one, and remove the ones coming next. else if(compressNextWhitespace == RemoveWhiteSpace) continue; if (wsm == QTextHtmlParserNode::WhiteSpacePre || textEditMode ) { if (ch == QLatin1Char('\n')) { if (textEditMode) continue; } else if (ch == QLatin1Char('\r')) { continue; } } else if (wsm != QTextHtmlParserNode::WhiteSpacePreWrap) { compressNextWhitespace = RemoveWhiteSpace; if (wsm == QTextHtmlParserNode::WhiteSpaceNoWrap) ch = QChar::Nbsp; else ch = QLatin1Char(' '); } } else { compressNextWhitespace = PreserveWhiteSpace; } if (ch == QLatin1Char('\n') || ch == QChar::ParagraphSeparator) { if (!textToInsert.isEmpty()) { cursor.insertText(textToInsert, format); textToInsert.clear(); } QTextBlockFormat fmt = cursor.blockFormat(); if (fmt.hasProperty(QTextFormat::BlockBottomMargin)) { QTextBlockFormat tmp = fmt; tmp.clearProperty(QTextFormat::BlockBottomMargin); cursor.setBlockFormat(tmp); } fmt.clearProperty(QTextFormat::BlockTopMargin); appendBlock(fmt, cursor.charFormat()); } else { if (!namedAnchors.isEmpty()) { if (!textToInsert.isEmpty()) { cursor.insertText(textToInsert, format); textToInsert.clear(); } format.setAnchor(true); format.setAnchorNames(namedAnchors); cursor.insertText(ch, format); namedAnchors.clear(); format.clearProperty(QTextFormat::IsAnchor); format.clearProperty(QTextFormat::AnchorName); } else { textToInsert += ch; } } } if (!textToInsert.isEmpty()) { cursor.insertText(textToInsert, format); } return cursor.position() != initialCursorPosition; }