Skip to content
Snippets Groups Projects
basetexteditor.cpp 126 KiB
Newer Older
con's avatar
con committed

            cursor->clearSelection();
            cursor->setPosition(closedParenParag.position() + closedParen.pos + 1, QTextCursor::KeepAnchor);

            if ((c == QLatin1Char('{') && closedParen.chr != QLatin1Char('}'))
                || (c == QLatin1Char('(') && closedParen.chr != QLatin1Char(')'))
                || (c == QLatin1Char('[') && closedParen.chr != QLatin1Char(']'))
                || (c == QLatin1Char('+') && closedParen.chr != QLatin1Char('-'))
               )
                return Mismatch;

            return Match;
        }
    }
}

TextBlockUserData::MatchType TextBlockUserData::checkClosedParenthesis(QTextCursor *cursor, QChar c)
{
    QTextBlock block = cursor->block();
    if (!TextEditDocumentLayout::hasParentheses(block) || TextEditDocumentLayout::ifdefedOut(block))
con's avatar
con committed
        return NoMatch;

    Parentheses parenList = TextEditDocumentLayout::parentheses(block);
con's avatar
con committed
    Parenthesis openParen, closedParen;
    QTextBlock openParenParag = block;
con's avatar
con committed

    const int cursorPos = cursor->position() - openParenParag.position();
    int i = parenList.count() - 1;
    int ignore = 0;
    bool foundClosed = false;
    for (;;) {
        if (!foundClosed) {
            if (i < 0)
                return NoMatch;
            closedParen = parenList.at(i);
            if (closedParen.pos != cursorPos - 1) {
                --i;
                continue;
            } else {
                foundClosed = true;
                --i;
            }
        }

        if (i < 0) {
            for (;;) {
                openParenParag = openParenParag.previous();
                if (!openParenParag.isValid())
                    return NoMatch;

                if (TextEditDocumentLayout::hasParentheses(openParenParag)
                    && !TextEditDocumentLayout::ifdefedOut(openParenParag)) {
con's avatar
con committed
                    parenList = TextEditDocumentLayout::parentheses(openParenParag);
                    break;
                }
            }
            i = parenList.count() - 1;
        }

        openParen = parenList.at(i);
        if (openParen.type == Parenthesis::Closed) {
            ignore++;
            --i;
            continue;
        } else {
            if (ignore > 0) {
                ignore--;
                --i;
                continue;
            }

            cursor->clearSelection();
            cursor->setPosition(openParenParag.position() + openParen.pos, QTextCursor::KeepAnchor);

            if ((c == '}' && openParen.chr != '{')    ||
                 (c == ')' && openParen.chr != '(')   ||
                 (c == ']' && openParen.chr != '[')   ||
                 (c == '-' && openParen.chr != '+'))
                return Mismatch;

            return Match;
        }
    }
}


