void TextDocumentModel::fillBlock(const QTextBlock &block, QStandardItem *parent) { for (auto it = block.begin(); it != block.end(); ++it) { QStandardItem *item = new QStandardItem(tr("Fragment: %1").arg(it.fragment().text())); const QRectF b = m_document->documentLayout()->blockBoundingRect(block); appendRow(parent, item, it.fragment().charFormat(), b); if (!block.layout()) continue; #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) foreach (const auto &range, block.layout()->formats()) { const auto start = std::max(range.start, it.fragment().position() - block.position()); const auto end = std::min(range.start + range.length, it.fragment().position() + it.fragment().length() - block.position()); if (start >= end) continue; auto child = new QStandardItem(tr("Layout Range: %1").arg(it.fragment().text().mid(start, end -start))); appendRow(item, child, range.format, QRectF()); } #endif } }
virtual void visitBlock(QTextBlock &block, const QTextCursor &caret) { m_formats.clear(); m_cursors.clear(); for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) { QTextCursor fragmentSelection(caret); fragmentSelection.setPosition(it.fragment().position()); fragmentSelection.setPosition(it.fragment().position() + it.fragment().length(), QTextCursor::KeepAnchor); if (fragmentSelection.anchor() >= fragmentSelection.position()) { continue; } visitFragmentSelection(fragmentSelection); } QTextCursor cursor(caret); cursor.mergeBlockFormat(m_deltaBlockFormat); cursor.mergeBlockCharFormat(m_deltaCharFormat); QList<QTextCharFormat>::Iterator it = m_formats.begin(); foreach(QTextCursor cursor, m_cursors) { cursor.setCharFormat(*it); ++it; }
void TextDocumentModel::fillBlock(const QTextBlock &block, QStandardItem *parent) { for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) { QStandardItem *item = new QStandardItem(tr("Fragment: %1").arg(it.fragment().text())); const QRectF b = m_document->documentLayout()->blockBoundingRect(block); appendRow(parent, item, it.fragment().charFormat(), b); } }
QString Text::extractSanitizedText(int from, int to) const { if (!doc) return ""; QString txt; QTextBlock begin = doc->findBlock(from); QTextBlock end = doc->findBlock(to); for (QTextBlock block = begin; block != end.next() && block.isValid(); block = block.next()) { for (QTextBlock::Iterator itr = block.begin(); itr != block.end(); ++itr) { int pos = itr.fragment() .position(); // fragment position -> position of the first character in the fragment if (itr.fragment().charFormat().isImageFormat()) { QTextImageFormat imgFmt = itr.fragment().charFormat().toImageFormat(); QString key = imgFmt.name(); // img key (eg. key::D for :D) QString rune = key.mid(4); if (pos >= from && pos < to) { txt += rune; ++pos; } } else { for (QChar c : itr.fragment().text()) { if (pos >= from && pos < to) txt += c; ++pos; } } } txt += '\n'; } txt.chop(1); return txt; }
virtual void visitBlock(QTextBlock &block, const QTextCursor &caret) { for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) { QTextCursor fragmentSelection(caret); fragmentSelection.setPosition(it.fragment().position()); fragmentSelection.setPosition(it.fragment().position() + it.fragment().length(), QTextCursor::KeepAnchor); if (fragmentSelection.anchor() >= fragmentSelection.position()) { continue; } visitFragmentSelection(fragmentSelection); } QList<QTextCharFormat>::Iterator it = m_formats.begin(); Q_FOREACH (QTextCursor cursor, m_cursors) { QTextFormat prevFormat(cursor.charFormat()); cursor.setCharFormat(*it); editor()->registerTrackedChange(cursor, KoGenChange::FormatChange, kundo2_i18n("Formatting"), *it, prevFormat, false); ++it; }
void ContactListEdit::GetCollectedContacts(IMailProcessor::TRecipientPublicKeys* storage) const { assert(storage != nullptr); storage->reserve(10); QTextBlock block = document()->begin(); while(block.isValid()) { for(QTextBlock::iterator i = block.begin(); i != block.end(); ++i) { QTextCharFormat format = i.fragment().charFormat(); if(format.isImageFormat()) { QTextImageFormat imgF = format.toImageFormat(); IMailProcessor::TRecipientPublicKey pk; decodePublicKey(imgF, &pk); assert(pk.valid()); storage->push_back(pk); } } block = block.next(); } }
bool RTF::Writer::write(QIODevice* device, QTextDocument* text) { if (m_codec == 0) { return false; } device->write(m_header); for (QTextBlock block = text->begin(); block.isValid(); block = block.next()) { QByteArray par("{\\pard\\plain"); QTextBlockFormat block_format = block.blockFormat(); bool rtl = block_format.layoutDirection() == Qt::RightToLeft; if (rtl) { par += "\\rtlpar"; } Qt::Alignment align = block_format.alignment(); if (rtl && (align & Qt::AlignLeft)) { par += "\\ql"; } else if (align & Qt::AlignRight) { par += "\\qr"; } else if (align & Qt::AlignCenter) { par += "\\qc"; } else if (align & Qt::AlignJustify) { par += "\\qj"; } if (block_format.indent() > 0) { par += "\\li" + QByteArray::number(block_format.indent() * 15); } device->write(par); if (block.begin() != block.end()) { device->write(" "); for (QTextBlock::iterator iter = block.begin(); iter != block.end(); ++iter) { QTextFragment fragment = iter.fragment(); QTextCharFormat char_format = fragment.charFormat(); QByteArray style; if (char_format.fontWeight() == QFont::Bold) { style += "\\b"; } if (char_format.fontItalic()) { style += "\\i"; } if (char_format.fontUnderline()) { style += "\\ul"; } if (char_format.fontStrikeOut()) { style += "\\strike"; } if (char_format.verticalAlignment() == QTextCharFormat::AlignSuperScript) { style += "\\super"; } else if (char_format.verticalAlignment() == QTextCharFormat::AlignSubScript) { style += "\\sub"; } if (!style.isEmpty()) { device->write("{" + style + " " + fromUnicode(fragment.text()) + "}"); } else { device->write(fromUnicode(fragment.text())); } } } device->write("\\par}\n"); } device->write("\n}"); return true; }
void TextContent::updateTextConstraints() { // 1. actual content stretch double prevXScale = 1.0; double prevYScale = 1.0; /* if (m_textRect.width() > 0 && m_textRect.height() > 0) { QRect cRect = contentRect(); prevXScale = (qreal)cRect.width() / (qreal)m_textRect.width(); prevYScale = (qreal)cRect.height() / (qreal)m_textRect.height(); }*/ // 2. LAYOUT TEXT. find out Block rects and Document rect int minCharSide = 0; m_blockRects.clear(); m_textRect = QRect(0, 0, 0, 0); for (QTextBlock tb = m_text->begin(); tb.isValid(); tb = tb.next()) { if (!tb.isVisible()) continue; // 2.1.A. calc the Block size uniting Fragments bounding rects QRect blockRect(0, 0, 0, 0); for (QTextBlock::iterator tbIt = tb.begin(); !(tbIt.atEnd()); ++tbIt) { QTextFragment frag = tbIt.fragment(); if (!frag.isValid()) continue; QString text = frag.text(); if (text.trimmed().isEmpty()) continue; QFontMetrics metrics(frag.charFormat().font()); if (!minCharSide || metrics.height() > minCharSide) minCharSide = metrics.height(); // TODO: implement superscript / subscript (it's in charFormat's alignment) // it must be implemented in paint too QRect textRect = metrics.boundingRect(text); if (textRect.left() > 9999) continue; if (textRect.top() < blockRect.top()) blockRect.setTop(textRect.top()); if (textRect.bottom() > blockRect.bottom()) blockRect.setBottom(textRect.bottom()); int textWidth = metrics.width(text); blockRect.setWidth(blockRect.width() + textWidth); } // 2.1.B. calc the Block size of blank lines if (tb.begin() == tb.end()) { QFontMetrics metrics(tb.charFormat().font()); int textHeight = metrics.height(); blockRect.setWidth(1); blockRect.setHeight(textHeight); } // 2.2. add the Block's margins QTextBlockFormat tbFormat = tb.blockFormat(); blockRect.adjust(-tbFormat.leftMargin(), -tbFormat.topMargin(), tbFormat.rightMargin(), tbFormat.bottomMargin()); // 2.3. store the original block rect m_blockRects.append(blockRect); // 2.4. enlarge the Document rect (uniting the Block rect) blockRect.translate(0, m_textRect.bottom() - blockRect.top() + 1); if (blockRect.left() < m_textRect.left()) m_textRect.setLeft(blockRect.left()); if (blockRect.right() > m_textRect.right()) m_textRect.setRight(blockRect.right()); if (blockRect.top() < m_textRect.top()) m_textRect.setTop(blockRect.top()); if (blockRect.bottom() > m_textRect.bottom()) m_textRect.setBottom(blockRect.bottom()); } m_textRect.adjust(-m_textMargin, -m_textMargin, m_textMargin, m_textMargin); // 3. use shape-based rendering if (hasShape()) { #if 1 // more precise, but too close to the path m_shapeRect = m_shapePath.boundingRect().toRect(); #else // faster, but less precise (as it uses the controls points to determine // the path rect, instead of the path itself) m_shapeRect = m_shapePath.controlPointRect().toRect(); #endif minCharSide = qBound(10, minCharSide, 500); m_shapeRect.adjust(-minCharSide, -minCharSide, minCharSide, minCharSide); // FIXME: layout, save layouting and calc the exact size! //int w = m_shapeRect.width(); //int h = m_shapeRect.height(); //resizeContents(QRect(-w / 2, -h / 2, w, h)); resizeContents(m_shapeRect); // moveBy(m_shapeRect.left(), m_shapeRect.top()); // m_shapePath.translate(-m_shapeRect.left(), -m_shapeRect.top()); //setPos(m_shapeRect.center()); return; } // 4. resize content keeping stretch int w = (int)(prevXScale * (qreal)m_textRect.width()); int h = (int)(prevYScale * (qreal)m_textRect.height()); resizeContents(QRect(-w / 2, -h / 2, w, h)); }
QString Format::frameToString( QTextFrame *frame ) { QString out; QTextFrame::iterator it; for( it = frame->begin(); it != frame->end(); ++it ) { QTextBlock block = it.currentBlock(); if ( block.isValid() ) { out += "<block"; QTextCursor c( block ); QDateTime dt = TextFormats::lastModified( c ); if ( dt.isValid() ) { out += " lastmodified=\"" + dt.toString( Qt::ISODate ) + "\""; } if ( TextFormats::isTitle( c ) ) { out += " titlestyle=\"title\""; } else if ( TextFormats::isSubTitle( c ) ) { out += " titlestyle=\"subtitle\""; } QTextBlockFormat blockFormat = block.blockFormat(); if ( blockFormat.isValid() ) { QTextList *list = block.textList(); if ( list ) { QTextListFormat f = list->format(); out += " liststyle=\""; switch( f.style() ) { default: case QTextListFormat::ListDisc: out += "disc"; break; case QTextListFormat::ListDecimal: out += "decimal"; break; } out += "\""; out += " listindent=\"" + QString::number( f.indent() ) + "\""; } else { if ( blockFormat.indent() != 0 ) { out += " blockindent=\"" + QString::number( blockFormat.indent() ) + "\""; } } } out += ">\n"; QTextBlock::iterator it2; for( it2 = block.begin(); it2 != block.end(); ++it2 ) { QTextFragment fragment = it2.fragment(); if ( !fragment.isValid() ) continue; QString text = fragment.text(); QString outText; for( int i = 0; i < text.size(); ++i ) { if ( text.at( i ) == 0xfffc ) { outText += "<todo status=\""; QTextImageFormat imageFormat = fragment.charFormat().toImageFormat(); if ( imageFormat.isValid() ) { if ( imageFormat.name().contains( "done" ) ) outText += "done"; else outText += "todo"; } else { dbg() << "NO IMAGE FORMAT" << endl; } outText += "\"/>"; } else { outText += escape( QString( text.at( i ) ) ); } } out += " <fragment"; QTextCharFormat format = fragment.charFormat(); if ( !format.anchorHref().isEmpty() ) { out += " link=\"" + escape( format.anchorHref() ) + "\""; } if ( format.fontWeight() == QFont::Bold ) { out += " bold=\"true\""; } if ( format.fontItalic() ) { out += " italic=\"true\""; } if ( format.hasProperty( QTextFormat::FontPointSize ) && format.fontPointSize() != 10 ) { out += " fontsize=\"" + QString::number( format.fontPointSize() ) + "\""; } if ( outText.trimmed().isEmpty() ) outText.replace( " ", "[FIXME:space]" ); out += ">" + outText + "</fragment>\n"; } out += "</block>"; out += "\n"; } QTextFrame *f = it.currentFrame(); if ( f ) { QTextFrameFormat format = f->frameFormat(); out += "<frame"; if ( format.hasProperty( TextFormats::FrameType ) ) { out += " type="; if ( format.property( TextFormats::FrameType ) == TextFormats::CodeFrame ) { out += "\"code\""; } else { out += "\"undefined\""; } } out += ">\n"; out += frameToString( f ); out += "</frame>\n"; } } return out; }
QString validHtml(const QString &html, bool allowReplacement, QTextCursor *tc) { QDesktopWidget dw; ValidDocument oValidDocument(allowReplacement); QRectF qr = dw.availableGeometry(); oValidDocument.setTextWidth(qr.width() / 2); oValidDocument.setDefaultStyleSheet(qApp->styleSheet()); oValidDocument.setHtml(html); bool fIsValid = oValidDocument.isValid(); QStringList qslAllowed = allowedSchemes(); for (QTextBlock qtb = oValidDocument.begin(); qtb != oValidDocument.end(); qtb = qtb.next()) { for (QTextBlock::iterator qtbi = qtb.begin(); qtbi != qtb.end(); ++qtbi) { const QTextFragment &qtf = qtbi.fragment(); QTextCharFormat qcf = qtf.charFormat(); if (! qcf.anchorHref().isEmpty()) { QUrl url(qcf.anchorHref()); if (! url.isValid() || ! qslAllowed.contains(url.scheme())) { QTextCharFormat qcfn = QTextCharFormat(); QTextCursor qtc(&oValidDocument); qtc.setPosition(qtf.position(), QTextCursor::MoveAnchor); qtc.setPosition(qtf.position()+qtf.length(), QTextCursor::KeepAnchor); qtc.setCharFormat(qcfn); qtbi = qtb.begin(); } } if (qcf.isImageFormat()) { QTextImageFormat qtif = qcf.toImageFormat(); QUrl url(qtif.name()); if (! qtif.name().isEmpty() && ! url.isValid()) fIsValid = false; } } } oValidDocument.adjustSize(); QSizeF s = oValidDocument.size(); if (!fIsValid || (s.width() > qr.width()) || (s.height() > qr.height())) { oValidDocument.setPlainText(html); oValidDocument.adjustSize(); s = oValidDocument.size(); if ((s.width() > qr.width()) || (s.height() > qr.height())) { QString errorMessage = "[[ Text object too large to display ]]"; if (tc) { tc->insertText(errorMessage); return QString(); } else { return errorMessage; } } } if (tc) { QTextCursor tcNew(&oValidDocument); tcNew.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); tc->insertFragment(tcNew.selection()); return QString(); } else { return oValidDocument.toHtml(); } }