Exemple #1
0
void TextTools::indentLessClicked()
      {
      QTextList* list = cursor()->currentList();
      if (list == 0) {
            QTextBlockFormat format = cursor()->blockFormat();
            int indent = format.indent();
            if (indent) {
                  indent--;
                  format.setIndent(indent);
                  cursor()->insertBlock(format);
                  updateText();
                  }
            return;
            }
      QTextCharFormat format = cursor()->blockCharFormat();
      QTextListFormat listFormat = list->format();
      QTextBlock block = cursor()->block();
      if (block.next().isValid())
            block = block.next();
      else {
            block = QTextBlock();
            }
      cursor()->insertBlock(block.blockFormat());
      cursor()->setCharFormat(block.charFormat());
      updateText();
      }
int QTextCopyHelper::appendFragment(int pos, int endPos, int objectIndex)
{
    QTextDocumentPrivate::FragmentIterator fragIt = src->find(pos);
    const QTextFragmentData * const frag = fragIt.value();

    Q_ASSERT(objectIndex == -1
             || (frag->size_array[0] == 1 && src->formatCollection()->format(frag->format).objectIndex() != -1));

    int charFormatIndex;
    if (forceCharFormat)
       charFormatIndex = primaryCharFormatIndex;
    else
       charFormatIndex = convertFormatIndex(frag->format, objectIndex);

    const int inFragmentOffset = qMax(0, pos - fragIt.position());
    int charsToCopy = qMin(int(frag->size_array[0] - inFragmentOffset), endPos - pos);

    QTextBlock nextBlock = src->blocksFind(pos + 1);

    int blockIdx = -2;
    if (nextBlock.position() == pos + 1) {
        blockIdx = convertFormatIndex(nextBlock.blockFormat());
    } else if (pos == 0 && insertPos == 0) {
        dst->setBlockFormat(dst->blocksBegin(), dst->blocksBegin(), convertFormat(src->blocksBegin().blockFormat()).toBlockFormat());
        dst->setCharFormat(-1, 1, convertFormat(src->blocksBegin().charFormat()).toCharFormat());
    }

    QString txtToInsert(originalText.constData() + frag->stringPosition + inFragmentOffset, charsToCopy);
    if (txtToInsert.length() == 1
        && (txtToInsert.at(0) == QChar::ParagraphSeparator
            || txtToInsert.at(0) == QTextBeginningOfFrame
            || txtToInsert.at(0) == QTextEndOfFrame
           )
       ) {
        dst->insertBlock(txtToInsert.at(0), insertPos, blockIdx, charFormatIndex);
        ++insertPos;
    } else {
        if (nextBlock.textList()) {
            QTextBlock dstBlock = dst->blocksFind(insertPos);
            if (!dstBlock.textList()) {
                // insert a new text block with the block and char format from the
                // source block to make sure that the following text fragments
                // end up in a list as they should
                int listBlockFormatIndex = convertFormatIndex(nextBlock.blockFormat());
                int listCharFormatIndex = convertFormatIndex(nextBlock.charFormat());
                dst->insertBlock(insertPos, listBlockFormatIndex, listCharFormatIndex);
                ++insertPos;
            }
        }
        dst->insert(insertPos, txtToInsert, charFormatIndex);
        const int userState = nextBlock.userState();
        if (userState != -1)
            dst->blocksFind(insertPos).setUserState(userState);
        insertPos += txtToInsert.length();
    }

    return charsToCopy;
}
void ChangeFollower::processUpdates(const QList<int> &changedStyles)
{
    KoStyleManager *sm = m_styleManager.data();
    if (!sm) {
        // since the stylemanager would be the one calling this method, I doubt this
        // will ever happen.  But better safe than sorry..
        deleteLater();
        return;
    }

    // optimization strategy;  store the formatid of the formats we checked into
    // a qset for 'hits' and 'ignores' and avoid the copying of the format
    // (fragment.charFormat() / block.blockFormat()) when the formatId is
    // already checked previosly

    QTextCursor cursor(m_document);
    QTextBlock block = cursor.block();
    while (block.isValid()) {
        QTextBlockFormat bf = block.blockFormat();
        int id = bf.intProperty(KoParagraphStyle::StyleId);
        if (id > 0 && changedStyles.contains(id)) {
            cursor.setPosition(block.position());
            KoParagraphStyle *style = sm->paragraphStyle(id);
            Q_ASSERT(style);

            style->applyStyle(bf);
            cursor.setBlockFormat(bf);
        }
        QTextCharFormat cf = block.charFormat();
        id = cf.intProperty(KoCharacterStyle::StyleId);
        if (id > 0 && changedStyles.contains(id)) {
            KoCharacterStyle *style = sm->characterStyle(id);
            Q_ASSERT(style);
            style->applyStyle(block);
        }

        QTextBlock::iterator iter = block.begin();
        while (! iter.atEnd()) {
            QTextFragment fragment = iter.fragment();
            cf = fragment.charFormat();
            id = cf.intProperty(KoCharacterStyle::StyleId);
            if (id > 0 && changedStyles.contains(id)) {
                // create selection
                cursor.setPosition(fragment.position());
                cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
                KoCharacterStyle *style = sm->characterStyle(id);
                Q_ASSERT(style);

                style->applyStyle(cf);
                cursor.mergeCharFormat(cf);
            }
            iter++;
        }
        block = block.next();
    }
}
qreal TextDocumentLayout::indentWidth(const QTextBlock &block)
{
    QRegExp exp("^[ \\t]*");
    if(exp.indexIn(block.text()) == -1)
    {
        return 0;
    }
    QFontMetrics fm(block.charFormat().font());
    return fm.width(exp.capturedTexts().at(0));
}
Exemple #5
0
void StrainPipeData::header(QTextBlock block)
{
    QTextCursor cursor=QTextCursor(block);
    QTextCharFormat headerCharF = block.charFormat();
    headerCharF.setFontPointSize(30);
    headerCharF.setFontWeight(QFont::Bold);
    cursor.setBlockCharFormat(headerCharF);

    QString header= directory.absoluteFilePath() + " results\n";
    QTextDocumentFragment headerFrag
        = QTextDocumentFragment::fromPlainText(header);
    cursor.insertFragment(headerFrag);
}
void CollectionPipeData::header(QTextBlock block)
{
    QTextCursor cursor=QTextCursor(block);
    QTextCharFormat headerCharF = block.charFormat();
    headerCharF.setFontPointSize(30);
    headerCharF.setFontWeight(QFont::Bold);
    cursor.setBlockCharFormat(headerCharF);

    QString header= "collection results";
    QTextDocumentFragment headerFrag
            = QTextDocumentFragment::fromPlainText(header);
    cursor.insertFragment(headerFrag);
}
Exemple #7
0
int VPreviewManager::calculateBlockMargin(const QTextBlock &p_block, int p_tabStopWidth)
{
    static QHash<QString, int> spaceWidthOfFonts;

    if (!p_block.isValid()) {
        return 0;
    }

    QString text = p_block.text();
    int nrSpaces = 0;
    for (int i = 0; i < text.size(); ++i) {
        if (!text[i].isSpace()) {
            break;
        } else if (text[i] == ' ') {
            ++nrSpaces;
        } else if (text[i] == '\t') {
            nrSpaces += p_tabStopWidth;
        }
    }

    if (nrSpaces == 0) {
        return 0;
    }

    int spaceWidth = 0;
    QFont font;
    QVector<QTextLayout::FormatRange> fmts = p_block.layout()->formats();
    if (fmts.isEmpty()) {
        font = p_block.charFormat().font();
    } else {
        font = fmts.first().format.font();
    }

    QString fontName = font.toString();
    auto it = spaceWidthOfFonts.find(fontName);
    if (it != spaceWidthOfFonts.end()) {
        spaceWidth = it.value();
    } else {
        spaceWidth = QFontMetrics(font).width(' ');
        spaceWidthOfFonts.insert(fontName, spaceWidth);
    }

    return spaceWidth * nrSpaces;
}
Exemple #8
0
QByteArray QGithubMarkdown::write(QTextDocument *source)
{
	QStringList output;
	bool wasInList = false;
	bool inCodeBlock = false;
	auto endCodeBlock = [&]()
	{
		if (inCodeBlock)
		{
			output.append("```\n");
		}
		inCodeBlock = false;
	};
	auto formatForPos = [&](const QTextBlock &block, const int pos) -> QTextCharFormat
	{
		for (const auto fmtRange : block.textFormats())
		{
			if (fmtRange.start <= pos && pos <= (fmtRange.start + fmtRange.length))
			{
				return fmtRange.format;
			}
		}
		Q_ASSERT(false);
		return QTextCharFormat();
	};
	auto blockToMarkdown = [&](const QTextBlock &block, const int offset = 0) -> QString
	{
		QString out;
		bool inBold = false;
		bool inItalic = false;
		QString currentLink;
		for (int i = offset; i < block.text().size(); ++i)
		{
			const QChar c = block.text().at(i);
			const QTextCharFormat fmt = formatForPos(block, i);
			if (fmt.fontItalic() != inItalic)
			{
				out.insert(out.size() - 1, '_');
				inItalic = !inItalic;
			}
			if ((fmt.fontWeight() == QFont::Bold) != inBold)
			{
				out.insert(out.size() - 1, "**");
				inBold = !inBold;
			}
			if (fmt.anchorHref().isEmpty() && !currentLink.isNull())
			{
				out.insert(out.size() - 1, "](" + currentLink + ")");
			}
			else if (!fmt.anchorHref().isEmpty() && currentLink.isNull())
			{
				out.insert(out.size() - 1, "[");
				currentLink = fmt.anchorHref();
			}
			// FIXME images
			out.append(c);
		}
		return out;
	};
	for (QTextBlock block = source->begin(); block != source->end(); block = block.next())
	{
		// heading
		if (block.charFormat().toolTip() == block.text())
		{
			endCodeBlock();
			output.append(QString(sizeMap.key(block.charFormat().fontPointSize()), '#') + " " + block.text() + "\n");
		}
		else
		{
			// list
			if (QTextList *list = block.textList())
			{
				endCodeBlock();
				const QString indent = QString((list->format().indent()-1) * 2, ' ');
				if (list->format().style() == QTextListFormat::ListDisc)
				{
					output.append(indent + "* " + blockToMarkdown(block));
				}
				else
				{
					output.append(indent + QString::number(list->itemNumber(block) + 1) + ". " + blockToMarkdown(block));
				}
				wasInList = true;
			}
			else
			{
				if (wasInList)
				{
					output.append("");
					wasInList = false;
				}
				if (block.charFormat().fontFamily() == "Monospace")
				{
					if (!inCodeBlock)
					{
						inCodeBlock = true;
						output.insert(output.size() - 1, "```");
					}
					output.append(block.text().remove("\n"));
				}
				else
				{
					endCodeBlock();
					output.append(blockToMarkdown(block) + "\n");
				}
			}
		}
	}
	QString string = output.join("\n");
	return string.trimmed().toUtf8();
}
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;
}
void TextDocumentLayout::layoutBlock(const QTextBlock &block)
{
    QTextDocument *doc = document();
    qreal margin = doc->documentMargin();
    qreal blockMaximumWidth = 0;

    qreal height = 0;
    QTextLayout *tl = block.layout();
    QTextOption option = doc->defaultTextOption();
    tl->setTextOption(option);

    int extraMargin = 0;
    if (option.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) {
        QFontMetrics fm(block.charFormat().font());
        extraMargin += fm.width(QChar(0x21B5));
    }
    tl->beginLayout();
    qreal availableWidth = d->width;
    if (availableWidth <= 0) {
        availableWidth = qreal(INT_MAX); // similar to text edit with pageSize.width == 0
    }
    availableWidth -= 2*margin + extraMargin;
    qreal indentMargin = 0;
    while (1) {
        QTextLine line = tl->createLine();
        if (!line.isValid())
            break;
        line.setLeadingIncluded(true);
        line.setLineWidth(availableWidth - indentMargin);
        line.setPosition(QPointF(margin + indentMargin, height));
        if(!height) //enter only in the first iteration
        {
            indentMargin = indentWidth(block);
        }
        height += line.height();
        blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin);
    }
    tl->endLayout();

    int previousLineCount = doc->lineCount();
    const_cast<QTextBlock&>(block).setLineCount(block.isVisible() ? tl->lineCount() : 0);
    int lineCount = doc->lineCount();

    bool emitDocumentSizeChanged = previousLineCount != lineCount;
    if (blockMaximumWidth > d->maximumWidth) {
        // new longest line
        d->maximumWidth = blockMaximumWidth;
        d->maximumWidthBlockNumber = block.blockNumber();
        emitDocumentSizeChanged = true;
    } else if (block.blockNumber() == d->maximumWidthBlockNumber && blockMaximumWidth < d->maximumWidth) {
        // longest line shrinking
        QTextBlock b = doc->firstBlock();
        d->maximumWidth = 0;
        QTextBlock maximumBlock;
        while (b.isValid()) {
            qreal blockMaximumWidth = blockWidth(b);
            if (blockMaximumWidth > d->maximumWidth) {
                d->maximumWidth = blockMaximumWidth;
                maximumBlock = b;
            }
            b = b.next();
        }
        if (maximumBlock.isValid()) {
            d->maximumWidthBlockNumber = maximumBlock.blockNumber();
            emitDocumentSizeChanged = true;
        }
    }
    if (emitDocumentSizeChanged)// && !d->blockDocumentSizeChanged)
        emit documentSizeChanged(documentSize());

    emit updateBlock(block);
}
Exemple #11
0
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));
}