bool TextBlockUserData::findPreviousOpenParenthesis(QTextCursor *cursor, bool select)
{
    QTextBlock block = cursor->block();
    int position = cursor->position();
    int ignore = 0;
    while (block.isValid()) {
        Parentheses parenList = TextEditDocumentLayout::parentheses(block);
        if (!parenList.isEmpty() && !TextEditDocumentLayout::ifdefedOut(block)) {
            for (int i = parenList.count()-1; i >= 0; --i) {
                Parenthesis paren = parenList.at(i);
                if (block == cursor->block() &&
                    (position - block.position() <= paren.pos + (paren.type == Parenthesis::Closed ? 1 : 0)))
                        continue;
                if (paren.type == Parenthesis::Closed) {
                    ++ignore;
                } else if (ignore > 0) {
                    --ignore;
                } else {
                    cursor->setPosition(block.position() + paren.pos, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
                    return true;
                }
            }
        }
        block = block.previous();
    }
    return false;
}

bool TextBlockUserData::findNextClosingParenthesis(QTextCursor *cursor, bool select)
{
    QTextBlock block = cursor->block();
    int position = cursor->position();
    int ignore = 0;
    while (block.isValid()) {
        Parentheses parenList = TextEditDocumentLayout::parentheses(block);
        if (!parenList.isEmpty() && !TextEditDocumentLayout::ifdefedOut(block)) {
            for (int i = 0; i < parenList.count(); ++i) {
                Parenthesis paren = parenList.at(i);
                if (block == cursor->block() && position - block.position() >= paren.pos)
                    continue;
                if (paren.type == Parenthesis::Opened) {
                    ++ignore;
                } else if (ignore > 0) {
                    --ignore;
                } else {
                    cursor->setPosition(block.position() + paren.pos+1, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
                    return true;
                }
            }
        }
        block = block.next();
    }
    return false;
}

con's avatar
con committed
TextBlockUserData::MatchType TextBlockUserData::matchCursorBackward(QTextCursor *cursor)
{
    cursor->clearSelection();
    const QTextBlock block = cursor->block();

    if (!TextEditDocumentLayout::hasParentheses(block) || TextEditDocumentLayout::ifdefedOut(block))
con's avatar
con committed
        return NoMatch;

    const int relPos = cursor->position() - block.position();

    Parentheses parentheses = TextEditDocumentLayout::parentheses(block);
    const Parentheses::const_iterator cend = parentheses.constEnd();
    for (Parentheses::const_iterator it = parentheses.constBegin();it != cend; ++it) {
        const Parenthesis &paren = *it;
        if (paren.pos == relPos - 1
            && paren.type == Parenthesis::Closed) {
            return checkClosedParenthesis(cursor, paren.chr);
        }
    }
    return NoMatch;
}

TextBlockUserData::MatchType TextBlockUserData::matchCursorForward(QTextCursor *cursor)
{
    cursor->clearSelection();
    const QTextBlock block = cursor->block();

    if (!TextEditDocumentLayout::hasParentheses(block) || TextEditDocumentLayout::ifdefedOut(block))
con's avatar
con committed
        return NoMatch;

    const int relPos = cursor->position() - block.position();

    Parentheses parentheses = TextEditDocumentLayout::parentheses(block);
    const Parentheses::const_iterator cend = parentheses.constEnd();
    for (Parentheses::const_iterator it = parentheses.constBegin();it != cend; ++it) {
        const Parenthesis &paren = *it;
        if (paren.pos == relPos
            && paren.type == Parenthesis::Opened) {
            return checkOpenParenthesis(cursor, paren.chr);
        }
    }
    return NoMatch;
}


void BaseTextEditor::highlightSearchResults(const QString &txt, QTextDocument::FindFlags findFlags)
{
    if (d->m_searchExpr.pattern() == txt)
        return;
    d->m_searchExpr.setPattern(txt);
    d->m_searchExpr.setPatternSyntax(QRegExp::FixedString);
    d->m_searchExpr.setCaseSensitivity((findFlags & QTextDocument::FindCaseSensitively) ?
                                       Qt::CaseSensitive : Qt::CaseInsensitive);
    d->m_findFlags = findFlags;
    viewport()->update();
}


void BaseTextEditor::setFindScope(const QTextCursor &scope)
{
    if (scope.isNull() != d->m_findScope.isNull()) {
        d->m_findScope = scope;
        viewport()->update();
    }
}

void BaseTextEditor::_q_matchParentheses()
{
    if (isReadOnly())
        return;

    QTextCursor backwardMatch = textCursor();
    QTextCursor forwardMatch = textCursor();
    const TextBlockUserData::MatchType backwardMatchType = TextBlockUserData::matchCursorBackward(&backwardMatch);
    const TextBlockUserData::MatchType forwardMatchType = TextBlockUserData::matchCursorForward(&forwardMatch);

    if (backwardMatchType == TextBlockUserData::NoMatch && forwardMatchType == TextBlockUserData::NoMatch)
        return;

    QList<QTextEdit::ExtraSelection> extraSelections;
con's avatar
con committed

    if (backwardMatch.hasSelection()) {
        QTextEdit::ExtraSelection sel;
        if (backwardMatchType == TextBlockUserData::Mismatch) {
            sel.cursor = backwardMatch;
            sel.format = d->m_mismatchFormat;
        } else {

            if (d->m_formatRange) {
                sel.cursor = backwardMatch;
                sel.format = d->m_rangeFormat;
                extraSelections.append(sel);
            }

            sel.cursor = backwardMatch;
            sel.format = d->m_matchFormat;

            sel.cursor.setPosition(backwardMatch.selectionStart());
            sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
            extraSelections.append(sel);

            sel.cursor.setPosition(backwardMatch.selectionEnd());
            sel.cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
        }
        extraSelections.append(sel);
    }

    if (forwardMatch.hasSelection()) {
        QTextEdit::ExtraSelection sel;
        if (forwardMatchType == TextBlockUserData::Mismatch) {
            sel.cursor = forwardMatch;
            sel.format = d->m_mismatchFormat;
        } else {

            if (d->m_formatRange) {
                sel.cursor = forwardMatch;
                sel.format = d->m_rangeFormat;
                extraSelections.append(sel);
            }

            sel.cursor = forwardMatch;
            sel.format = d->m_matchFormat;

            sel.cursor.setPosition(forwardMatch.selectionStart());
            sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
            extraSelections.append(sel);

            sel.cursor.setPosition(forwardMatch.selectionEnd());
            sel.cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
        }
        extraSelections.append(sel);
    }
    setExtraSelections(ParenthesesMatchingSelection, extraSelections);
con's avatar
con committed
}

void BaseTextEditor::setActionHack(QObject *hack)
{
    d->m_actionHack = hack;
}

QObject *BaseTextEditor::actionHack() const
{
    return d->m_actionHack;
}

void BaseTextEditor::changeEvent(QEvent *e)
{
    QPlainTextEdit::changeEvent(e);
    if (e->type() == QEvent::ApplicationFontChange
        || e->type() == QEvent::FontChange) {
        if (d->m_extraArea) {
            QFont f = d->m_extraArea->font();
            f.setPointSize(font().pointSize());
            d->m_extraArea->setFont(f);
            slotUpdateExtraAreaWidth();
            d->m_extraArea->update();
        }
    }
}

// shift+del
void BaseTextEditor::deleteLine()
{
    QTextCursor cursor = textCursor();
    if (!cursor.hasSelection()) {
        const QTextBlock &block = cursor.block();
        if (block.next().isValid()) {
            cursor.setPosition(block.position());
            cursor.setPosition(block.next().position(), QTextCursor::KeepAnchor);
        } else {
            cursor.movePosition(QTextCursor::EndOfBlock);
            cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
            cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
        }
        setTextCursor(cursor);
    }
    cut();
}

void BaseTextEditor::setExtraSelections(ExtraSelectionKind kind, const QList<QTextEdit::ExtraSelection> &selections)
con's avatar
con committed
{
    if (selections.isEmpty() && d->m_extraSelections[kind].isEmpty())
        return;
    d->m_extraSelections[kind] = selections;

    QList<QTextEdit::ExtraSelection> all;
    for (int i = 0; i < NExtraSelectionKinds; ++i)
        all += d->m_extraSelections[i];
    QPlainTextEdit::setExtraSelections(all);
con's avatar
con committed
}

QList<QTextEdit::ExtraSelection> BaseTextEditor::extraSelections(ExtraSelectionKind kind) const
con's avatar
con committed
{
    return d->m_extraSelections[kind];
con's avatar
con committed
}


// the blocks list must be sorted
void BaseTextEditor::setIfdefedOutBlocks(const QList<BaseTextEditor::BlockRange> &blocks)
{
    QTextDocument *doc = document();
    TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
hjk's avatar
hjk committed
    QTC_ASSERT(documentLayout, return);
con's avatar
con committed

    bool needUpdate = false;

    QTextBlock block = doc->firstBlock();

    int rangeNumber = 0;
    while (block.isValid()) {
        if (rangeNumber < blocks.size()) {
            const BlockRange &range = blocks.at(rangeNumber);

            if (block.position() >= range.first && (block.position() <= range.last || !range.last)) {
                needUpdate |= TextEditDocumentLayout::setIfdefedOut(block);
con's avatar
con committed
            } else {
                needUpdate |= TextEditDocumentLayout::clearIfdefedOut(block);
con's avatar
con committed
            }
            if (block.contains(range.last))
                ++rangeNumber;
        } else {
            needUpdate |= TextEditDocumentLayout::clearIfdefedOut(block);
        }

        block = block.next();
    }

    if (needUpdate)
        documentLayout->requestUpdate();
}

void BaseTextEditor::format()
{
    QTextCursor cursor = textCursor();
    cursor.beginEditBlock();
    indent(document(), cursor, QChar::Null);
    cursor.endEditBlock();
}
con's avatar
con committed

void BaseTextEditor::unCommentSelection()
con's avatar
con committed
{
}

void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs)
{
    const QTextCharFormat textFormat = fs.toTextCharFormat(QLatin1String(Constants::C_TEXT));
    const QTextCharFormat selectionFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SELECTION));
    const QTextCharFormat lineNumberFormat = fs.toTextCharFormat(QLatin1String(Constants::C_LINE_NUMBER));
    const QTextCharFormat searchResultFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SEARCH_RESULT));
    const QTextCharFormat searchScopeFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SEARCH_SCOPE));
    const QTextCharFormat parenthesesFormat = fs.toTextCharFormat(QLatin1String(Constants::C_PARENTHESES));
    const QTextCharFormat currentLineFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE));
    const QTextCharFormat ifdefedOutFormat = fs.toTextCharFormat(QLatin1String(Constants::C_DISABLED_CODE));
    QFont font(textFormat.font());

    const QColor foreground = textFormat.foreground().color();
    const QColor background = textFormat.background().color();
    QPalette p = palette();
    p.setColor(QPalette::Text, foreground);
    p.setColor(QPalette::Foreground, foreground);
    p.setColor(QPalette::Base, background);
    p.setColor(QPalette::Highlight, (selectionFormat.background().style() != Qt::NoBrush) ?
               selectionFormat.background().color() :
               QApplication::palette().color(QPalette::Highlight));
    p.setColor(QPalette::HighlightedText, selectionFormat.foreground().color());
    p.setBrush(QPalette::Inactive, QPalette::Highlight, p.highlight());
    p.setBrush(QPalette::Inactive, QPalette::HighlightedText, p.highlightedText());
    setPalette(p);
    setFont(font);
    setTabSettings(d->m_document->tabSettings()); // update tabs, they depend on the font

    // Line numbers
    QPalette ep = d->m_extraArea->palette();
    ep.setColor(QPalette::Dark, lineNumberFormat.foreground().color());
    ep.setColor(QPalette::Background, lineNumberFormat.background().style() != Qt::NoBrush ?
                lineNumberFormat.background().color() : background);
    d->m_extraArea->setPalette(ep);

    // Search results
    d->m_searchResultFormat.setBackground(searchResultFormat.background());
    d->m_searchScopeFormat.setBackground(searchScopeFormat.background());
    d->m_currentLineFormat.setBackground(currentLineFormat.background());

    // Matching braces
    d->m_matchFormat.setForeground(parenthesesFormat.foreground());
    d->m_rangeFormat.setBackground(parenthesesFormat.background());

    // Disabled code
    d->m_ifdefedOutFormat.setForeground(ifdefedOutFormat.foreground());

    slotUpdateExtraAreaWidth();
}

