void HGMarkdownHighlighter::highlight() { if (cached_elements == NULL) { qDebug() << "cached_elements is NULL"; return; } if (highlightingStyles == NULL) this->setDefaultStyles(); this->clearFormatting(); for (int i = 0; i < highlightingStyles->size(); i++) { HighlightingStyle style = highlightingStyles->at(i); pmh_element *elem_cursor = cached_elements[style.type]; while (elem_cursor != NULL) { if (elem_cursor->end <= elem_cursor->pos) { elem_cursor = elem_cursor->next; continue; } // "The QTextLayout object can only be modified from the // documentChanged implementation of a QAbstractTextDocumentLayout // subclass. Any changes applied from the outside cause undefined // behavior." -- we are breaking this rule here. There might be // a better (more correct) way to do this. int startBlockNum = document->findBlock(elem_cursor->pos).blockNumber(); int endBlockNum = document->findBlock(elem_cursor->end).blockNumber(); for (int j = startBlockNum; j <= endBlockNum; j++) { QTextBlock block = document->findBlockByNumber(j); QTextLayout *layout = block.layout(); QList<QTextLayout::FormatRange> list = layout->additionalFormats(); int blockpos = block.position(); QTextLayout::FormatRange r; r.format = style.format; if (j == startBlockNum) { r.start = elem_cursor->pos - blockpos; r.length = (startBlockNum == endBlockNum) ? elem_cursor->end - elem_cursor->pos : block.length() - r.start; } else if (j == endBlockNum) { r.start = 0; r.length = elem_cursor->end - blockpos; } else { r.start = 0; r.length = block.length(); } list.append(r); layout->setAdditionalFormats(list); } elem_cursor = elem_cursor->next; } } document->markContentsDirty(0, document->characterCount()); }
void tst_qquickstyledtext::textOutput() { QFETCH(QString, input); QFETCH(QString, output); QFETCH(FormatList, formats); QFETCH(bool, modifiesFontSize); QTextLayout layout; QList<QQuickStyledTextImgTag*> imgTags; bool fontSizeModified = false; QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); QCOMPARE(layout.text(), output); QList<QTextLayout::FormatRange> layoutFormats = layout.additionalFormats(); QCOMPARE(layoutFormats.count(), formats.count()); for (int i = 0; i < formats.count(); ++i) { QCOMPARE(layoutFormats.at(i).start, formats.at(i).start); QCOMPARE(layoutFormats.at(i).length, formats.at(i).length); if (formats.at(i).type & Format::Bold) QVERIFY(layoutFormats.at(i).format.fontWeight() == QFont::Bold); else QVERIFY(layoutFormats.at(i).format.fontWeight() == QFont::Normal); QVERIFY(layoutFormats.at(i).format.fontItalic() == bool(formats.at(i).type & Format::Italic)); QVERIFY(layoutFormats.at(i).format.fontUnderline() == bool(formats.at(i).type & Format::Underline)); } QCOMPARE(fontSizeModified, modifiesFontSize); }
void QSAEditor::clearMarkerFormat(const QTextBlock &block, int markerId) { QTextLayout *layout = block.layout(); QList<QTextLayout::FormatRange> formats = layout->additionalFormats(); bool formatsChanged = false; for (int i = 0; i < formats.count(); ++i) if (formats.at(i).format.hasProperty(markerId)) { formats[i].format.clearBackground(); formats[i].format.clearProperty(markerId); if (formats.at(i).format.properties().isEmpty()) { formats.removeAt(i); --i; } formatsChanged = true; } if (formatsChanged) layout->setAdditionalFormats(formats); }
void tst_qquickstyledtext::anchors() { QFETCH(QString, input); QFETCH(QString, output); QFETCH(FormatList, formats); QTextLayout layout; QList<QQuickStyledTextImgTag*> imgTags; bool fontSizeModified = false; QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); QCOMPARE(layout.text(), output); QList<QTextLayout::FormatRange> layoutFormats = layout.additionalFormats(); QCOMPARE(layoutFormats.count(), formats.count()); for (int i = 0; i < formats.count(); ++i) { QCOMPARE(layoutFormats.at(i).start, formats.at(i).start); QCOMPARE(layoutFormats.at(i).length, formats.at(i).length); QVERIFY(layoutFormats.at(i).format.isAnchor() == bool(formats.at(i).type & Format::Anchor)); } }
void QSyntaxHighlighterPrivate::applyFormatChanges() { QTextLayout *layout = currentBlock.layout(); QList<QTextLayout::FormatRange> ranges = layout->additionalFormats(); const int preeditAreaStart = layout->preeditAreaPosition(); const int preeditAreaLength = layout->preeditAreaText().length(); QList<QTextLayout::FormatRange>::Iterator it = ranges.begin(); while (it != ranges.end()) { if (it->start >= preeditAreaStart && it->start + it->length <= preeditAreaStart + preeditAreaLength) ++it; else it = ranges.erase(it); } QTextCharFormat emptyFormat; QTextLayout::FormatRange r; r.start = r.length = -1; int i = 0; while (i < formatChanges.count()) { while (i < formatChanges.count() && formatChanges.at(i) == emptyFormat) ++i; if (i >= formatChanges.count()) break; r.start = i; r.format = formatChanges.at(i); while (i < formatChanges.count() && formatChanges.at(i) == r.format) ++i; if (i >= formatChanges.count()) break; r.length = i - r.start; if (r.start >= preeditAreaStart) { r.start += preeditAreaLength; } else if (r.start + r.length >= preeditAreaStart) { r.length += preeditAreaLength; } ranges << r; r.start = r.length = -1; } if (r.start != -1) { r.length = formatChanges.count() - r.start; if (r.start >= preeditAreaStart) { r.start += preeditAreaLength; } else if (r.start + r.length >= preeditAreaStart) { r.length += preeditAreaLength; } ranges << r; } layout->setAdditionalFormats(ranges); }
void MarkdownHighlighter::resultReady(pmh_element **elements) { QTextBlock block = document()->firstBlock(); while (block.isValid()) { block.layout()->clearAdditionalFormats(); block = block.next(); } if (!elements) { qDebug() << "elements is null"; return; } // QTextDocument::characterCount returns a value one higher than the // actual character count. // See: https://bugreports.qt.nokia.com//browse/QTBUG-4841 // document->toPlainText().length() would give us the correct value // but it's probably too slow. unsigned long max_offset = document()->characterCount() - 1; for (int i = 0; i < highlightingStyles.size(); i++) { HighlightingStyle style = highlightingStyles.at(i); pmh_element *elem_cursor = elements[style.type]; while (elem_cursor != NULL) { unsigned long pos = elem_cursor->pos; unsigned long end = elem_cursor->end; if (end <= pos || max_offset < pos) { elem_cursor = elem_cursor->next; continue; } if (max_offset < end) end = max_offset; // "The QTextLayout object can only be modified from the // documentChanged implementation of a QAbstractTextDocumentLayout // subclass. Any changes applied from the outside cause undefined // behavior." -- we are breaking this rule here. There might be // a better (more correct) way to do this. int startBlockNum = document()->findBlock(pos).blockNumber(); int endBlockNum = document()->findBlock(end).blockNumber(); for (int j = startBlockNum; j <= endBlockNum; j++) { QTextBlock block = document()->findBlockByNumber(j); QTextLayout *layout = block.layout(); QList<QTextLayout::FormatRange> list = layout->additionalFormats(); int blockpos = block.position(); QTextLayout::FormatRange r; r.format = style.format; if (/*_makeLinksClickable &&*/ (elem_cursor->type == pmh_LINK || elem_cursor->type == pmh_AUTO_LINK_URL || elem_cursor->type == pmh_AUTO_LINK_EMAIL || elem_cursor->type == pmh_REFERENCE) && elem_cursor->address != NULL) { QString address(elem_cursor->address); if (elem_cursor->type == pmh_AUTO_LINK_EMAIL && !address.startsWith("mailto:")) address = "mailto:" + address; QTextCharFormat linkFormat(r.format); linkFormat.setAnchor(true); linkFormat.setAnchorHref(address); linkFormat.setToolTip(address); r.format = linkFormat; } if (j == startBlockNum) { r.start = pos - blockpos; r.length = (startBlockNum == endBlockNum) ? end - pos : block.length() - r.start; } else if (j == endBlockNum) { r.start = 0; r.length = end - blockpos; } else { r.start = 0; r.length = block.length(); } list.append(r); layout->setAdditionalFormats(list); } elem_cursor = elem_cursor->next; } } document()->markContentsDirty(0, document()->characterCount()); pmh_free_elements(elements); }