int ShaderEdit::searchPreviousMatch( QTextBlock block, int start, QString close, QString open ) { int skipNext = 0; --start; TextBlockData *data = (TextBlockData*)block.userData(); do { if ( data ) { for ( int i = start; i >= 0; --i ) { ParenthesisInfo pi = data->parenthesis[i]; QString s = pi.character; if ( s == open ) { if ( skipNext > 0 ) --skipNext; else return block.position() + pi.position; } else if ( s == close ) ++skipNext; } } block = block.previous(); data = (TextBlockData*)block.userData(); if ( data ) start = data->parenthesis.count() - 1; } while ( block.isValid() ); return -1; }
static int findOpeningMatch(const QTextDocument *doc, int cursorPosition) { QTextBlock block = doc->findBlock(cursorPosition); TextBlockData *blockData = reinterpret_cast<TextBlockData *>(block.userData()); if (!blockData->bracketPositions.isEmpty()) { int depth = 1; while (block.isValid()) { blockData = reinterpret_cast<TextBlockData *>(block.userData()); if (blockData && !blockData->bracketPositions.isEmpty()) { for (int c = blockData->bracketPositions.count() - 1; c >= 0; --c) { int absPos = block.position() + blockData->bracketPositions.at(c); if (absPos >= cursorPosition - 1) continue; if (doc->characterAt(absPos) == '}') depth++; else depth--; if (depth == 0) return absPos; } } block = block.previous(); } } return -1; }
void TestDocumentLayout::testCenteredItems() { initForNewTest("ListItem\nListItem\nListItem"); KoListStyle listStyle; KoListLevelProperties llp; llp.setStyle(KoListStyle::DecimalItem); listStyle.setLevelProperties(llp); QTextBlock block = m_doc->begin(); // normal block QVERIFY(block.isValid()); listStyle.applyStyle(block); block = block.next(); // centered block QVERIFY(block.isValid()); listStyle.applyStyle(block); QTextBlockFormat fmt; fmt.setAlignment(Qt::AlignHCenter); QTextCursor cursor(block); cursor.mergeBlockFormat(fmt); block = block.next(); // centered RTL text. listStyle.applyStyle(block); cursor = QTextCursor(block); fmt.setProperty(KoParagraphStyle::TextProgressionDirection, KoText::RightLeftTopBottom); cursor.mergeBlockFormat(fmt); m_layout->layout(); block = m_doc->begin(); QTextLayout *layout = block.layout(); QTextLine line1 = layout->lineAt(0); KoTextBlockData *data1 = dynamic_cast<KoTextBlockData *>(block.userData()); QVERIFY(line1.isValid()); QVERIFY(line1.width() < 200); // the counter takes some space. block = block.next(); layout = block.layout(); QTextLine line2 = layout->lineAt(0); KoTextBlockData *data2 = dynamic_cast<KoTextBlockData *>(block.userData()); QVERIFY(line2.isValid()); QVERIFY(line2.width() < 200); // the counter takes some space. QCOMPARE(line1.width(), line2.width()); const qreal width1 = line1.naturalTextWidth() + data1->counterWidth() + data1->counterSpacing(); const qreal width2 = line2.naturalTextWidth() + data2->counterWidth() + data2->counterSpacing(); QCOMPARE(width1, width2); QVERIFY(data1->counterPosition().x() < data2->counterPosition().x()); const qreal padding = (200 - width2) / 2; QVERIFY(padding > 0);// not really a layout test, but the rest will be bogus otherwise. QCOMPARE(data2->counterPosition().x(), padding); // close to the centered text. // right to left parag places the counter on the right. Its centered, so not the far right. block = block.next(); layout = block.layout(); QTextLine line = layout->lineAt(0); KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData()); QCOMPARE(data->counterPosition().x(), 200 - padding - data->counterWidth()); }
void Document::dictionaryChanged() { for (QTextBlock i = m_text->document()->begin(); i != m_text->document()->end(); i = i.next()) { if (i.userData()) { static_cast<BlockStats*>(i.userData())->checkSpelling(i.text(), m_dictionary); } } m_highlighter->rehighlight(); }
void TestDocumentLayout::testListParagraphIndent() { // test that the list item is drawn indented on an indented paragraph. initForNewTest("Foo\nBar\n"); KoParagraphStyle h1; m_styleManager->add(&h1); KoParagraphStyle h2; m_styleManager->add(&h2); h2.setTextIndent(10); KoListStyle listStyle; h1.setListStyle(&listStyle); KoListStyle listStyle2; h2.setListStyle(&listStyle2); QTextBlock block = m_doc->begin(); h1.applyStyle(block); block = block.next(); h2.applyStyle(block); m_layout->layout(); // still at h2 parag! KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData()); QVERIFY(data); QCOMPARE(data->counterPosition(), QPointF(10, 14.4)); }
TokenIterator& operator --() { if(idx > 0) { --idx; return *this; } else if( idx < 0 ) { return *this; } idx = -1; while( (blk = blk.previous()).isValid() ) { data = static_cast<TextBlockData*>(blk.userData()); if(data) idx = data->tokens.size() - 1; if (idx < 0) continue; // we have a valid idx break; } return *this; }
// Return an iterator for the token at 'pos' or 'pos-1'. // If there is no such token, the returned iterator is invalid. static TokenIterator around( const QTextBlock & block, int positionInBlock ) { TokenIterator it; it.blk = block; it.idx = -1; if(!block.isValid()) return it; it.data = static_cast<TextBlockData*>(block.userData()); if (!it.data) return it; int n = it.data->tokens.size(); for( int i = 0; i < n; ++i ) { Token const & token = it.data->tokens[i]; if(token.positionInBlock > positionInBlock) { return it; } else if(token.positionInBlock == positionInBlock - 1 || token.positionInBlock == positionInBlock) { it.idx = i; break; } } return it; }
void TestDocumentLayout::testRightToLeftList() { initForNewTest("a\nb\nc"); KoParagraphStyle h1; h1.setTextProgressionDirection(KoText::RightLeftTopBottom); m_styleManager->add(&h1); KoListStyle listStyle; KoListLevelProperties llp = listStyle.levelProperties(1); llp.setStyle(KoListStyle::DecimalItem); listStyle.setLevelProperties(llp); h1.setListStyle(&listStyle); QTextBlock block = m_doc->begin(); h1.applyStyle(block); block = block.next(); h1.applyStyle(block); block = block.next(); h1.applyStyle(block); block = block.next(); m_layout->layout(); block = m_doc->begin(); while (block.isValid()) { KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData()); QVERIFY(data); QVERIFY(data->counterWidth() > 2); QVERIFY(data->counterPosition().x() > 100); QTextLine line = block.layout()->lineAt(0); QVERIFY(line.isValid()); QCOMPARE(line.x(), (qreal)0); QCOMPARE(line.width() + data->counterWidth() + data->counterSpacing(), (qreal)200); block = block.next(); } }
void TestDocumentLayout::testLetterSynchronization() { // make numbering be 'y, z, aa, bb, cc' initForNewTest("a\nb\na\nb\nc"); KoParagraphStyle h1; m_styleManager->add(&h1); KoListStyle listStyle; KoListLevelProperties llp; llp.setStyle(KoListStyle::AlphaLowerItem); llp.setLetterSynchronization(true); llp.setStartValue(25); listStyle.setLevelProperties(llp); h1.setListStyle(&listStyle); QTextBlock block = m_doc->begin(); while (block.isValid()) { h1.applyStyle(block); block = block.next(); } m_layout->layout(); static const char *const values[] = { "y", "z", "aa", "bb", "cc" }; block = m_doc->begin(); int i = 0; while (block.isValid()) { KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData()); QVERIFY(data); // qDebug() << "-> " << data->counterText() << endl; QCOMPARE(data->counterText(), QString(values[i++])); block = block.next(); } }
int ShaderEdit::searchNextMatch( QTextBlock block, int start, QString open, QString close ) { int skipNext = 0; int i = start + 1; do { TextBlockData *data = (TextBlockData*)block.userData(); if ( data ) { for ( ; i < data->parenthesis.count(); ++i ) { ParenthesisInfo pi = data->parenthesis[i]; QString s = pi.character; if ( s == close ) { if ( skipNext > 0 ) --skipNext; else return block.position() + pi.position; } else if ( s == open ) ++skipNext; } } block = block.next(); i = 0; } while ( block.isValid() ); return -1; }
void VPreviewManager::clearBlockObsoletePreviewInfo(long long p_timeStamp, PreviewSource p_source) { OrderedIntSet affectedBlocks; QVector<int> obsoleteBlocks; const QSet<int> &blocks = m_highlighter->getPossiblePreviewBlocks(); for (auto i : blocks) { QTextBlock block = m_document->findBlockByNumber(i); if (!block.isValid()) { obsoleteBlocks.append(i); continue; } VTextBlockData *blockData = dynamic_cast<VTextBlockData *>(block.userData()); if (!blockData) { continue; } if (blockData->clearObsoletePreview(p_timeStamp, p_source)) { affectedBlocks.insert(i, QMapDummyValue()); } if (blockData->getPreviews().isEmpty()) { obsoleteBlocks.append(i); } } m_highlighter->clearPossiblePreviewBlocks(obsoleteBlocks); m_editor->relayout(affectedBlocks); }
void KPrAttributeHeight::updateCache(KPrAnimationCache *cache, KPrShapeAnimation *shapeAnimation, qreal value) { qreal tx = 0.0, ty = 0.0; KoShape * shape = shapeAnimation->shape(); KoTextBlockData * textBlockData = shapeAnimation->textBlockData(); QTransform transform; if (textBlockData) { if (KoTextShapeData *textShapeData = dynamic_cast<KoTextShapeData*>(shape->userData())) { QTextDocument *textDocument = textShapeData->document(); for (int i = 0; i < textDocument->blockCount(); i++) { QTextBlock textBlock = textDocument->findBlockByNumber(i); if (textBlock.userData() == textBlockData) { QTextLayout *layout = textBlock.layout(); value = value * cache->pageSize().height() / layout->boundingRect().height(); tx = layout->minimumWidth() * cache->zoom() / 2; ty = layout->boundingRect().height() * cache->zoom() / 2; } } } } else { value = value * cache->pageSize().height() / shape->size().height(); tx = shape->size().width() * cache->zoom() / 2; ty = shape->size().height() * cache->zoom() / 2; } transform.translate(tx, ty).scale(1, value).translate(-tx, -ty); cache->update(shape, shapeAnimation->textBlockData(), "transform", transform); }
void KPrAttributeHeight::initCache(KPrAnimationCache *animationCache, int step, KPrShapeAnimation * shapeAnimation, qreal startValue, qreal endValue) { qreal v1 = 0.0, v2 = 0.0, tx = 0.0, ty = 0.0; KoShape * shape = shapeAnimation->shape(); KoTextBlockData * textBlockData = shapeAnimation->textBlockData(); if (textBlockData) { if (KoTextShapeData *textShapeData = dynamic_cast<KoTextShapeData*>(shape->userData())) { QTextDocument *textDocument = textShapeData->document(); for (int i = 0; i < textDocument->blockCount(); i++) { QTextBlock textBlock = textDocument->findBlockByNumber(i); if (textBlock.userData() == textBlockData) { QTextLayout *layout = textBlock.layout(); v1 = startValue * animationCache->pageSize().height() / layout->boundingRect().height(); v2 = endValue * animationCache->pageSize().height() / layout->boundingRect().height(); tx = layout->minimumWidth() * animationCache->zoom() / 2; ty = layout->boundingRect().height() * animationCache->zoom() / 2; } } } } else { v1 = startValue * animationCache->pageSize().height() / shape->size().height(); v2 = endValue * animationCache->pageSize().height() / shape->size().height(); tx = shape->size().width() * animationCache->zoom() / 2; ty = shape->size().height() * animationCache->zoom() / 2; } animationCache->init(step, shape, textBlockData, "transform", QTransform().translate(tx, ty).scale(1, v1).translate(-tx, -ty)); animationCache->init(step + 1, shape, textBlockData, "transform", QTransform().translate(tx, ty).scale(1, v2).translate(-tx, -ty)); }
bool CodeEditor::matchRightParenthesis(QTextBlock currentBlock, int i, int numRightParentheses) { TextBlockData *data = static_cast<TextBlockData *>(currentBlock.userData()); QVector<ParenthesisInfo *> parentheses = data->parentheses(); int docPos = currentBlock.position(); for (; i > -1 && parentheses.size() > 0; --i) { ParenthesisInfo *info = parentheses.at(i); if (info->character == ')') { ++numRightParentheses; continue; } if (info->character == '(' && numRightParentheses == 0) { createParenthesisSelection(docPos + info->position); return true; } else { --numRightParentheses; } } currentBlock = currentBlock.previous(); if (currentBlock.isValid()) return matchRightParenthesis(currentBlock, 0, numRightParentheses); return false; }
void TestDocumentLayout::testInvalidateLists() { initForNewTest("Base\nListItem1\nListItem2"); //KoParagraphStyle style; KoListStyle listStyle; KoListLevelProperties llp; llp.setStyle(KoListStyle::DecimalItem); listStyle.setLevelProperties(llp); //style.setListStyle(&listStyle); QTextBlock block = m_doc->begin().next(); QVERIFY(block.isValid()); listStyle.applyStyle(block); block = block.next(); QVERIFY(block.isValid()); listStyle.applyStyle(block); m_layout->layout(); // check the list items were done (semi) properly block = m_doc->begin().next(); QVERIFY(block.textList()); KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData()); QVERIFY(data); QVERIFY(data->hasCounterData()); QTextCursor cursor(m_doc); cursor.setPosition(10); // list item1 cursor.insertText("x"); QCOMPARE(data->hasCounterData(), true); // nothing changed cursor.setPosition(22); // list item2 cursor.insertText("x"); QCOMPARE(data->hasCounterData(), true); // nothing changed cursor.deleteChar(); QCOMPARE(data->hasCounterData(), true); // nothing changed cursor.setPosition(25); // end of doc cursor.insertBlock(); block = cursor.block(); QVERIFY(block.textList()); QVERIFY(block.userData() == 0); QCOMPARE(data->hasCounterData(), false); // inserting a new block on this list made the list be invalidated }
void Editor::clearAllBookmarks() { int line = 1; for ( QTextBlock block = m_textEdit->document()->begin(); block.isValid(); block = block.next(), line++ ) { BlockUserData *blockUserData = ( BlockUserData* ) block.userData(); if ( blockUserData && blockUserData->bookmark ) toggleBookmark ( line ); } }
// static bool ListItemsHelper::needsRecalc(QTextList *textList) { Q_ASSERT(textList); QTextBlock tb = textList->item(0); KoTextBlockData *data = dynamic_cast<KoTextBlockData*>(tb.userData()); if (data == 0) return true; return !data->hasCounterData(); }
QString TextDocument::tooltip(const QPoint& point) const { const int pos = documentLayout()->hitTest(point, Qt::FuzzyHit); const QTextBlock block = findBlock(pos); TextBlockMessageData* blockData = static_cast<TextBlockMessageData*>(block.userData()); if (blockData) return formatEvents(blockData->data.getEvents()); return QString(); }
// Constructs an iterator for the first token at the given block. // If there's no token in the block, the new iterator is invalid. TokenIterator( const QTextBlock & block ): blk(block), idx(-1) { if (block.isValid()) { data = static_cast<TextBlockData*>(block.userData()); if (data && !data->tokens.empty()) idx = 0; } }
QTextBlock TextBlockUserData::testCollapse(const QTextBlock& block) { QTextBlock info = block; if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == CollapseAfter) ; else if (block.next().userData() && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode() == TextBlockUserData::CollapseThis) info = block.next(); else return QTextBlock(); int pos = static_cast<TextBlockUserData*>(info.userData())->collapseAtPos(); if (pos < 0) return QTextBlock(); QTextCursor cursor(info); cursor.setPosition(cursor.position() + pos); matchCursorForward(&cursor); return cursor.block(); }
void DocumentMarker::removeMark(TextEditor::ITextMark *mark) { QTextBlock block = document->findBlockByNumber(mark->lineNumber() - 1); if (TextBlockUserData *data = static_cast<TextBlockUserData *>(block.userData())) { if (!data->removeMark(mark)) qDebug() << "Could not find mark" << mark << "on line" << mark->lineNumber(); } removeMarkFromMarksCache(mark); mark->setMarkableInterface(0); }
BaseTextDocument::~BaseTextDocument() { QTextBlock block = m_document->begin(); while (block.isValid()) { if (TextBlockUserData *data = static_cast<TextBlockUserData *>(block.userData())) data->documentClosing(); block = block.next(); } delete m_document; m_document = 0; }
QList<int> Editor::bookmarksList() { QList<int> list; int line = 1; for ( QTextBlock block = m_textEdit->document()->begin(); block.isValid(); block = block.next(), line++ ) { BlockUserData *blockUserData = ( BlockUserData* ) block.userData(); if ( blockUserData && blockUserData->bookmark ) list << line; } return list; }
void Highlighter::contentsChange(int pos, int add, int rem) { // Invalidate the cache where the text has changed const QTextBlock &lastBlock = document()->findBlock(pos + add - rem); QTextBlock block = document()->findBlock(pos); do { LanguageCache* cache=dynamic_cast<LanguageCache*>(block.userData()); if (cache) cache->invalidate(pos-block.position()); block = block.next(); } while (block.isValid() && block < lastBlock); }
void ShaderEdit::cursorPositionChanged() { QList<QTextEdit::ExtraSelection> selections; int curPos = editor->textCursor().positionInBlock(); QTextBlock currentBlock = editor->textCursor().block(); TextBlockData *data = (TextBlockData*)currentBlock.userData(); if ( !data ) { editor->setExtraSelections( selections ); return; } int searchPos = curPos; int matchPos = -1; for ( int i = 0; i < data->parenthesis.count(); ++i ) { ParenthesisInfo pi = data->parenthesis[i]; if ( pi.position == curPos || pi.position == curPos - 1 ) { searchPos = currentBlock.position() + pi.position; QString s = pi.character; if ( s == "(" ) matchPos = searchNextMatch( currentBlock, i, s, ")" ); else if ( s == "{" ) matchPos = searchNextMatch( currentBlock, i, s, "}" ); else if ( s == "[" ) matchPos = searchNextMatch( currentBlock, i, s, "]" ); else if ( s == ")" ) matchPos = searchPreviousMatch( currentBlock, i, s, "(" ); else if ( s == "}" ) matchPos = searchPreviousMatch( currentBlock, i, s, "{" ); else if ( s == "]" ) matchPos = searchPreviousMatch( currentBlock, i, s, "[" ); break; } } if ( matchPos > -1 ) { QTextEdit::ExtraSelection selection; selection.format.setBackground( Qt::yellow ); QTextCursor cursor = editor->textCursor(); cursor.setPosition( searchPos ); cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor ); selection.cursor = cursor; selections.append( selection ); cursor.setPosition( matchPos ); cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor ); selection.cursor = cursor; selections.append( selection ); } editor->setExtraSelections( selections ); }
int ScCodeEditor::indentationLevel(const QTextCursor & cursor) { QTextDocument *doc = QPlainTextEdit::document(); int startBlockNum = doc->findBlock(cursor.selectionStart()).blockNumber(); QStack<int> stack; int level = 0; int blockNum = 0; QTextBlock block = QPlainTextEdit::document()->begin(); while (block.isValid()) { if (level > 0) { stack.push(level); level = 0; } TextBlockData *data = static_cast<TextBlockData*>(block.userData()); if (data) { int count = data->tokens.size(); for (int idx = 0; idx < count; ++idx) { const Token & token = data->tokens[idx]; switch (token.type) { case Token::OpeningBracket: if (token.character != '(' || stack.size() || token.positionInBlock) level += 1; break; case Token::ClosingBracket: if (level) level -= 1; else if(!stack.isEmpty()) { stack.top() -= 1; if (stack.top() <= 0) stack.pop(); } break; default: ; } } } if (blockNum == startBlockNum) return stack.size(); block = block.next(); ++blockNum; } return -1; }
void KTextDocumentLayout::documentChanged(int position, int charsRemoved, int charsAdded) { Q_UNUSED(charsRemoved); if (shapes().count() == 0) // nothing to do. return; /* switch (document()->documentLayout()->property("KoTextRelayoutForPage").toInt()) { case KTextShapeData::NormalState: kDebug() << "KoTextRelayoutForPage in NormalState"; break; case KTextShapeData::LayoutCopyShape: kDebug() << "KoTextRelayoutForPage in LayoutCopyShape"; break; case KTextShapeData::LayoutOrig: kDebug() << "KoTextRelayoutForPage in LayoutOrig, skipping relayout"; break; } */ if (document()->documentLayout()->property("KoTextRelayoutForPage").toInt() == KTextShapeData::LayoutOrig) { // don't refresh if we relayout after a relayout-for-page return; } int from = position; const int to = from + charsAdded; while (from < to) { // find blocks that have been added QTextBlock block = document()->findBlock(from); if (! block.isValid()) break; if (from == block.position() && block.textList()) { KTextBlockData *data = dynamic_cast<KTextBlockData*>(block.userData()); if (data) data->setCounterWidth(-1); // invalidate whole list. } from = block.position() + block.length(); } foreach (KShape *shape, shapes()) { KTextShapeData *data = qobject_cast<KTextShapeData*>(shape->userData()); Q_ASSERT(data); if (data && data->position() <= position && data->endPosition() >= position) { // found our (first) shape to re-layout data->foul(); m_state->interrupted = true; scheduleLayout(); return; } }
void TestDocumentLayout::testBasicList() { initForNewTest("Base\nListItem\nListItem2: The quick brown fox jums over the lazy dog.\nNormal\nNormal"); KoParagraphStyle style; QTextBlock block = m_doc->begin(); style.applyStyle(block); block = block.next(); QVERIFY(block.isValid()); KoListStyle listStyle; KoListLevelProperties level1; level1.setStyle(KoListStyle::Bullet); listStyle.setLevelProperties(level1); style.setListStyle(&listStyle); style.applyStyle(block); // make this a listStyle QVERIFY(block.textList()); QCOMPARE(block.textList()->format().intProperty(QTextListFormat::ListStyle), (int) KoListStyle::Bullet); block = block.next(); QVERIFY(block.isValid()); style.applyStyle(block); // make this a listStyle m_layout->layout(); QTextLayout *blockLayout = m_block.layout(); QCOMPARE(blockLayout->lineAt(0).x(), 0.0); block = m_doc->begin().next(); QVERIFY(block.isValid()); blockLayout = block.layout(); // parag 2 KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData()); QVERIFY(data); qreal counterSpacing = data->counterSpacing(); QVERIFY(counterSpacing > 0.); // 12 is hardcoded to be the width of a discitem (taken from the default font): QCOMPARE(blockLayout->lineAt(0).x(), 12.0 + counterSpacing); block = block.next(); QVERIFY(block.isValid()); blockLayout = block.layout(); // parag 3 QCOMPARE(blockLayout->lineAt(0).x(), 12.0 + counterSpacing); QVERIFY(blockLayout->lineCount() > 1); QCOMPARE(blockLayout->lineAt(1).x(), 12.0 + counterSpacing); // make sure not only the first line is indented block = block.next(); QVERIFY(block.isValid()); blockLayout = block.layout(); // parag 4 QCOMPARE(blockLayout->lineAt(0).x(), 0.0); }
// Constructs an iterator for the token that starts at, or contains the given position. // If there is no such token, the new iterator is invalid. TokenIterator( const QTextBlock & block, int positionInBlock ): blk(block) { if (block.isValid()) { data = static_cast<TextBlockData*>(block.userData()); idx = data ? data->tokens.size() : 0; while (idx--) { const Token & token = data->tokens[idx]; if (token.positionInBlock > positionInBlock) continue; else if (token.positionInBlock == positionInBlock || token.positionInBlock + token.length > positionInBlock) break; } } else idx = -1; }
void TestDocumentLayout::testAutoRestartList() { initForNewTest("Humans\nGandhi\nEinstein\nInventions\nCar\nToilet\nLaboratory\n"); KoParagraphStyle h1; m_styleManager->add(&h1); KoParagraphStyle h2; m_styleManager->add(&h2); KoListStyle listStyle; KoListLevelProperties llp = listStyle.levelProperties(1); llp.setStyle(KoListStyle::DecimalItem); llp.setStartValue(1); llp.setListItemSuffix("."); listStyle.setLevelProperties(llp); h1.setListStyle(&listStyle); KoListStyle listStyle2; KoListLevelProperties llp2 = listStyle2.levelProperties(2); llp2.setStyle(KoListStyle::DecimalItem); llp2.setStartValue(1); llp2.setDisplayLevel(2); llp2.setListItemSuffix("."); listStyle2.setLevelProperties(llp2); h2.setListStyle(&listStyle2); QTextBlock block = m_doc->begin(); h1.applyStyle(block); block = block.next(); h2.applyStyle(block); block = block.next(); h2.applyStyle(block); block = block.next(); h1.applyStyle(block); // inventions block = block.next(); h2.applyStyle(block); QTextBlock car = block; block = block.next(); h2.applyStyle(block); block = block.next(); h2.applyStyle(block); m_layout->layout(); KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(car.userData()); QVERIFY(data); // qDebug() << data->counterText(); QCOMPARE(data->counterText(), QString("2.1.")); }