void BaseTextEditor::setTabSettings(const TabSettings &ts)
{
    d->m_document->setTabSettings(ts);
    int charWidth = QFontMetrics(font()).width(QChar(' '));
    setTabStopWidth(charWidth * ts.m_tabSize);
}

void BaseTextEditor::setDisplaySettings(const DisplaySettings &ds)
{
    setLineWrapMode(ds.m_textWrapping ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap);
    setLineNumbersVisible(ds.m_displayLineNumbers);
    setVisibleWrapColumn(ds.m_showWrapColumn ? ds.m_wrapColumn : 0);
    setCodeFoldingVisible(ds.m_displayFoldingMarkers);
    setHighlightCurrentLine(ds.m_highlightCurrentLine);
    setHighlightBlocks(ds.m_highlightBlocks);

    if (d->m_displaySettings.m_visualizeWhitespace != ds.m_visualizeWhitespace) {
        if (QSyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter())
            highlighter->rehighlight();
        QTextOption option =  document()->defaultTextOption();
        if (ds.m_visualizeWhitespace)
            option.setFlags(option.flags() | QTextOption::ShowTabsAndSpaces);
        else
            option.setFlags(option.flags() & ~QTextOption::ShowTabsAndSpaces);
        option.setFlags(option.flags() | QTextOption::AddSpaceForLineAndParagraphSeparators);
        document()->setDefaultTextOption(option);
con's avatar
con committed
    }

    d->m_displaySettings = ds;
}

