/*!
    Makes the given \a block part of the list.

    \sa remove(), removeItem()
*/
void QTextList::add(const QTextBlock &block)
{
    QTextBlockFormat fmt = block.blockFormat();
    fmt.setObjectIndex(objectIndex());
    block.docHandle()->setBlockFormat(block, block, fmt, QTextDocumentPrivate::SetFormat);
}
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());
}
Beispiel #3
0
void TestDocumentLayout::testNumberedList()
{
    initForNewTest("Base\nListItem1\nListItem2\nListItem3\nListItem4\nListItem5\nListItem6\nListItem6\nListItem7\nListItem8\nListItem9\nListItem10\nListItem11\nListItem12\n");

    KoParagraphStyle style;
    m_styleManager->add(&style);
    QTextBlock block = m_doc->begin();
    style.applyStyle(block);
    block = block.next();

    KoListStyle listStyle;
    KoListLevelProperties llp;
    llp.setStyle(KoListStyle::DecimalItem);
    listStyle.setLevelProperties(llp);
    style.setListStyle(&listStyle);

    QTextList *previous = 0;
    int i;
    for (i = 1; i <= 9; i++) {
        QVERIFY(block.isValid());
        // qDebug() << "->" << block.text();
        style.applyStyle(block);
        QTextList *textList = block.textList();
        QVERIFY(textList);
        if (previous == 0) {
            previous = textList;
        } else {
            QCOMPARE(textList, previous);
        }
        QCOMPARE(textList->format().intProperty(QTextListFormat::ListStyle), (int)(KoListStyle::DecimalItem));
        block = block.next();
    }
    m_layout->layout();
    QTextLayout *blockLayout = m_block.layout();

    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
    QTextBlock blok = m_doc->begin().next();
    qreal indent = blok.layout()->lineAt(0).x();
    QVERIFY(indent > 0.0);
    for (i = 1; i <= 9; ++i) {
        // qDebug() << "=>" << blok.text();
        QTextList *textList = blok.textList();
        QVERIFY(textList);
        QCOMPARE(blok.layout()->lineAt(0).x(), indent); // all the same indent.
        blok = blok.next();
    }

    // now make number of listitems be more than 10, so we use 2 digits.
    for (i = 9; i <= 12; ++i) {
        QVERIFY(block.isValid());
        style.applyStyle(block);
        // qDebug() << "->" << block.text();
        block = block.next();
    }
    m_layout->layout();
    blockLayout = m_block.layout();

    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
    blok = m_doc->begin().next();
    qreal indent2 = blok.layout()->lineAt(0).x();
    QVERIFY(indent2 > indent); // since it takes an extra digit
    for (i = 2; i <= 12; ++i) {
        // qDebug() << "=>" << blok.text();
        QCOMPARE(blok.layout()->lineAt(0).x(), indent2); // all the same indent.
        blok = blok.next();
    }

    // now to make sure the text is actually properly set.
    block = m_doc->begin().next();
    i = 1;
    while (block.isValid() && i < 13) {
        KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
        QVERIFY(data);
        QCOMPARE(data->counterText(), QString::number(i++));
        block = block.next();
    }

    llp.setListItemSuffix(".");
    llp.setStartValue(4);
    listStyle.setLevelProperties(llp);

    QTextCursor cursor(m_doc);
    cursor.setPosition(10); // listItem1
    QTextBlockFormat format = cursor.blockFormat();
    format.setProperty(KoParagraphStyle::ListStartValue, 4);
    cursor.setBlockFormat(format);

    cursor.setPosition(40); // listItem4
    format = cursor.blockFormat();
    format.setProperty(KoParagraphStyle::ListStartValue, 12);
    cursor.setBlockFormat(format);

    // at this point we start numbering at 4. Have 4, 5, 6, 12, 13, 14, 15 etc
    m_layout->layout();

    // now to make sur the text is actually properly set.
    block = m_doc->begin().next();
    i = 4;
    while (block.isValid() && i < 22) {
        if (i == 7) {
            i = 12;
        }
        KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
        QVERIFY(data);
        QCOMPARE(data->counterText(), QString::number(i++));
        block = block.next();
    }
}
QString FlatTextarea::getText(int32 start, int32 end) const {
	if (end >= 0 && end <= start) return QString();

	if (start < 0) start = 0;
	bool full = (start == 0) && (end < 0);

	QTextDocument *doc(document());
	QTextBlock from = full ? doc->begin() : doc->findBlock(start), till = (end < 0) ? doc->end() : doc->findBlock(end);
	if (till.isValid()) till = till.next();

	int32 possibleLen = 0;
	for (QTextBlock b = from; b != till; b = b.next()) {
		possibleLen += b.length();
	}
	QString result;
	result.reserve(possibleLen + 1);
	if (!full && end < 0) {
		end = possibleLen;
	}

	for (QTextBlock b = from; b != till; b = b.next()) {
		for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) {
			QTextFragment fragment(iter.fragment());
			if (!fragment.isValid()) continue;

			int32 p = full ? 0 : fragment.position(), e = full ? 0 : (p + fragment.length());
			if (!full) {
				if (p >= end || e <= start) {
					continue;
				}
			}

			QTextCharFormat f = fragment.charFormat();
			QString emojiText;
			QString t(fragment.text());
			if (!full) {
				if (p < start) {
					t = t.mid(start - p, end - start);
				} else if (e > end) {
					t = t.mid(0, end - p);
				}
			}
			QChar *ub = t.data(), *uc = ub, *ue = uc + t.size();
			for (; uc != ue; ++uc) {
				switch (uc->unicode()) {
				case 0xfdd0: // QTextBeginningOfFrame
				case 0xfdd1: // QTextEndOfFrame
				case QChar::ParagraphSeparator:
				case QChar::LineSeparator:
					*uc = QLatin1Char('\n');
					break;
				case QChar::Nbsp:
					*uc = QLatin1Char(' ');
					break;
				case QChar::ObjectReplacementCharacter:
					if (emojiText.isEmpty() && f.isImageFormat()) {
						QString imageName = static_cast<QTextImageFormat*>(&f)->name();
						if (imageName.startsWith(QLatin1String("emoji://e."))) {
							if (EmojiPtr emoji = emojiFromUrl(imageName)) {
								emojiText = textEmojiString(emoji);
							}
						}
					}
					if (uc > ub) result.append(ub, uc - ub);
					if (!emojiText.isEmpty()) result.append(emojiText);
					ub = uc + 1;
				break;
				}
			}
			if (uc > ub) result.append(ub, uc - ub);
		}
		result.append('\n');
	}
	result.chop(1);
	return result;
}
Beispiel #5
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();
}
Beispiel #6
0
void CodeArea::keyPressEvent(QKeyEvent *e)
{

    if (mCompleter && mCompleter->popup()->isVisible())
    {
             // The following keys are forwarded by the completer to the widget
            switch (e->key())
            {
                case Qt::Key_Enter:
                case Qt::Key_Return:
                case Qt::Key_Escape:
                case Qt::Key_Tab:
                case Qt::Key_Backtab:
                     e->ignore();
                     return; // let the completer do default behavior
                default:
                    break;
            }
    }

    {
       switch (e->key()) {
       case Qt::Key_Tab:
       {
           QTextCursor tc = textCursor();
           if(tc.hasSelection())
           {

           }
           if(!(e->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier)))
           {
               this->insertPlainText("    ");
               QTextCursor tc = textCursor();
               tc.setPosition(tc.position());
               setTextCursor(tc);
               return;
           }

       }
       case Qt::Key_Backtab:
       {
           QTextCursor tc = textCursor();

           QTextBlock tb = tc.block();
           QString str = tb.text();
           int space = 4;
           tc.movePosition(QTextCursor::StartOfLine);
           foreach(QString s, str)
           {
               if(s == " "&& space!=0)
               {
                   space--;
                   tc.movePosition(QTextCursor::Right);
                   tc.deletePreviousChar();

               }
               else
                   break;
           }
           return;
       }
       case Qt::Key_Return:
       {
           QTextCursor tc = textCursor();
           QTextBlock tb = tc.block();
           QString str = tb.text();
           int space = 0;
           foreach(QString s, str)
           {
               if(s == " ")
                   space++;
               else
                   break;
           }
           insertPlainText("\n");
           for(int x= 0; x <space;++x)
               insertPlainText(" ");
           tc.movePosition(QTextCursor::EndOfLine);
           setTextCursor(tc);
           e->accept();
           return;
       }
       default:
           break;
       }
    }

    bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_Space); // CTRL+E
    if (!mCompleter || !isShortcut) // do not process the shortcut when we have a completer
        QPlainTextEdit::keyPressEvent(e);

    const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
    if (!mCompleter || (ctrlOrShift && e->text().isEmpty()))
        return;

    static QString eow("~!@#$%^&*_+(){}|\"<>?,:./;'[]\\-="); // end of word
    bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;
    QString completionPrefix = textUnderCursor();
    /*if(completionPrefix.endsWith(")"))
    {
        completionPrefix.remove(completionPrefix.size()-1);
    }*/

    if (!isShortcut && (hasModifier || e->text().isEmpty()|| completionPrefix.length() < 3
                      || eow.contains(e->text().right(1)))) {
        mCompleter->popup()->hide();
        return;
    }

    if (completionPrefix != mCompleter->completionPrefix()) {
        mCompleter->setCompletionPrefix(completionPrefix);
        mCompleter->popup()->setCurrentIndex(mCompleter->completionModel()->index(0, 0));
    }
    QRect cr = cursorRect();
    cr.setWidth(mCompleter->popup()->sizeHintForColumn(0)
                + mCompleter->popup()->verticalScrollBar()->sizeHint().width());
    mCompleter->complete(cr); // popup it up!
}
void QFCompleterTextEditNumberBar::paintEvent(QPaintEvent */*event*/) {
    QTextDocument* doc=editor->document();
    QAbstractTextDocumentLayout *layout = doc->documentLayout();
    qreal yPosition=editor->verticalScrollBar()->value();
    qreal vpHeight=editor->viewport()->height();

    QPainter p(this);
    p.setFont(linenumberFont);
    int linenumberWidth=QString::number(doc->blockCount()).size()*p.fontMetrics().width("0")+4;
    int markerheight=p.fontMetrics().ascent()+2;

    // set the width of the widget
    setFixedWidth(linenumberWidth+markerWidth+2);

    // first we draw the background
    p.setBrush(QBrush(linenumberColumnColor));
    p.setPen(QPen(linenumberColumnColor));
    p.drawRect(0,0,width(),vpHeight);
    p.setPen(QPen(markerColumnColor));
    p.setBrush(QBrush(markerColumnColor));
    p.drawRect(linenumberWidth,0,width()-linenumberWidth,vpHeight);

    // reset the rect of all markers
    QMutableMapIterator<int, itemData> i(markers);
    while (i.hasNext()) {
        i.next();
        itemData d=i.value();
        d.rect=QRect(0,0,0,0);
        i.setValue(d);
    }

    // now we draw the line numbers
    p.setPen(QPen(linenumberColor));
    for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) {
        QRectF brect=layout->blockBoundingRect(it);
        qreal bottompos=brect.y()+brect.height();
        markerheight=brect.height()-8;
        // we end this loop if the current block lies below the viewport
        if (brect.y() > yPosition+ vpHeight)
            break;
        // if we are inside the viewport, we have to paint a line number for this line
        if (bottompos >= yPosition) {
            QString txt = QString::number(it.blockNumber()+1);
            p.drawText(1, brect.y()-yPosition, linenumberWidth-2, brect.height(), Qt::AlignRight|Qt::AlignVCenter, txt);
            if (markers.contains(it.blockNumber()+1)) {
                itemData d=markers[it.blockNumber()+1];
                QRect markerrect=QRect(linenumberWidth+2, brect.y()-yPosition+4, width()-linenumberWidth-4, markerheight);
                markers[it.blockNumber()+1].rect=markerrect;
                if (d.type==mtInfo) {
                    //p.drawImage(linenumberWidth+2, brect.y()-yPosition, QIcon(":/event_info.png"));
                    p.setBrush(infoMarkerColor);
                    QPen pe=p.pen();
                    pe.setColor(QColor("black"));
                    pe.setCosmetic(true);
                    pe.setWidth(1);
                    p.setPen(pe);
                    p.drawRect(markerrect);
                } else if (d.type==mtError) {
                    //p.drawImage(linenumberWidth+2, brect.y()-yPosition, QIcon(":/event_error.png"));
                    p.setBrush(errorMarkerColor);
                    QPen pe=p.pen();
                    pe.setColor(QColor("black"));
                    pe.setCosmetic(true);
                    pe.setWidth(1);
                    p.setPen(pe);
                    p.drawRect(markerrect);
                } else {
                    //p.drawImage(linenumberWidth+2, brect.y()-yPosition, QIcon(":/event_warning.png"));
                    p.setBrush(warningMarkerColor);
                    QPen pe=p.pen();
                    pe.setColor(QColor("black"));
                    pe.setCosmetic(true);
                    pe.setWidth(1);
                    p.setPen(pe);
                    p.drawRect(markerrect);
                }
            }
        }
    }

}
Beispiel #8
0
void GenericCodeEditor::paintLineIndicator( QPaintEvent *e )
{
    QPalette plt( mLineIndicator->palette() );
    QRect r( e->rect() );
    QPainter p( mLineIndicator );

    p.fillRect( r, plt.color( QPalette::Mid ) );
    p.setPen( plt.color(QPalette::Dark) );
    p.drawLine( r.topRight(), r.bottomRight() );

    p.setPen( plt.color(QPalette::ButtonText) );

    QTextDocument *doc = QPlainTextEdit::document();
    QTextCursor cursor(textCursor());
    int selStartBlock, selEndBlock;
    if (cursor.hasSelection()) {
        selStartBlock = doc->findBlock(cursor.selectionStart()).blockNumber();
        selEndBlock = doc->findBlock(cursor.selectionEnd()).blockNumber();
    }
    else
        selStartBlock = selEndBlock = -1;

    QTextBlock block = firstVisibleBlock();
    int blockNumber = block.blockNumber();
    qreal top = blockBoundingGeometry(block).translated(contentOffset()).top();
    qreal bottom = top + blockBoundingRect(block).height();

    while (block.isValid() && top <= e->rect().bottom()) {
        if (block.isVisible() && bottom >= e->rect().top()) {
            p.save();

            QRectF numRect( 0, top, mLineIndicator->width() - 1, bottom - top );

            int num = blockNumber;
            if (num >= selStartBlock && num <= selEndBlock) {
                num -= selStartBlock;
                p.setPen(Qt::NoPen);
                p.setBrush(plt.color(QPalette::Highlight));
                p.drawRect(numRect);
                p.setPen(plt.color(QPalette::HighlightedText));
            }

            QString number = QString::number(num + 1);
            p.drawText(0, top, mLineIndicator->width() - 4, bottom - top,
                       Qt::AlignRight, number);

            p.restore();
        }

        block = block.next();
        top = bottom;
        bottom = top + blockBoundingRect(block).height();
        ++blockNumber;
    }
    
    if(!mEditorBoxIsActive) {
        QColor color = plt.color(QPalette::Mid);
        if(color.lightness() >= 128)
            color = color.darker(60);
        else
            color = color.lighter(50);
        
        color.setAlpha(inactiveFadeAlpha());
        p.fillRect( r, color );
    }
}
Beispiel #9
0
QString KTextEditingPlugin::paragraph(QTextDocument *document, int cursorPosition) const
{
    QTextBlock block = document->findBlock(cursorPosition);
    return block.text();
}
Beispiel #10
0
void InputField::processDocumentContentsChange(int position, int charsAdded) {
	int32 emojiPosition = 0, emojiLen = 0;
	const EmojiData *emoji = 0;

	static QString space(' ');

	QTextDocument *doc(_inner.document());
	QTextCursor c(_inner.textCursor());
	c.joinPreviousEditBlock();
	while (true) {
		int32 start = position, end = position + charsAdded;
		QTextBlock from = doc->findBlock(start), till = doc->findBlock(end);
		if (till.isValid()) till = till.next();

		for (QTextBlock b = from; b != till; b = b.next()) {
			for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) {
				QTextFragment fragment(iter.fragment());
				if (!fragment.isValid()) continue;

				int32 fp = fragment.position(), fe = fp + fragment.length();
				if (fp >= end || fe <= start) {
					continue;
				}

				QString t(fragment.text());
				const QChar *ch = t.constData(), *e = ch + t.size();
				for (; ch != e; ++ch) {
					// QTextBeginningOfFrame // QTextEndOfFrame
					if (ch->unicode() == 0xfdd0 || ch->unicode() == 0xfdd1 || ch->unicode() == QChar::ParagraphSeparator || ch->unicode() == QChar::LineSeparator || ch->unicode() == '\n' || ch->unicode() == '\r') {
						if (!_inner.document()->pageSize().isNull()) {
							_inner.document()->setPageSize(QSizeF(0, 0));
						}
						int32 nlPosition = fp + (ch - t.constData());
						QTextCursor c(doc->docHandle(), nlPosition);
						c.setPosition(nlPosition + 1, QTextCursor::KeepAnchor);
						c.insertText(space);
						position = nlPosition + 1;
						emoji = TwoSymbolEmoji; // just a flag
						break;
					}
					emoji = emojiFromText(ch, e, emojiLen);
					if (emoji) {
						emojiPosition = fp + (ch - t.constData());
						break;
					}
					if (ch + 1 < e && ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) ++ch;
				}
				if (emoji) break;
			}
			if (emoji) break;
			if (b.next() != doc->end()) {
				int32 nlPosition = b.next().position() - 1;
				QTextCursor c(doc->docHandle(), nlPosition);
				c.setPosition(nlPosition + 1, QTextCursor::KeepAnchor);
				c.insertText(space);
				position = nlPosition + 1;
				emoji = TwoSymbolEmoji; // just a flag
				break;
			}
		}
		if (emoji == TwoSymbolEmoji) { // just skip
			emoji = 0;
			emojiPosition = 0;
		} else if (emoji) {
			if (!_inner.document()->pageSize().isNull()) {
				_inner.document()->setPageSize(QSizeF(0, 0));
			}

			QTextCursor c(doc->docHandle(), emojiPosition);
			c.setPosition(emojiPosition + emojiLen, QTextCursor::KeepAnchor);
			int32 removedUpto = c.position();

			insertEmoji(emoji, c);

			for (Insertions::iterator i = _insertions.begin(), e = _insertions.end(); i != e; ++i) {
				if (i->first >= removedUpto) {
					i->first -= removedUpto - emojiPosition - 1;
				} else if (i->first >= emojiPosition) {
					i->second -= removedUpto - emojiPosition;
					i->first = emojiPosition + 1;
				} else if (i->first + i->second > emojiPosition + 1) {
					i->second -= qMin(removedUpto, i->first + i->second) - emojiPosition;
				}
			}

			charsAdded -= removedUpto - position;
			position = emojiPosition + 1;

			emoji = 0;
			emojiPosition = 0;
		} else {
			break;
		}
	}
	c.endEditBlock();
}
Beispiel #11
0
void QSyntaxHighlighterPrivate::_q_reformatBlocks(int from, int charsRemoved, int charsAdded)
{
    Q_UNUSED(charsRemoved);
    rehighlightPending = false;

    QTextBlock block = doc->findBlock(from);
    if (!block.isValid())
        return;

    int endPosition;
    QTextBlock lastBlock = doc->findBlock(from + charsAdded);
    if (lastBlock.isValid())
        endPosition = lastBlock.position() + lastBlock.length();
    else
        endPosition = doc->docHandle()->length();

    bool forceHighlightOfNextBlock = false;

    while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) {
        const int stateBeforeHighlight = block.userState();

        reformatBlock(block);

        forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight);

        block = block.next();
    }

    formatChanges.clear();
}
void QTextCopyHelper::copy()
{
    if (cursor.hasComplexSelection()) {
        QTextTable *table = cursor.currentTable();
        int row_start, col_start, num_rows, num_cols;
        cursor.selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);

        QTextTableFormat tableFormat = table->format();
        tableFormat.setColumns(num_cols);
        tableFormat.clearColumnWidthConstraints();
        const int objectIndex = dst->formatCollection()->createObjectIndex(tableFormat);

        Q_ASSERT(row_start != -1);
        for (int r = row_start; r < row_start + num_rows; ++r) {
            for (int c = col_start; c < col_start + num_cols; ++c) {
                QTextTableCell cell = table->cellAt(r, c);
                const int rspan = cell.rowSpan();
                const int cspan = cell.columnSpan();
                if (rspan != 1) {
                    int cr = cell.row();
                    if (cr != r)
                        continue;
                }
                if (cspan != 1) {
                    int cc = cell.column();
                    if (cc != c)
                        continue;
                }

                // add the QTextBeginningOfFrame
                QTextCharFormat cellFormat = cell.format();
                if (r + rspan >= row_start + num_rows) {
                    cellFormat.setTableCellRowSpan(row_start + num_rows - r);
                }
                if (c + cspan >= col_start + num_cols) {
                    cellFormat.setTableCellColumnSpan(col_start + num_cols - c);
                }
                const int charFormatIndex = convertFormatIndex(cellFormat, objectIndex);

                int blockIdx = -2;
                const int cellPos = cell.firstPosition();
                QTextBlock block = src->blocksFind(cellPos);
                if (block.position() == cellPos) {
                    blockIdx = convertFormatIndex(block.blockFormat());
                }

                dst->insertBlock(QTextBeginningOfFrame, insertPos, blockIdx, charFormatIndex);
                ++insertPos;

                // nothing to add for empty cells
                if (cell.lastPosition() > cellPos) {
                    // add the contents
                    appendFragments(cellPos, cell.lastPosition());
                }
            }
        }

        // add end of table
        int end = table->lastPosition();
        appendFragment(end, end+1, objectIndex);
    } else {
        appendFragments(cursor.selectionStart(), cursor.selectionEnd());
    }
}
void CodeFoldingPanel::paintEvent(QPaintEvent *e)
{
    QTextDocument *doc = editorWidget()->document();
    TextDocumentLayout *documentLayout = qobject_cast<TextDocumentLayout*>(doc->documentLayout());
    if(!documentLayout)
        return;

    QPalette pal = areaWidget()->palette();
    pal.setCurrentColorGroup(QPalette::Active);
    QPainter painter(this);
    const QFontMetrics fm(areaWidget()->font());

    const int collapseColumnWidth = d->m_codeFoldingVisible ? foldBoxWidth(fm): 0;
    const int extraAreaWidth = d->m_extraArea->width() - collapseColumnWidth;

    painter.fillRect(e->rect(), pal.color(QPalette::Background));

    QTextBlock block = editorWidget()->firstVisibleBlock();
    int blockNumber = block.blockNumber();
    qreal top = editorWidget()->blockBoundingGeometry(block).translated(editorWidget()->contentOffset()).top();
    qreal bottom = top;

    while (block.isValid() && top <= e->rect().bottom()) {

        top = bottom;
        const qreal height = editorWidget()->blockBoundingRect(block).height();
        bottom = top + height;
        QTextBlock nextBlock = block.next();

        QTextBlock nextVisibleBlock = nextBlock;
        int nextVisibleBlockNumber = blockNumber + 1;

        if (!nextVisibleBlock.isVisible()) {
            // invisible blocks do have zero line count
            nextVisibleBlock = doc->findBlockByLineNumber(nextVisibleBlock.firstLineNumber());
            nextVisibleBlockNumber = nextVisibleBlock.blockNumber();
        }

        if (bottom < e->rect().top()) {
            block = nextVisibleBlock;
            blockNumber = nextVisibleBlockNumber;
            continue;
        }

        painter.setPen(pal.color(QPalette::Dark));

        painter.save();
        painter.setRenderHint(QPainter::Antialiasing, false);

        int extraAreaHighlightFoldBlockNumber = -1;
        int extraAreaHighlightFoldEndBlockNumber = -1;
        bool endIsVisible = false;
        if (!d->m_highlightBlocksInfo.isEmpty()) {
            extraAreaHighlightFoldBlockNumber =  d->m_highlightBlocksInfo.open.last();
            extraAreaHighlightFoldEndBlockNumber =  d->m_highlightBlocksInfo.close.first();
            endIsVisible = doc->findBlockByNumber(extraAreaHighlightFoldEndBlockNumber).isVisible();

//                    QTextBlock before = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber-1);
//                    if (TextBlockUserData::hasCollapseAfter(before)) {
//                        extraAreaHighlightCollapseBlockNumber--;
//                    }
        }

        TextBlockUserData *nextBlockUserData = TextDocumentLayout::testUserData(nextBlock);

        bool drawBox = nextBlockUserData
                       && TextDocumentLayout::foldingIndent(block) < nextBlockUserData->foldingIndent();



        bool active = blockNumber == extraAreaHighlightFoldBlockNumber;

        bool drawStart = active;
        bool drawEnd = blockNumber == extraAreaHighlightFoldEndBlockNumber || (drawStart && !endIsVisible);
        bool hovered = blockNumber >= extraAreaHighlightFoldBlockNumber
                       && blockNumber <= extraAreaHighlightFoldEndBlockNumber;

        int boxWidth = foldBoxWidth(fm);
        if (hovered) {
            int itop = qRound(top);
            int ibottom = qRound(bottom);
            QRect box = QRect(extraAreaWidth + 1, itop, boxWidth - 2, ibottom - itop);
            drawRectBox(&painter, box, drawStart, drawEnd, pal);
        }

        if (drawBox) {
            bool expanded = nextBlock.isVisible();
            int size = boxWidth/4;
            QRect box(extraAreaWidth + size, top + size,
                      2 * (size) + 1, 2 * (size) + 1);
            d->drawFoldingMarker(&painter, pal, box, expanded, active, hovered);
        }


        painter.restore();

        block = nextVisibleBlock;
        blockNumber = nextVisibleBlockNumber;
    }
}
Beispiel #14
0
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());
}
IAssistProposal *QssCompletionAssistProcessor::perform(const IAssistInterface *interface)
{
    m_interface.reset(interface);

    if (isInComment())
        return 0;

    if (interface->reason() == IdleEditor && !acceptsIdleEditor())
        return 0;

    if (m_startPosition == -1)
        m_startPosition = findStartOfName();

    QTextBlock block = interface->textDocument()->findBlock(interface->position());
    QTextBlock prevBlock = block.previous();
    Lexer lexer;
    Parser parser;
    if (prevBlock.isValid()) {
        lexer.setState(qssLexerState(prevBlock.userState()));
        parser.setState(qssParserState(prevBlock.userState()));
    }
    QList<Token> tokenList = lexer.scanMore(block.text());
    int index = m_startPosition - block.position();
    Q_FOREACH (const Token &t, tokenList) {
        if (index <= t.begin())
            break;
        parser.parseMore(t);
    }
    QStringList keywords;
    QIcon icon;
    switch (parser.state()) {
    case Parser::ObjectState:
        keywords << Lexer::objects();
        icon = QIcon(":/qsseditor/images/class.png");
        break;
    case Parser::PseudoStatesState:
        keywords << Lexer::pseudoStates();
        icon = QIcon(":/qsseditor/images/func.png");
        break;
    case Parser::SubControlState:
        keywords << Lexer::subControls();
        icon = QIcon(":/qsseditor/images/func.png");
        break;
    case Parser::AttributeNameState:
        keywords << Lexer::attributeNames();
        icon = QIcon(":/qsseditor/images/var.png");
        break;
    case Parser::AttributeBodyState:
        keywords << Lexer::attributeCtors() << Lexer::attributeKeywords();
        icon = QIcon(":/qsseditor/images/keyword.png");
        break;
    default:
        ;
    }
    keywords.removeDuplicates();
    QList<TextEditor::BasicProposalItem *> items;
    for (int i = 0; i < keywords.count(); i++) {
        BasicProposalItem *item = new QssAssistProposalItem;
        item->setText(keywords[i]);
        item->setIcon(icon);
        items.append(item);
    }
    return new GenericProposal(m_startPosition, new QssAssistProposalModel(items));
}
/*
    Returns the recommended indent for the bottom line of program.
    Unless null, typedIn stores the character of yyProgram that
    triggered reindentation.

    This function works better if typedIn is set properly; it is
    slightly more conservative if typedIn is completely wild, and
    slighly more liberal if typedIn is always null. The user might be
    annoyed by the liberal behavior.
*/
int QmlJSIndenter::indentForBottomLine(QTextBlock begin, QTextBlock end, QChar typedIn)
{
    if (begin == end)
        return 0;

    const QTextBlock last = end.previous();

    initialize(begin, last);

    QString bottomLine = last.text();
    QChar firstCh = firstNonWhiteSpace(bottomLine);
    int indent = 0;

    if (bottomLineStartsInMultilineComment()) {
        /*
            The bottom line starts in a C-style comment. Indent it
            smartly, unless the user has already played around with it,
            in which case it's better to leave her stuff alone.
        */
        if (isOnlyWhiteSpace(bottomLine))
            indent = indentWhenBottomLineStartsInMultiLineComment();
        else
            indent = indentOfLine(bottomLine);
    } else {
        if (isUnfinishedLine())
            indent = indentForContinuationLine();
        else
            indent = indentForStandaloneLine();

        if ((okay(typedIn, QLatin1Char('}')) && firstCh == QLatin1Char('}'))
            || (okay(typedIn, QLatin1Char(']')) && firstCh == QLatin1Char(']'))) {
            /*
                A closing brace is one level more to the left than the
                code it follows.
            */
            indent -= ppIndentSize;
        } else if (okay(typedIn, QLatin1Char(':'))) {
            if (caseOrDefault.exactMatch(bottomLine)) {
                /*
                    Move a case label (or the ':' in front of a
                    constructor initialization list) one level to the
                    left, but only if the user did not play around with
                    it yet. Some users have exotic tastes in the
                    matter, and most users probably are not patient
                    enough to wait for the final ':' to format their
                    code properly.

                    We don't attempt the same for goto labels, as the
                    user is probably the middle of "foo::bar". (Who
                    uses goto, anyway?)
                */
                if (indentOfLine(bottomLine) <= indent)
                    indent -= ppIndentSize;
                else
                    indent = indentOfLine(bottomLine);
            }
        }
    }

    return qMax(0, indent);
}
void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
{
    restoreCurrentState(block.previous());

    const int lexerState = tokenizeBlock(block);
    m_tokenIndex = 0;
    m_newStates.clear();

    //qDebug() << "Starting to look at " << block.text() << block.blockNumber() + 1;

    for (; m_tokenIndex < m_tokens.size(); ) {
        m_currentToken = tokenAt(m_tokenIndex);
        const int kind = extendedTokenKind(m_currentToken);

        //qDebug() << "Token" << m_currentLine.mid(m_currentToken.begin(), m_currentToken.length) << m_tokenIndex << "in line" << block.blockNumber() + 1;
        //dump();

        if (kind == Comment
                && state().type != multiline_comment_cont
                && state().type != multiline_comment_start) {
            m_tokenIndex += 1;
            continue;
        }

        switch (m_currentState.top().type) {
        case topmost_intro:
            switch (kind) {
            case Identifier:    enter(objectdefinition_or_js); continue;
            case Import:        enter(top_qml); continue;
            case LeftBrace:     enter(top_js); enter(expression); continue; // if a file starts with {, it's likely json
            default:            enter(top_js); continue;
            } break;

        case top_qml:
            switch (kind) {
            case Import:        enter(import_start); break;
            case Identifier:    enter(binding_or_objectdefinition); break;
            } break;

        case top_js:
            tryStatement();
            break;

        case objectdefinition_or_js:
            switch (kind) {
            case Dot:           break;
            case Identifier:
                if (!m_currentLine.at(m_currentToken.begin()).isUpper()) {
                    turnInto(top_js);
                    continue;
                }
                break;
            case LeftBrace:     turnInto(binding_or_objectdefinition); continue;
            default:            turnInto(top_js); continue;
            } break;

        case import_start:
            enter(import_maybe_dot_or_version_or_as);
            break;

        case import_maybe_dot_or_version_or_as:
            switch (kind) {
            case Dot:           turnInto(import_dot); break;
            case As:            turnInto(import_as); break;
            case Number:        turnInto(import_maybe_as); break;
            default:            leave(); leave(); continue;
            } break;

        case import_maybe_as:
            switch (kind) {
            case As:            turnInto(import_as); break;
            default:            leave(); leave(); continue;
            } break;

        case import_dot:
            switch (kind) {
            case Identifier:    turnInto(import_maybe_dot_or_version_or_as); break;
            default:            leave(); leave(); continue;
            } break;

        case import_as:
            switch (kind) {
            case Identifier:    leave(); leave(); break;
            } break;

        case binding_or_objectdefinition:
            switch (kind) {
            case Colon:         enter(binding_assignment); break;
            case LeftBrace:     enter(objectdefinition_open); break;
            } break;

        case binding_assignment:
            switch (kind) {
            case Semicolon:     leave(true); break;
            case If:            enter(if_statement); break;
            case With:          enter(statement_with_condition); break;
            case Try:           enter(try_statement); break;
            case Switch:        enter(switch_statement); break;
            case LeftBrace:     enter(jsblock_open); break;
            case On:
            case As:
            case List:
            case Import:
            case Signal:
            case Property:
            case Identifier:    enter(expression_or_objectdefinition); break;

            // error recovery
            case RightBracket:
            case RightParenthesis:  leave(true); break;

            default:            enter(expression); continue;
            } break;

        case objectdefinition_open:
            switch (kind) {
            case RightBrace:    leave(true); break;
            case Default:       enter(default_property_start); break;
            case Property:      enter(property_start); break;
            case Function:      enter(function_start); break;
            case Signal:        enter(signal_start); break;
            case On:
            case As:
            case List:
            case Import:
            case Identifier:    enter(binding_or_objectdefinition); break;
            } break;

        case default_property_start:
            if (kind != Property)
                leave(true);
            else
                turnInto(property_start);
            break;

        case property_start:
            switch (kind) {
            case Colon:         enter(binding_assignment); break; // oops, was a binding
            case Var:
            case Identifier:    enter(property_name); break;
            case List:          enter(property_list_open); break;
            default:            leave(true); continue;
            } break;

        case property_name:
            turnInto(property_maybe_initializer);
            break;

        case property_list_open:
            if (m_currentLine.midRef(m_currentToken.begin(), m_currentToken.length) == QLatin1String(">"))
                turnInto(property_name);
            break;

        case property_maybe_initializer:
            switch (kind) {
            case Colon:         turnInto(binding_assignment); break;
            default:            leave(true); continue;
            } break;

        case signal_start:
            switch (kind) {
            case Colon:         enter(binding_assignment); break; // oops, was a binding
            default:            enter(signal_maybe_arglist); break;
            } break;

        case signal_maybe_arglist:
            switch (kind) {
            case LeftParenthesis:   turnInto(signal_arglist_open); break;
            default:                leave(true); continue;
            } break;

        case signal_arglist_open:
            switch (kind) {
            case RightParenthesis:  leave(true); break;
            } break;

        case function_start:
            switch (kind) {
            case LeftParenthesis:   enter(function_arglist_open); break;
            } break;

        case function_arglist_open:
            switch (kind) {
            case RightParenthesis:  turnInto(function_arglist_closed); break;
            } break;

        case function_arglist_closed:
            switch (kind) {
            case LeftBrace:         turnInto(jsblock_open); break;
            default:                leave(true); continue; // error recovery
            } break;

        case expression_or_objectdefinition:
            switch (kind) {
            case Dot:
            case Identifier:        break; // need to become an objectdefinition_open in cases like "width: Qt.Foo {"
            case LeftBrace:         turnInto(objectdefinition_open); break;

            // propagate 'leave' from expression state
            case RightBracket:
            case RightParenthesis:  leave(); continue;

            default:                enter(expression); continue; // really? identifier and more tokens might already be gone
            } break;

        case expression_or_label:
            switch (kind) {
            case Colon:             turnInto(labelled_statement); break;

            // propagate 'leave' from expression state
            case RightBracket:
            case RightParenthesis:  leave(); continue;

            default:                enter(expression); continue;
            } break;

        case ternary_op:
            if (kind == Colon) {
                enter(ternary_op_after_colon);
                enter(expression_continuation);
                break;
            }
            // fallthrough
        case ternary_op_after_colon:
        case expression:
            if (tryInsideExpression())
                break;
            switch (kind) {
            case Comma:
            case Delimiter:         enter(expression_continuation); break;
            case RightBracket:
            case RightParenthesis:  leave(); continue;
            case RightBrace:        leave(true); continue;
            case Semicolon:         leave(true); break;
            } break;

        case expression_continuation:
            leave();
            continue;

        case expression_maybe_continuation:
            switch (kind) {
            case Question:
            case Delimiter:
            case LeftBracket:
            case LeftParenthesis:  leave(); continue;
            default:               leave(true); continue;
            } break;

        case paren_open:
            if (tryInsideExpression())
                break;
            switch (kind) {
            case RightParenthesis:  leave(); break;
            } break;

        case bracket_open:
            if (tryInsideExpression())
                break;
            switch (kind) {
            case Comma:             enter(bracket_element_start); break;
            case RightBracket:      leave(); break;
            } break;

        case objectliteral_open:
            if (tryInsideExpression())
                break;
            switch (kind) {
            case Colon:             enter(objectliteral_assignment); break;
            case RightBracket:
            case RightParenthesis:  leave(); continue; // error recovery
            case RightBrace:        leave(true); break;
            } break;

        // pretty much like expression, but ends with , or }
        case objectliteral_assignment:
            if (tryInsideExpression())
                break;
            switch (kind) {
            case Delimiter:         enter(expression_continuation); break;
            case RightBracket:
            case RightParenthesis:  leave(); continue; // error recovery
            case RightBrace:        leave(); continue; // so we also leave objectliteral_open
            case Comma:             leave(); break;
            } break;

        case bracket_element_start:
            switch (kind) {
            case Identifier:        turnInto(bracket_element_maybe_objectdefinition); break;
            default:                leave(); continue;
            } break;

        case bracket_element_maybe_objectdefinition:
            switch (kind) {
            case LeftBrace:         turnInto(objectdefinition_open); break;
            default:                leave(); continue;
            } break;

        case jsblock_open:
        case substatement_open:
            if (tryStatement())
                break;
            switch (kind) {
            case RightBrace:        leave(true); break;
            } break;

        case labelled_statement:
            if (tryStatement())
                break;
            leave(true); // error recovery
            break;

        case substatement:
            // prefer substatement_open over block_open
            if (kind != LeftBrace) {
                if (tryStatement())
                    break;
            }
            switch (kind) {
            case LeftBrace:         turnInto(substatement_open); break;
            } break;

        case if_statement:
            switch (kind) {
            case LeftParenthesis:   enter(condition_open); break;
            default:                leave(true); break; // error recovery
            } break;

        case maybe_else:
            switch (kind) {
            case Else:              turnInto(else_clause); enter(substatement); break;
            default:                leave(true); continue;
            } break;

        case maybe_catch_or_finally:
            switch (kind) {
            case Catch:             turnInto(catch_statement); break;
            case Finally:           turnInto(finally_statement); break;
            default:                leave(true); continue;
            } break;

        case else_clause:
            // ### shouldn't happen
            dump();
            Q_ASSERT(false);
            leave(true);
            break;

        case condition_open:
            if (tryInsideExpression())
                break;
            switch (kind) {
            case RightParenthesis:  turnInto(substatement); break;
            } break;

        case switch_statement:
        case catch_statement:
        case statement_with_condition:
            switch (kind) {
            case LeftParenthesis:   enter(statement_with_condition_paren_open); break;
            default:                leave(true);
            } break;

        case statement_with_condition_paren_open:
            if (tryInsideExpression())
                break;
            switch (kind) {
            case RightParenthesis:  turnInto(substatement); break;
            } break;

        case try_statement:
        case finally_statement:
            switch (kind) {
            case LeftBrace:         enter(jsblock_open); break;
            default:                leave(true); break;
            } break;

        case do_statement:
            switch (kind) {
            case While:             break;
            case LeftParenthesis:   enter(do_statement_while_paren_open); break;
            default:                leave(true); continue; // error recovery
            } break;

        case do_statement_while_paren_open:
            if (tryInsideExpression())
                break;
            switch (kind) {
            case RightParenthesis:  leave(); leave(true); break;
            } break;

        case breakcontinue_statement:
            switch (kind) {
            case Identifier:        leave(true); break;
            default:                leave(true); continue; // try again
            } break;

        case case_start:
            switch (kind) {
            case Colon:             turnInto(case_cont); break;
            } break;

        case case_cont:
            if (kind != Case && kind != Default && tryStatement())
                break;
            switch (kind) {
            case RightBrace:        leave(); continue;
            case Default:
            case Case:              leave(); continue;
            } break;

        case multiline_comment_start:
        case multiline_comment_cont:
            if (kind != Comment) {
                leave();
                continue;
            } else if (m_tokenIndex == m_tokens.size() - 1
                       && (lexerState & Scanner::MultiLineMask) == Scanner::Normal) {
                leave();
            } else if (m_tokenIndex == 0) {
                // to allow enter/leave to update the indentDepth
                turnInto(multiline_comment_cont);
            }
            break;

        default:
            qWarning() << "Unhandled state" << m_currentState.top().type;
            break;
        } // end of state switch

        ++m_tokenIndex;
    }

    int topState = m_currentState.top().type;

    // if there's no colon on the same line, it's not a label
    if (topState == expression_or_label)
        enter(expression);
    // if not followed by an identifier on the same line, it's done
    else if (topState == breakcontinue_statement)
        leave(true);

    topState = m_currentState.top().type;

    // some states might be continued on the next line
    if (topState == expression
            || topState == expression_or_objectdefinition
            || topState == objectliteral_assignment
            || topState == ternary_op_after_colon) {
        enter(expression_maybe_continuation);
    }
    // multi-line comment start?
    if (topState != multiline_comment_start
            && topState != multiline_comment_cont
            && (lexerState & Scanner::MultiLineMask) == Scanner::MultiLineComment) {
        enter(multiline_comment_start);
    }

    saveCurrentState(block);
}
Beispiel #18
0
void SourceWindow::drawLineInfoArea(QPainter* p, QPaintEvent* event)
{
    QTextBlock block = firstVisibleBlock();

    p->setFont(m_lineNoFont);

    for (; block.isValid(); block = block.next())
    {
	if (!block.isVisible())
	    continue;

	QRect r = blockBoundingGeometry(block).translated(contentOffset()).toRect();
	if (r.bottom() < event->rect().top())
	    continue; // skip blocks that are higher than the region being updated
	else if (r.top() > event->rect().bottom())
	    break;    // all the following blocks are lower then the region being updated

	int row = block.blockNumber();
	uchar item = m_lineItems[row];

	int h = r.height();
	p->save();
	p->translate(0, r.top());

	if (item & liBP) {
	    // enabled breakpoint
	    int y = (h - m_brkena.height())/2;
	    if (y < 0) y = 0;
	    p->drawPixmap(0,y,m_brkena);
	}
	if (item & liBPdisabled) {
	    // disabled breakpoint
	    int y = (h - m_brkdis.height())/2;
	    if (y < 0) y = 0;
	    p->drawPixmap(0,y,m_brkdis);
	}
	if (item & liBPtemporary) {
	    // temporary breakpoint marker
	    int y = (h - m_brktmp.height())/2;
	    if (y < 0) y = 0;
	    p->drawPixmap(0,y,m_brktmp);
	}
	if (item & liBPconditional) {
	    // conditional breakpoint marker
	    int y = (h - m_brkcond.height())/2;
	    if (y < 0) y = 0;
	    p->drawPixmap(0,y,m_brkcond);
	}
	if (item & liBPorphan) {
	    // orphaned breakpoint marker
	    int y = (h - m_brkcond.height())/2;
	    if (y < 0) y = 0;
	    p->drawPixmap(0,y,m_brkorph);
	}
	if (item & liPC) {
	    // program counter in innermost frame
	    int y = (h - m_pcinner.height())/2;
	    if (y < 0) y = 0;
	    p->drawPixmap(0,y,m_pcinner);
	}
	if (item & liPCup) {
	    // program counter somewhere up the stack
	    int y = (h - m_pcup.height())/2;
	    if (y < 0) y = 0;
	    p->drawPixmap(0,y,m_pcup);
	}
	p->translate(m_widthItems, 0);
	if (!isRowDisassCode(row) && m_sourceCode[rowToLine(row)].canDisass) {
	    int w = m_widthPlus;
	    int x = w/2;
	    int y = h/2;
	    p->drawLine(x-2, y, x+2, y);
	    if (!isRowExpanded(row)) {
		p->drawLine(x, y-2, x, y+2);
	    }
	}
	p->translate(m_widthPlus, 0);
	if (!isRowDisassCode(row)) {
	    p->drawText(0, 0, m_widthLineNo, h, Qt::AlignRight|Qt::AlignVCenter,
			QString().setNum(rowToLine(row)+1));
	}
	p->restore();
    }
}
Beispiel #19
0
bool GenericCodeEditor::find( const QRegExp &expr, QTextDocument::FindFlags options )
{
    // Although QTextDocument provides a find() method, we implement
    // our own, because the former one is not adequate.

    if(expr.isEmpty()) return true;

    bool backwards = options & QTextDocument::FindBackward;

    QTextCursor c( textCursor() );
    int pos;
    if (c.hasSelection())
    {
        bool matching = expr.exactMatch(c.selectedText());

        if( backwards == matching )
            pos = c.selectionStart();
        else
            pos = c.selectionEnd();
    }
    else
        pos = c.position();

    QTextDocument *doc = QPlainTextEdit::document();
    QTextBlock startBlock = doc->findBlock(pos);
    int startBlockOffset = pos - startBlock.position();

    QTextCursor cursor;

    if (!backwards) {
        int blockOffset = startBlockOffset;
        QTextBlock block = startBlock;
        while (block.isValid()) {
            if (findInBlock(doc, block, expr, blockOffset, options, cursor))
                break;
            blockOffset = 0;
            block = block.next();
        }
        if(cursor.isNull())
        {
            blockOffset = 0;
            block = doc->begin();
            while(true) {
                if (findInBlock(doc, block, expr, blockOffset, options, cursor)
                    || block == startBlock)
                    break;
                block = block.next();
            }
        }
    } else {
        int blockOffset = startBlockOffset;
        QTextBlock block = startBlock;
        while (block.isValid()) {
            if (findInBlock(doc, block, expr, blockOffset, options, cursor))
                break;
            block = block.previous();
            blockOffset = block.length() - 1;
        }
        if(cursor.isNull())
        {
            block = doc->end();
            while(true) {
                blockOffset = block.length() - 1;
                if (findInBlock(doc, block, expr, blockOffset, options, cursor)
                    || block == startBlock)
                    break;
                block = block.previous();
            }
        }
    }

    if(!cursor.isNull()) {
        setTextCursor(cursor);
        return true;
    }
    else
        return false;
}
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;
}
Beispiel #21
0
void MainWindow::interpolateButtonClicked()
{
    QString tString = ui->tLineEdit->text();
    bool ok;
    double tValue = tString.toDouble(&ok);

    if(!ok)
        ; // if you're too stupid to enter a valid number, you're too stupid
    // to read a proper error message, so no error message here.


    // get the input by filtering non-valid input data
    QTextDocument *doc = ui->dataInput->document();
    QStringList inputList;
    for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
    {
        QString line = QString::fromStdString(it.text().toStdString());
        // empty lines and malformed input are skipped
        if(line != ""
            && line.contains(QRegExp("-?\\d+(\\.\\d+)?\\s+-?\\d+(\\.\\d+)?")))
            inputList << line.trimmed();
        else
            qDebug() << "Skipping line: " << line;
    }

    int number_points = inputList.size();
    double data[number_points][2];

    // split the lines in x and y
    for(int i=0; i<inputList.size(); i++)
    {
        QString point = inputList.at(i);
        QStringList l = point.split(QRegExp("\\s+"));

        // this should never happen
        if(l.size()<2){
            qDebug() << "String couldn't be split.";
            qDebug() << "Can't interpolate.";
            return;
        }

        data[i][0] = l.at(0).toDouble();
        data[i][1] = l.at(1).toDouble();
    }

    // the output file
    QFile output;
    output.setFileName("results.dat");
    output.open(QIODevice::WriteOnly | QIODevice::Text);
    QTextStream fout(&output);

    // basic matrix
    double Mcr[4][4] = {
        {-0.5, 1.5, -1.5, 0.5},
        {1, -2.5, 2, -0.5},
        {-0.5, 0, 0.5, 0},
        {0, 1, 0, 0}
    };

    double Gbi[4][2];

    for(int i=0; i<number_points-1; i++)
    {
        // Select the four points required for the calculation.
        // With the min/max functions the border points are implicitely
        // duplicated as they wouldn't be interpolated by the algorithm
        // otherwise.
        for(int j=0; j<2; j++)
        {
            Gbi[0][j] = data[std::max(0, i-1)][j];
            Gbi[1][j] = data[i][j];
            Gbi[2][j] = data[std::min(number_points-1, i+1)][j];
            Gbi[3][j] = data[std::min(number_points-1, i+2)][j];
        }

        // interpolate points between two given points
        for(double u=0; u<1; u=u+0.001)
        {
            double T[4] = {pow(u,3), pow(u,2), u, 1};
            double results[2] = {0, 0};

            // interpolate one point by calculating T * Mcr * Gbi
            for(int bi_ctr=0; bi_ctr<2; bi_ctr++)
            {
                double sum = 0;
                for(int point_row=0; point_row<4; point_row++)
                {
                    for(int mcr_row=0; mcr_row<4; mcr_row++)
                    {
                        sum += T[mcr_row] * Mcr[mcr_row][point_row]
                                * Gbi[point_row][bi_ctr];
                    }
                }
                results[bi_ctr] = sum;
            }

            fout << results[0] << " " << results[1] << "\n";

            // if the user entered a valid value for x then display y
            if(ok)
            {
                //qDebug() << "ok";

                double diff = results[0] - tValue;
                //qDebug() << tValue << " " << results[0];
                qDebug() << diff;

                if( diff <= 0.001 )
                    ui->resultLineEdit->setText(QString("%1").arg(results[1]));
            }
        }
    }

    output.close();
}
void ScCodeEditor::keyPressEvent( QKeyEvent *e )
{
    hideMouseCursor(e);

    QTextCursor cursor( textCursor() );
    bool cursorMoved = true;

    if (e == QKeySequence::MoveToNextWord)
        moveToNextToken( cursor, QTextCursor::MoveAnchor );
    else if (e == QKeySequence::MoveToPreviousWord)
        moveToPreviousToken( cursor, QTextCursor::MoveAnchor );
    else if (e == QKeySequence::SelectNextWord)
        moveToNextToken( cursor, QTextCursor::KeepAnchor );
    else if (e == QKeySequence::SelectPreviousWord)
        moveToPreviousToken( cursor, QTextCursor::KeepAnchor );
    else
        cursorMoved = false;

    if (cursorMoved) {
        setTextCursor( cursor );
        return;
    }

    switch (e->key()) {
    case Qt::Key_Home:
    {
        Qt::KeyboardModifiers mods(e->modifiers());
        if (mods && mods != Qt::ShiftModifier) {
            GenericCodeEditor::keyPressEvent(e);
            return;
        }

        QTextCursor::MoveMode mode =
            mods & Qt::ShiftModifier ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor;

        QTextCursor c(textCursor());
        QTextBlock b(c.block());

        int pos = indentedStartOfLine(b);
        pos += b.position();

        if (c.position() == pos)
            c.movePosition(QTextCursor::StartOfLine, mode);
        else
            c.setPosition(pos, mode);

        setTextCursor(c);

        return;
    }

    case Qt::Key_Backtab:
    {
        QTextCursor cursor = textCursor();
        insertSpaceToNextTabStop( cursor );
        ensureCursorVisible();
        return;
    }
    case Qt::Key_Backspace:
        if (mInsertMatchingTokens && !overwriteMode() && e->modifiers() == 0)
            if (removeMatchingTokens())
                break;
        GenericCodeEditor::keyPressEvent(e);
        break;
    case Qt::Key_Enter:
    case Qt::Key_Return:
    {
        QTextBlock cursorBlock = cursor.block();
        int cursorPosInBlock = cursor.position() - cursorBlock.position();
        TokenIterator nextToken = TokenIterator::rightOf(cursorBlock, cursorPosInBlock);
        if ( nextToken.block() == cursorBlock && nextToken.type() == Token::ClosingBracket )
        {
            cursor.beginEditBlock();
            cursor.insertBlock();
            cursor.insertBlock();
            cursor.endEditBlock();
            cursor.movePosition( QTextCursor::PreviousBlock, QTextCursor::KeepAnchor );
            indent(cursor, JoinEditBlock);
            cursor.movePosition( QTextCursor::EndOfBlock );
        }
        else {
            cursor.beginEditBlock();
            cursor.insertBlock();
            cursor.endEditBlock();
            indent(cursor, JoinEditBlock);
        }
        cursor.setVerticalMovementX(-1);
        setTextCursor(cursor);
        break;
    }
    default:
        if (!overwriteMode() && insertMatchingTokens(e->text()))
            break;
        GenericCodeEditor::keyPressEvent(e);
    }

    mAutoCompleter->keyPress(e);
}
void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
	int32 emojiPosition = 0, emojiLen = 0;
	const EmojiData *emoji = 0;

	QTextDocument *doc(document());

	while (true) {
		int32 start = position, end = position + charsAdded;
		QTextBlock from = doc->findBlock(start), till = doc->findBlock(end);
		if (till.isValid()) till = till.next();

		for (QTextBlock b = from; b != till; b = b.next()) {
			for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) {
				QTextFragment fragment(iter.fragment());
				if (!fragment.isValid()) continue;

				int32 fp = fragment.position(), fe = fp + fragment.length();
				if (fp >= end || fe <= start) {
					continue;
				}

				QString t(fragment.text());
				const QChar *ch = t.constData(), *e = ch + t.size();
				for (; ch != e; ++ch) {
					emoji = emojiFromText(ch, e, emojiLen);
					if (emoji) {
						emojiPosition = fp + (ch - t.constData());
						break;
					}
					if (ch + 1 < e && ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) ++ch;
				}
				if (emoji) break;
			}
			if (emoji) break;
		}
		if (emoji) {
			QTextCursor c(doc->docHandle(), emojiPosition);
			c.setPosition(emojiPosition + emojiLen, QTextCursor::KeepAnchor);
			int32 removedUpto = c.position();

			insertEmoji(emoji, c);

			for (Insertions::iterator i = _insertions.begin(), e = _insertions.end(); i != e; ++i) {
				if (i->first >= removedUpto) {
					i->first -= removedUpto - emojiPosition - 1;
				} else if (i->first >= emojiPosition) {
					i->second -= removedUpto - emojiPosition;
					i->first = emojiPosition + 1;
				} else if (i->first + i->second > emojiPosition + 1) {
					i->second -= qMin(removedUpto, i->first + i->second) - emojiPosition;
				}
			}

			charsAdded -= removedUpto - position;
			position = emojiPosition + 1;

			emoji = 0;
			emojiPosition = 0;
		} else {
			break;
		}
	}
}
void ScCodeEditor::indent( const QTextCursor & selection, EditBlockMode editBlockMode )
{
    if (selection.isNull())
        return;

    QTextCursor cursor(selection);

    if (editBlockMode == NewEditBlock)
        cursor.beginEditBlock();
    else
        cursor.joinPreviousEditBlock();

    QTextDocument *doc = QPlainTextEdit::document();
    int startBlockNum = doc->findBlock(cursor.selectionStart()).blockNumber();
    int endBlockNum = cursor.hasSelection() ?
        doc->findBlock(cursor.selectionEnd()).blockNumber() : startBlockNum;

    QStack<int> stack;
    int global_level = 0;
    int blockNum = 0;
    bool in_string = false;
    QTextBlock block = QPlainTextEdit::document()->begin();
    while (block.isValid())
    {
        int initialStackSize = stack.size();
        int level = 0;
        bool block_start_in_string = in_string;

        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;
                    break;

                case Token::ClosingBracket:
                    if (level)
                        --level;
                    else if (global_level) {
                        --global_level;
                        if (!stack.isEmpty() && global_level < stack.top())
                            stack.pop();
                    }
                    break;

                case Token::StringMark:
                    in_string = !in_string;
                    break;

                default:
                    break;
                }
            }
        }

        if(blockNum >= startBlockNum) {
            int indentLevel;
            if (data && data->tokens.size() && data->tokens[0].type == Token::ClosingBracket)
                indentLevel = stack.size();
            else if (!block_start_in_string)
                indentLevel = initialStackSize;
            else
                indentLevel = 0;
            block = indent(block, indentLevel);
        }

        if(blockNum == endBlockNum)
            break;

        block = block.next();
        ++blockNum;

        if (level) {
            global_level += level;
            stack.push(global_level);
        }
    }

    cursor.endEditBlock();
}
/*!
    \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;
}
static bool isSingleLineComment(QTextBlock const & block)
{
    static QRegExp commentRegex("^\\s*//.*");
    return commentRegex.exactMatch(block.text());
}
/*
   Removes some nefast constructs from a code line and returns the
   resulting line.
*/
QString LineInfo::trimmedCodeLine(const QString &t)
{
    Scanner scanner;

    QTextBlock currentLine = yyLinizerState.iter;
    int startState = qMax(0, currentLine.previous().userState()) & 0xff;

    yyLinizerState.tokens = scanner(t, startState);
    QString trimmed;
    int previousTokenEnd = 0;
    foreach (const Token &token, yyLinizerState.tokens) {
        trimmed.append(t.midRef(previousTokenEnd, token.begin() - previousTokenEnd));

        if (token.is(Token::String)) {
            for (int i = 0; i < token.length; ++i)
                trimmed.append(QLatin1Char('X'));

        } else if (token.is(Token::Comment)) {
            for (int i = 0; i < token.length; ++i)
                trimmed.append(QLatin1Char(' '));

        } else {
            trimmed.append(tokenText(token));
        }

        previousTokenEnd = token.end();
    }

    int index = yyLinizerState.tokens.size() - 1;
    for (; index != -1; --index) {
        const Token &token = yyLinizerState.tokens.at(index);
        if (token.isNot(Token::Comment))
            break;
    }

    bool isBinding = false;
    foreach (const Token &token, yyLinizerState.tokens) {
        if (token.is(Token::Colon)) {
            isBinding = true;
            break;
        }
    }

    if (index != -1) {
        const Token &last = yyLinizerState.tokens.at(index);
        bool needSemicolon = false;

        switch (last.kind) {
        case Token::LeftParenthesis:
        case Token::LeftBrace:
        case Token::LeftBracket:
        case Token::Semicolon:
        case Token::Delimiter:
            break;

        case Token::RightParenthesis:
        case Token::RightBrace:
        case Token::RightBracket:
            if (isBinding)
                needSemicolon = true;
            break;

        case Token::String:
        case Token::Number:
        case Token::Comma:
            needSemicolon = true;
            break;

        case Token::Identifier: {
            // need to disambiguate
            // "Rectangle\n{" in a QML context from
            // "a = Somevar\n{" in a JS context
            // What's done here does not cover all cases, but goes as far as possible
            // with the limited information that's available.
            const QStringRef text = tokenText(last);
            if (yyLinizerState.leftBraceFollows && !text.isEmpty() && text.at(0).isUpper()) {
                int i = index;

                // skip any preceding 'identifier.'; these could appear in both cases
                while (i >= 2) {
                    const Token &prev = yyLinizerState.tokens.at(i-1);
                    const Token &prevPrev = yyLinizerState.tokens.at(i-2);
                    if (prev.kind == Token::Dot && prevPrev.kind == Token::Identifier)
                        i -= 2;
                    else
                        break;
                }

                // it could also be 'a = \n Foo \n {', but that sounds unlikely
                if (i == 0)
                    break;

                // these indicate a QML context
                const Token &prev = yyLinizerState.tokens.at(i-1);
                if (prev.kind == Token::Semicolon || prev.kind == Token::Identifier
                        || prev.kind == Token::RightBrace || prev.kind == Token::RightBracket) {
                    break;
                }
            }
            needSemicolon = true;
            break;
        }

        case Token::Keyword:
            if (tokenText(last) != QLatin1String("else"))
                needSemicolon = true;
            break;

        default:
            break;
        } // end of switch

        if (needSemicolon) {
            const Token sc(trimmed.size(), 1, Token::Semicolon);
            yyLinizerState.tokens.append(sc);
            trimmed.append(QLatin1Char(';'));
            yyLinizerState.insertedSemicolon = true;
        }
    }

    return trimmed;
}
void ScCodeEditor::toggleCommentSelection()
{
    QTextCursor cursor = textCursor();
    cursor.beginEditBlock();

    if (isBlockOnlySelection(cursor)) {
        const bool isComment = isSingleLineComment(cursor);

        QTextCursor selectionCursor(cursor);
        selectionCursor.setPosition(cursor.selectionStart());

        QTextBlock currentBlock = selectionCursor.block();
        int firstBlockIndentation = isComment ? 0
                                              : indentationLevel(selectionCursor);

        do {
            QTextCursor blockCursor(currentBlock);
            if (!isComment)
                addSingleLineComment(blockCursor, firstBlockIndentation);
            else
                removeSingleLineComment(blockCursor);
            currentBlock = currentBlock.next();
        } while (currentBlock.isValid() && currentBlock.position() < cursor.selectionEnd());

        if (!isComment) {
            // fix up selection
            QTextCursor newSelection(cursor);
            if (cursor.anchor() < cursor.position()) {
                newSelection.setPosition(newSelection.selectionStart());
                newSelection.movePosition(QTextCursor::StartOfBlock);
                newSelection.setPosition(cursor.selectionEnd(), QTextCursor::KeepAnchor);
            } else {
                newSelection.setPosition(newSelection.selectionEnd());
                newSelection.setPosition(cursor.selectionStart(), QTextCursor::KeepAnchor);
                newSelection.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
            }
            setTextCursor(newSelection);
        }
    } else {
        QString selectionText = cursor.selectedText();
        QTextCursor selectionCursor(cursor);
        if (isSelectionComment(selectionText)) {
            selectionText = selectionText.trimmed().remove(0, 2);
            selectionText.chop(2);
            selectionCursor.insertText(selectionText);
        } else {
            selectionText = QString("/*") + selectionText + QString("*/");
            selectionCursor.insertText(selectionText);
        }

        // fix up selection
        const int position = selectionCursor.position();
        const int anchor   = selectionCursor.anchor();
        if (position > anchor) {
            cursor.setPosition(position - selectionText.size());
            cursor.setPosition(position, QTextCursor::KeepAnchor);
        } else {
            cursor.setPosition(position);
            cursor.setPosition(position - selectionText.size(), QTextCursor::KeepAnchor);
        }
        setTextCursor(cursor);
    }

    cursor.endEditBlock();
}
Beispiel #29
0
void Utils::unCommentSelection(QPlainTextEdit *edit, CommentFlag flag, const CommentDefinition &definition)
{
    if (!definition.hasSingleLineStyle() && !definition.hasMultiLineStyle())
        return;

    QTextCursor cursor = edit->textCursor();
    QTextDocument *doc = cursor.document();

    if (!cursor.hasSelection() && (flag == BlockComment) ) {
        if (definition.hasMultiLineStyle()) {
            cursor.beginEditBlock();
            cursor.insertText(definition.multiLineStart());
            cursor.insertText(definition.multiLineEnd());
            cursor.movePosition(QTextCursor::Left,QTextCursor::MoveAnchor,definition.multiLineEnd().length());
            cursor.endEditBlock();
            edit->setTextCursor(cursor);
            return;
        }
    }

    cursor.beginEditBlock();

    int pos = cursor.position();
    int anchor = cursor.anchor();
    int start = qMin(anchor, pos);
    int end = qMax(anchor, pos);
    bool anchorIsStart = (anchor == start);

    QTextBlock startBlock = doc->findBlock(start);
    QTextBlock endBlock = doc->findBlock(end);

    if (end > start && endBlock.position() == end) {
        --end;
        endBlock = endBlock.previous();
    }

    bool doMultiLineStyleUncomment = false;
    bool doMultiLineStyleComment = false;
    bool doSingleLineStyleUncomment = false;

    bool hasSelection = cursor.hasSelection();
    int firstSpacesOffset = -1;

    if (hasSelection && definition.hasMultiLineStyle()) {

        QString startText = startBlock.text();
        int startPos = start - startBlock.position();
        const int multiLineStartLength = definition.multiLineStart().length();
        bool hasLeadingCharacters = !startText.left(startPos).trimmed().isEmpty();

        if (startPos >= multiLineStartLength
            && isComment(startText,
                         startPos - multiLineStartLength,
                         definition,
                         &CommentDefinition::multiLineStart)) {
            startPos -= multiLineStartLength;
            start -= multiLineStartLength;
        }

        bool hasSelStart = (startPos <= startText.length() - multiLineStartLength
                            && isComment(startText,
                                         startPos,
                                         definition,
                                         &CommentDefinition::multiLineStart));

        QString endText = endBlock.text();
        int endPos = end - endBlock.position();
        const int multiLineEndLength = definition.multiLineEnd().length();
        bool hasTrailingCharacters =
                !endText.left(endPos).remove(definition.singleLine()).trimmed().isEmpty()
                && !endText.mid(endPos).trimmed().isEmpty();

        if (endPos <= endText.length() - multiLineEndLength
            && isComment(endText, endPos, definition, &CommentDefinition::multiLineEnd)) {
            endPos += multiLineEndLength;
            end += multiLineEndLength;
        }

        bool hasSelEnd = (endPos >= multiLineEndLength
                          && isComment(endText,
                                       endPos - multiLineEndLength,
                                       definition,
                                       &CommentDefinition::multiLineEnd));

        doMultiLineStyleUncomment = hasSelStart && hasSelEnd;
        doMultiLineStyleComment = !doMultiLineStyleUncomment
                                  && (hasLeadingCharacters
                                      || hasTrailingCharacters
                                      || !definition.hasSingleLineStyle()
                                      || (flag == BlockComment));
    } else if (!hasSelection && !definition.hasSingleLineStyle()) {

        QString text = startBlock.text().trimmed();
        doMultiLineStyleUncomment = text.startsWith(definition.multiLineStart())
                                    && text.endsWith(definition.multiLineEnd());
        doMultiLineStyleComment = !doMultiLineStyleUncomment && !text.isEmpty();

        start = startBlock.position();
        end = endBlock.position() + endBlock.length() - 1;

        if (doMultiLineStyleUncomment) {
            int offset = 0;
            text = startBlock.text();
            const int length = text.length();
            while (offset < length && text.at(offset).isSpace())
                ++offset;
            start += offset;
        }
    }

    if (flag == SingleComment) {
        if (doMultiLineStyleComment) {
            doMultiLineStyleComment = false;
        }
    }

    if (doMultiLineStyleUncomment) {
        cursor.setPosition(end);
        cursor.movePosition(QTextCursor::PreviousCharacter,
                            QTextCursor::KeepAnchor,
                            definition.multiLineEnd().length());
        cursor.removeSelectedText();
        cursor.setPosition(start);
        cursor.movePosition(QTextCursor::NextCharacter,
                            QTextCursor::KeepAnchor,
                            definition.multiLineStart().length());
        cursor.removeSelectedText();
    } else if (doMultiLineStyleComment) {
        cursor.setPosition(end);
        cursor.insertText(definition.multiLineEnd());
        cursor.setPosition(start);
        cursor.insertText(definition.multiLineStart());
    } else {
        endBlock = endBlock.next();
        doSingleLineStyleUncomment = true;
        for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
            QString text = block.text().trimmed();
            if (!text.isEmpty() && !text.startsWith(definition.singleLine())) {
                doSingleLineStyleUncomment = false;
                break;
            }
        }
        if (!hasSelection && cursor.block().text().isEmpty()) {
            doSingleLineStyleUncomment = false;
        }
        const int singleLineLength = definition.singleLine().length();
        for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
            if (doSingleLineStyleUncomment) {
                QString text = block.text();
                int i = 0;
                while (i <= text.size() - singleLineLength) {
                    if (isComment(text, i, definition, &CommentDefinition::singleLine)) {
                        cursor.setPosition(block.position() + i);
                        cursor.movePosition(QTextCursor::NextCharacter,
                                            QTextCursor::KeepAnchor,
                                            singleLineLength);
                        if (definition.isAfterWhiteSpacesAddSpace()) {
                            if (i < text.size()-singleLineLength) {
                                if (text.at(i+singleLineLength) == 0x0020) {
                                    cursor.movePosition(QTextCursor::NextCharacter,QTextCursor::KeepAnchor,1);
                                }
                            }
                        }
                        cursor.removeSelectedText();
                        break;
                    }
                    if (!text.at(i).isSpace())
                        break;
                    ++i;
                }
            } else {
                QString text = block.text();
                foreach(QChar c, text) {
                    if (!c.isSpace()) {
                        if (definition.isAfterWhiteSpaces()) {
                            int offset = text.indexOf(c);
                            if (firstSpacesOffset != -1 && offset > firstSpacesOffset) {
                                offset = firstSpacesOffset;
                            }
                            cursor.setPosition(block.position() + offset);
                        } else {
                            cursor.setPosition(block.position());
                        }
                        if (firstSpacesOffset == -1) {
                            firstSpacesOffset = cursor.position()-cursor.block().position();
                        }
                        if (definition.isAfterWhiteSpaces() && definition.isAfterWhiteSpacesAddSpace()) {
                            cursor.insertText(definition.singleLine()+" ");
                        } else {
                            cursor.insertText(definition.singleLine());
                        }
                        break;
                    }
                }
            }
        }
    }

    // adjust selection when commenting out
    if (hasSelection && !doMultiLineStyleUncomment && !doSingleLineStyleUncomment) {
        cursor = edit->textCursor();
        if (!doMultiLineStyleComment)
            start = startBlock.position(); // move the comment into the selection
        int lastSelPos = anchorIsStart ? cursor.position() : cursor.anchor();
        if (anchorIsStart) {
            cursor.setPosition(start);
            cursor.setPosition(lastSelPos, QTextCursor::KeepAnchor);
        } else {
            cursor.setPosition(lastSelPos);
            cursor.setPosition(start, QTextCursor::KeepAnchor);
        }
        edit->setTextCursor(cursor);
    }

    cursor.endEditBlock();
}
Beispiel #30
0
void TestDocumentLayout::testNestedPrefixedLists()
{
    /* A list with different prefix for each level should show only the prefix of that level
     * Specifically we should not concatenate the prefixes of the higher levels
     * Specifically we should not concatenate the suffixes of the higher levels
     * That is only the prefix and the suffix of the current level should be applied
     */
    initForNewTest("MMMM\nSSSS\n");

    KoParagraphStyle h1;
    m_styleManager->add(&h1);
    KoParagraphStyle h2;
    m_styleManager->add(&h2);

    KoListStyle listStyle;
    KoListLevelProperties llp1;
    llp1.setStartValue(1);
    llp1.setStyle(KoListStyle::DecimalItem);
    llp1.setListItemPrefix("Main");
    llp1.setListItemSuffix(":");

    listStyle.setLevelProperties(llp1);

    KoListLevelProperties llp2;
    llp2.setStartValue(1);
    llp2.setStyle(KoListStyle::DecimalItem);
    llp2.setLevel(2);
    llp2.setListItemPrefix("Sub");
    llp2.setListItemSuffix("*");
    llp2.setDisplayLevel(2);
    listStyle.setLevelProperties(llp2);

    h1.setListStyle(&listStyle);
    h2.setListLevel(2);
    h2.setListStyle(&listStyle);

    QVERIFY(listStyle.hasLevelProperties(1));
    QVERIFY(listStyle.hasLevelProperties(2));
    QVERIFY(!listStyle.hasLevelProperties(3));

    QTextBlock block = m_doc->begin().next();
    h1.applyStyle(block);
    block = block.next();
    QVERIFY(block.isValid());
    h2.applyStyle(block);

    m_layout->layout();

    block = m_doc->begin();
    QVERIFY(block.userData() == 0);
    block = block.next();
    static const char *const texts[] = { "Main1:", "Sub1.1*"};
    int i = 0;
    while (block.isValid()) {
        KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
        //qDebug() << "text: " << block.text();
        //qDebug() << "expected: " << texts[i];
        QVERIFY(data);
        //qDebug() << data->counterText();
        QCOMPARE(data->counterText(), QString(texts[i++]));
        block = block.next();
    }
}