/*! \fn QString QTextList::itemText(const QTextBlock &block) const Returns the text of the list item that corresponds to the given \a block. */ QString QTextList::itemText(const QTextBlock &blockIt) const { Q_D(const QTextList); int item = d->blocks.indexOf(blockIt) + 1; if (item <= 0) return QString(); QTextBlock block = d->blocks.at(item-1); QTextBlockFormat blockFormat = block.blockFormat(); QString result; const int style = format().style(); QString numberPrefix; QString numberSuffix = QLatin1String("."); if (format().hasProperty(QTextFormat::ListNumberPrefix)) numberPrefix = format().numberPrefix(); if (format().hasProperty(QTextFormat::ListNumberSuffix)) numberSuffix = format().numberSuffix(); switch (style) { case QTextListFormat::ListDecimal: result = QString::number(item); break; // from the old richtext case QTextListFormat::ListLowerAlpha: case QTextListFormat::ListUpperAlpha: { const char baseChar = style == QTextListFormat::ListUpperAlpha ? 'A' : 'a'; int c = item; while (c > 0) { c--; result.prepend(QChar(baseChar + (c % 26))); c /= 26; } } break; case QTextListFormat::ListLowerRoman: case QTextListFormat::ListUpperRoman: { if (item < 5000) { QByteArray romanNumeral; // works for up to 4999 items static const char romanSymbolsLower[] = "iiivixxxlxcccdcmmmm"; static const char romanSymbolsUpper[] = "IIIVIXXXLXCCCDCMMMM"; QByteArray romanSymbols; // wrap to have "mid" if (style == QTextListFormat::ListLowerRoman) romanSymbols = QByteArray::fromRawData(romanSymbolsLower, sizeof(romanSymbolsLower)); else romanSymbols = QByteArray::fromRawData(romanSymbolsUpper, sizeof(romanSymbolsUpper)); int c[] = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 }; int n = item; for (int i = 12; i >= 0; n %= c[i], i--) { int q = n / c[i]; if (q > 0) { int startDigit = i + (i+3)/4; int numDigits; if (i % 4) { // c[i] == 4|5|9|40|50|90|400|500|900 if ((i-2) % 4) { // c[i] == 4|9|40|90|400|900 => with subtraction (IV, IX, XL, XC, ...) numDigits = 2; } else { // c[i] == 5|50|500 (V, L, D) numDigits = 1; } } else { // c[i] == 1|10|100|1000 (I, II, III, X, XX, ...) numDigits = q; } romanNumeral.append(romanSymbols.mid(startDigit, numDigits)); } } result = QString::fromLatin1(romanNumeral); } else { result = QLatin1String("?"); } } break; default: Q_ASSERT(false); } if (blockIt.textDirection() == Qt::RightToLeft) return numberSuffix + result + numberPrefix; else return numberPrefix + result + numberSuffix; }
void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QTextBlock &block, const QPointF &position, const QColor &textColor, const QColor &anchorColor, int selectionStart, int selectionEnd) { Q_ASSERT(textDocument); #ifndef QT_NO_IM int preeditLength = block.isValid() ? block.layout()->preeditAreaText().length() : 0; int preeditPosition = block.isValid() ? block.layout()->preeditAreaPosition() : -1; #endif QVarLengthArray<QTextLayout::FormatRange> colorChanges; mergeFormats(block.layout(), &colorChanges); QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft() + position; if (QTextList *textList = block.textList()) { QPointF pos = blockPosition; QTextLayout *layout = block.layout(); if (layout->lineCount() > 0) { QTextLine firstLine = layout->lineAt(0); Q_ASSERT(firstLine.isValid()); setCurrentLine(firstLine); QRectF textRect = firstLine.naturalTextRect(); pos += textRect.topLeft(); if (block.textDirection() == Qt::RightToLeft) pos.rx() += textRect.width(); const QTextCharFormat charFormat = block.charFormat(); QFont font(charFormat.font()); QFontMetricsF fontMetrics(font); QTextListFormat listFormat = textList->format(); QString listItemBullet; switch (listFormat.style()) { case QTextListFormat::ListCircle: listItemBullet = QChar(0x25E6); // White bullet break; case QTextListFormat::ListSquare: listItemBullet = QChar(0x25AA); // Black small square break; case QTextListFormat::ListDecimal: case QTextListFormat::ListLowerAlpha: case QTextListFormat::ListUpperAlpha: case QTextListFormat::ListLowerRoman: case QTextListFormat::ListUpperRoman: listItemBullet = textList->itemText(block); break; default: listItemBullet = QChar(0x2022); // Black bullet break; }; QSizeF size(fontMetrics.width(listItemBullet), fontMetrics.height()); qreal xoff = fontMetrics.width(QLatin1Char(' ')); if (block.textDirection() == Qt::LeftToRight) xoff = -xoff - size.width(); setPosition(pos + QPointF(xoff, 0)); QTextLayout layout; layout.setFont(font); layout.setText(listItemBullet); // Bullet layout.beginLayout(); QTextLine line = layout.createLine(); line.setPosition(QPointF(0, 0)); layout.endLayout(); QList<QGlyphRun> glyphRuns = layout.glyphRuns(); for (int i=0; i<glyphRuns.size(); ++i) addUnselectedGlyphs(glyphRuns.at(i)); } } int textPos = block.position(); QTextBlock::iterator blockIterator = block.begin(); while (!blockIterator.atEnd()) { QTextFragment fragment = blockIterator.fragment(); QString text = fragment.text(); if (text.isEmpty()) continue; QTextCharFormat charFormat = fragment.charFormat(); QFont font(charFormat.font()); QFontMetricsF fontMetrics(font); int fontHeight = fontMetrics.descent() + fontMetrics.ascent(); int valign = charFormat.verticalAlignment(); if (valign == QTextCharFormat::AlignSuperScript) setPosition(QPointF(blockPosition.x(), blockPosition.y() - fontHeight / 2)); else if (valign == QTextCharFormat::AlignSubScript) setPosition(QPointF(blockPosition.x(), blockPosition.y() + fontHeight / 6)); else setPosition(blockPosition); if (text.contains(QChar::ObjectReplacementCharacter)) { QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat)); if (frame && frame->frameFormat().position() == QTextFrameFormat::InFlow) { int blockRelativePosition = textPos - block.position(); QTextLine line = block.layout()->lineForTextPosition(blockRelativePosition); if (!currentLine().isValid() || line.lineNumber() != currentLine().lineNumber()) { setCurrentLine(line); } QQuickTextNodeEngine::SelectionState selectionState = (selectionStart < textPos + text.length() && selectionEnd >= textPos) ? QQuickTextNodeEngine::Selected : QQuickTextNodeEngine::Unselected; addTextObject(QPointF(), charFormat, selectionState, textDocument, textPos); } textPos += text.length(); } else { if (charFormat.foreground().style() != Qt::NoBrush) setTextColor(charFormat.foreground().color()); else if (charFormat.isAnchor()) setTextColor(anchorColor); else setTextColor(textColor); int fragmentEnd = textPos + fragment.length(); #ifndef QT_NO_IM if (preeditPosition >= 0 && (preeditPosition + block.position()) >= textPos && (preeditPosition + block.position()) <= fragmentEnd) { fragmentEnd += preeditLength; } #endif if (charFormat.background().style() != Qt::NoBrush) { QTextLayout::FormatRange additionalFormat; additionalFormat.start = textPos - block.position(); additionalFormat.length = fragmentEnd - textPos; additionalFormat.format = charFormat; colorChanges << additionalFormat; } textPos = addText(block, charFormat, textColor, colorChanges, textPos, fragmentEnd, selectionStart, selectionEnd); } ++blockIterator; } #ifndef QT_NO_IM if (preeditLength >= 0 && textPos <= block.position() + preeditPosition) { setPosition(blockPosition); textPos = block.position() + preeditPosition; QTextLine line = block.layout()->lineForTextPosition(preeditPosition); if (!currentLine().isValid() || line.lineNumber() != currentLine().lineNumber()) { setCurrentLine(line); } textPos = addText(block, block.charFormat(), textColor, colorChanges, textPos, textPos + preeditLength, selectionStart, selectionEnd); } #endif setCurrentLine(QTextLine()); // Reset current line because the text layout changed m_hasContents = true; }