void BaseTextEditor::setStorageSettings(const StorageSettings &storageSettings)
{
    d->m_document->setStorageSettings(storageSettings);
con's avatar
con committed
}

void BaseTextEditor::collapse()
{
    QTextDocument *doc = document();
    TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
hjk's avatar
hjk committed
    QTC_ASSERT(documentLayout, return);
con's avatar
con committed
    QTextBlock block = textCursor().block();
    QTextBlock curBlock = block;
con's avatar
con committed
    while (block.isValid()) {
        if (TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
mae's avatar
mae committed
            if (block == curBlock || block.next() == curBlock)
                break;
            if ((block.next().userState()) >> 8 <= (curBlock.previous().userState() >> 8))
con's avatar
con committed
                break;
        }
        block = block.previous();
    }
    if (block.isValid()) {
        TextBlockUserData::doCollapse(block, false);
        d->moveCursorVisible();
        documentLayout->requestUpdate();
        documentLayout->emitDocumentSizeChanged();
    }
}

void BaseTextEditor::expand()
{
    QTextDocument *doc = document();
    TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
hjk's avatar
hjk committed
    QTC_ASSERT(documentLayout, return);
con's avatar
con committed
    QTextBlock block = textCursor().block();
    while (block.isValid() && !block.isVisible())
        block = block.previous();
    TextBlockUserData::doCollapse(block, true);
    d->moveCursorVisible();
    documentLayout->requestUpdate();
    documentLayout->emitDocumentSizeChanged();
}

void BaseTextEditor::unCollapseAll()
{
    QTextDocument *doc = document();
    TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
hjk's avatar
hjk committed
    QTC_ASSERT(documentLayout, return);
con's avatar
con committed

    QTextBlock block = doc->firstBlock();
    bool makeVisible = true;
    while (block.isValid()) {
        if (block.isVisible() && TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
            makeVisible = false;
            break;
        }
        block = block.next();
    }

    block = doc->firstBlock();

    while (block.isValid()) {
        if (TextBlockUserData::canCollapse(block))
            TextBlockUserData::doCollapse(block, makeVisible);
        block = block.next();
    }

    d->moveCursorVisible();
    documentLayout->requestUpdate();
    documentLayout->emitDocumentSizeChanged();
con's avatar
con committed
}

void BaseTextEditor::setTextCodec(QTextCodec *codec)
{
    baseTextDocument()->setCodec(codec);
}

QTextCodec *BaseTextEditor::textCodec() const
{
    return baseTextDocument()->codec();
}

void BaseTextEditor::setReadOnly(bool b)
{
    QPlainTextEdit::setReadOnly(b);
    if (b)
        setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard);
}

void BaseTextEditor::cut()
{
    if (d->m_inBlockSelectionMode) {
        copy();
        d->removeBlockSelection();
        return;
    }
    QPlainTextEdit::cut();
}

void BaseTextEditor::paste()
{
    if (d->m_inBlockSelectionMode) {
        d->removeBlockSelection();
    }
    QPlainTextEdit::paste();
}

con's avatar
con committed
QMimeData *BaseTextEditor::createMimeDataFromSelection() const
{
    if (d->m_inBlockSelectionMode) {
        QMimeData *mimeData = new QMimeData;
        QString text = d->copyBlockSelection();
        mimeData->setData(QLatin1String("application/vnd.nokia.qtcreator.blocktext"), text.toUtf8());
        mimeData->setText(text); // for exchangeability
        return mimeData;
    }
    return QPlainTextEdit::createMimeDataFromSelection();
}

bool BaseTextEditor::canInsertFromMimeData(const QMimeData *source) const
{
    return QPlainTextEdit::canInsertFromMimeData(source);
}

void BaseTextEditor::insertFromMimeData(const QMimeData *source)
{
    if (!isReadOnly() && source->hasFormat(QLatin1String("application/vnd.nokia.qtcreator.blocktext"))) {
        QString text = QString::fromUtf8(source->data(QLatin1String("application/vnd.nokia.qtcreator.blocktext")));
        if (text.isEmpty())
            return;
        QStringList lines = text.split(QLatin1Char('\n'));
        QTextCursor cursor = textCursor();
        cursor.beginEditBlock();
        int initialCursorPosition = cursor.position();
        int column = cursor.position() - cursor.block().position();
        cursor.insertText(lines.first());
        for (int i = 1; i < lines.count(); ++i) {
            QTextBlock next = cursor.block().next();
            if (next.isValid()) {
                cursor.setPosition(next.position() + qMin(column, next.length()-1));
            } else {
                cursor.movePosition(QTextCursor::EndOfBlock);
                cursor.insertBlock();
            }

            int actualColumn = cursor.position() - cursor.block().position();
            if (actualColumn < column)
                cursor.insertText(QString(column - actualColumn, QLatin1Char(' ')));
            cursor.insertText(lines.at(i));
        }
        cursor.setPosition(initialCursorPosition);
        cursor.endEditBlock();
        setTextCursor(cursor);
        ensureCursorVisible();
        return;
    }
    QPlainTextEdit::insertFromMimeData(source);
}

BaseTextEditorEditable::BaseTextEditorEditable(BaseTextEditor *editor)
  : e(editor)
{
#ifndef TEXTEDITOR_STANDALONE
    using namespace Find;
    Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
    BaseTextFind *baseTextFind = new BaseTextFind(editor);
    connect(baseTextFind, SIGNAL(highlightAll(QString, QTextDocument::FindFlags)),
            editor, SLOT(highlightSearchResults(QString, QTextDocument::FindFlags)));
    connect(baseTextFind, SIGNAL(findScopeChanged(QTextCursor)), editor, SLOT(setFindScope(QTextCursor)));
    aggregate->add(baseTextFind);
    aggregate->add(editor);
#endif

    m_cursorPositionLabel = new Core::Utils::LineColumnLabel;

    QHBoxLayout *l = new QHBoxLayout;
    QWidget *w = new QWidget;
    l->setMargin(0);
    l->setContentsMargins(0, 0, 5, 0);
    l->addStretch(1);
    l->addWidget(m_cursorPositionLabel);
    w->setLayout(l);

    m_toolBar = new QToolBar;
    m_toolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    m_toolBar->addWidget(w);

    connect(editor, SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition()));
}

BaseTextEditorEditable::~BaseTextEditorEditable()
{
    delete m_toolBar;
    delete e;
}

QToolBar *BaseTextEditorEditable::toolBar()
{
    return m_toolBar;
}

int BaseTextEditorEditable::find(const QString &) const
{
    return 0;
}

int BaseTextEditorEditable::currentLine() const
{
    return e->textCursor().blockNumber() + 1;
}

int BaseTextEditorEditable::currentColumn() const
{
    QTextCursor cursor = e->textCursor();
    return cursor.position() - cursor.block().position() + 1;
}

QRect BaseTextEditorEditable::cursorRect(int pos) const
{
    QTextCursor tc = e->textCursor();
    if (pos >= 0)
        tc.setPosition(pos);
    QRect result = e->cursorRect(tc);
    result.moveTo(e->viewport()->mapToGlobal(result.topLeft()));
    return result;
}

QString BaseTextEditorEditable::contents() const
{
    return e->toPlainText();
}

QString BaseTextEditorEditable::selectedText() const
{
    if (e->textCursor().hasSelection())
        return e->textCursor().selectedText();
    return QString();
}

QString BaseTextEditorEditable::textAt(int pos, int length) const
{
    QTextCursor c = e->textCursor();

    if (pos < 0)
        pos = 0;
    c.movePosition(QTextCursor::End);
    if (pos + length > c.position())
        length = c.position() - pos;

    c.setPosition(pos);
    c.setPosition(pos + length, QTextCursor::KeepAnchor);

    return c.selectedText();
}

void BaseTextEditorEditable::remove(int length)
{
    QTextCursor tc = e->textCursor();
    tc.setPosition(tc.position() + length, QTextCursor::KeepAnchor);
    tc.removeSelectedText();
}

void BaseTextEditorEditable::insert(const QString &string)
{
    QTextCursor tc = e->textCursor();
    tc.insertText(string);
}

void BaseTextEditorEditable::replace(int length, const QString &string)
{
    QTextCursor tc = e->textCursor();
    tc.setPosition(tc.position() + length, QTextCursor::KeepAnchor);
    tc.insertText(string);
}

void BaseTextEditorEditable::setCurPos(int pos)
{
    QTextCursor tc = e->textCursor();
    tc.setPosition(pos);
    e->setTextCursor(tc);
}

void BaseTextEditorEditable::select(int toPos)
{
    QTextCursor tc = e->textCursor();
    tc.setPosition(toPos, QTextCursor::KeepAnchor);
    e->setTextCursor(tc);
}

void BaseTextEditorEditable::updateCursorPosition()
{
    const QTextCursor cursor = e->textCursor();
    const QTextBlock block = cursor.block();
    const int line = block.blockNumber() + 1;
    const int column = cursor.position() - block.position() + 1;
    m_cursorPositionLabel->setText(tr("Line: %1, Col: %2").arg(line).arg(column),
                                   tr("Line: %1, Col: 999").arg(e->blockCount()));
con's avatar
con committed
    m_contextHelpId.clear();

    if (!block.isVisible())
        e->ensureCursorVisible();

}

QString BaseTextEditorEditable::contextHelpId() const
{
    if (m_contextHelpId.isEmpty())
        emit const_cast<BaseTextEditorEditable*>(this)->contextHelpIdRequested(e->editableInterface(),
                                                                               e->textCursor().position());
    return m_contextHelpId;
}


TextBlockUserData::~TextBlockUserData()
{
    TextMarks marks = m_marks;
    m_marks.clear();
    foreach (ITextMark *mrk, marks) {
        mrk->removedFromEditor();
    }
}