From e9ad023def7e6edb3f1c6ec2f99faa3584f615eb Mon Sep 17 00:00:00 2001 From: mae <qtc-committer@nokia.com> Date: Thu, 4 Dec 2008 18:37:02 +0100 Subject: [PATCH] block navigation and selection (bound to Ctrl+[]{} --- src/plugins/find/basetextfind.cpp | 5 +- src/plugins/texteditor/basetexteditor.cpp | 118 +++++++++++++++++- src/plugins/texteditor/basetexteditor.h | 10 ++ .../texteditor/texteditoractionhandler.cpp | 94 +++++++------- .../texteditor/texteditoractionhandler.h | 8 ++ src/plugins/texteditor/texteditorconstants.h | 6 + 6 files changed, 189 insertions(+), 52 deletions(-) diff --git a/src/plugins/find/basetextfind.cpp b/src/plugins/find/basetextfind.cpp index 63740d36527..6598a47e6f3 100644 --- a/src/plugins/find/basetextfind.cpp +++ b/src/plugins/find/basetextfind.cpp @@ -162,7 +162,10 @@ int BaseTextFind::replaceAll(const QString &before, const QString &after, QTextDocument::FindFlags findFlags) { QTextCursor editCursor = textCursor(); - editCursor.movePosition(QTextCursor::Start); + if (!m_findScope.isNull()) + editCursor.setPosition(m_findScope.selectionStart()); + else + editCursor.movePosition(QTextCursor::Start); editCursor.beginEditBlock(); int count = 0; QTextCursor found; diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index df5fe410808..a0cf9dee3b0 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -531,7 +531,6 @@ void BaseTextEditor::selectEncoding() } } - void DocumentMarker::updateMark(ITextMark *mark) { TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document->documentLayout()); @@ -600,6 +599,36 @@ void BaseTextEditor::slotSelectionChanged() d->m_blockSelectionExtraX = 0; } +void BaseTextEditor::gotoBlockStart() +{ + QTextCursor cursor = textCursor(); + if (TextBlockUserData::findPreviousOpenParenthesis(&cursor, false)) + setTextCursor(cursor); +} + +void BaseTextEditor::gotoBlockEnd() +{ + QTextCursor cursor = textCursor(); + if (TextBlockUserData::findNextClosingParenthesis(&cursor, false)) + setTextCursor(cursor); +} + +void BaseTextEditor::gotoBlockStartWithSelection() +{ + QTextCursor cursor = textCursor(); + if (TextBlockUserData::findPreviousOpenParenthesis(&cursor, true)) + setTextCursor(cursor); +} + +void BaseTextEditor::gotoBlockEndWithSelection() +{ + QTextCursor cursor = textCursor(); + if (TextBlockUserData::findNextClosingParenthesis(&cursor, true)) + setTextCursor(cursor); +} + + + void BaseTextEditor::keyPressEvent(QKeyEvent *e) { @@ -633,6 +662,11 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) e->accept(); return; } + } else if (e == QKeySequence::Paste) { + if (!ro) { + d->removeBlockSelection(); + // continue + } } } @@ -693,6 +727,8 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) break; case Qt::Key_Home: if (!(e == QKeySequence::MoveToStartOfDocument) && !(e == QKeySequence::SelectStartOfDocument)) { + if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) + d->m_lastEventWasBlockSelectionEvent = true; handleHomeKey(e->modifiers() & Qt::ShiftModifier); e->accept(); return; @@ -708,6 +744,7 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) return; } // fall through + case Qt::Key_End: case Qt::Key_Right: case Qt::Key_Left: #ifndef Q_OS_MAC @@ -795,6 +832,15 @@ skip_event: delete e; } +void BaseTextEditor::setTextCursor(const QTextCursor &cursor) +{ + // workaround for QTextControl bug + bool selectionChange = cursor.hasSelection() || textCursor().hasSelection(); + QPlainTextEdit::setTextCursor(cursor); + if (selectionChange) + slotSelectionChanged(); +} + void BaseTextEditor::gotoLine(int line, int column) { const int blockNumber = line - 1; @@ -2908,6 +2954,61 @@ TextBlockUserData::MatchType TextBlockUserData::checkClosedParenthesis(QTextCurs } } + +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()) { + for (int i = parenList.count()-1; i >= 0; --i) { + Parenthesis paren = parenList.at(i); + if (block == cursor->block() && position - block.position() <= paren.pos + 1) + 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()) { + 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; +} + TextBlockUserData::MatchType TextBlockUserData::matchCursorBackward(QTextCursor *cursor) { cursor->clearSelection(); @@ -3152,13 +3253,16 @@ void BaseTextEditor::collapse() TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout()); Q_ASSERT(documentLayout); QTextBlock block = textCursor().block(); + qDebug() << "collapse at block" << block.blockNumber(); while (block.isValid()) { - if (TextBlockUserData::canCollapse(block)) { - if ((block.next().userState()) >> 8 == (textCursor().block().userState() >> 8)) + qDebug() << "test block" << block.blockNumber(); + if (TextBlockUserData::canCollapse(block) && block.next().isVisible()) { + if ((block.next().userState()) >> 8 <= (textCursor().block().userState() >> 8)) break; } block = block.previous(); } + qDebug() << "found" << block.blockNumber(); if (block.isValid()) { TextBlockUserData::doCollapse(block, false); d->moveCursorVisible(); @@ -3238,6 +3342,14 @@ void BaseTextEditor::cut() QPlainTextEdit::cut(); } +void BaseTextEditor::paste() +{ + if (d->m_inBlockSelectionMode) { + d->removeBlockSelection(); + } + QPlainTextEdit::paste(); +} + QMimeData *BaseTextEditor::createMimeDataFromSelection() const { if (d->m_inBlockSelectionMode) { diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index ced22900030..54e4728c4b4 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -169,6 +169,8 @@ public: static MatchType checkClosedParenthesis(QTextCursor *cursor, QChar c); static MatchType matchCursorBackward(QTextCursor *cursor); static MatchType matchCursorForward(QTextCursor *cursor); + static bool findPreviousOpenParenthesis(QTextCursor *cursor, bool select = false); + static bool findNextClosingParenthesis(QTextCursor *cursor, bool select = false); private: @@ -298,6 +300,8 @@ public: void setReadOnly(bool b); + void setTextCursor(const QTextCursor &cursor); + public slots: void setDisplayName(const QString &title); virtual void setFontSettings(const TextEditor::FontSettings &); @@ -305,6 +309,7 @@ public slots: virtual void unCommentSelection(); virtual void setStorageSettings(const TextEditor::StorageSettings &); + void paste(); void cut(); void zoomIn(int range = 1); @@ -316,6 +321,11 @@ public slots: void expand(); void selectEncoding(); + void gotoBlockStart(); + void gotoBlockEnd(); + void gotoBlockStartWithSelection(); + void gotoBlockEndWithSelection(); + signals: void changed(); diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp index 94cdca6cfda..a9e955eae36 100644 --- a/src/plugins/texteditor/texteditoractionhandler.cpp +++ b/src/plugins/texteditor/texteditoractionhandler.cpp @@ -67,6 +67,8 @@ TextEditorActionHandler::TextEditorActionHandler(Core::ICore *core, = m_collapseAction = m_expandAction = m_deleteLineAction = m_selectEncodingAction = m_increaseFontSizeAction = m_decreaseFontSizeAction + = m_gotoBlockStartAction = m_gotoBlockStartWithSelectionAction + = m_gotoBlockEndAction = m_gotoBlockEndWithSelectionAction = 0; m_contextId << m_core->uniqueIDManager()->uniqueIdentifier(context); @@ -185,6 +187,27 @@ void TextEditorActionHandler::createActions() command->setDefaultKeySequence(QKeySequence(tr("Ctrl+-"))); connect(m_decreaseFontSizeAction, SIGNAL(triggered()), this, SLOT(decreaseFontSize())); advancedMenu->addAction(command); + + m_gotoBlockStartAction = new QAction(tr("Goto Block Start"), this); + command = am->registerAction(m_gotoBlockStartAction, Constants::GOTO_BLOCK_START, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+["))); + connect(m_gotoBlockStartAction, SIGNAL(triggered()), this, SLOT(gotoBlockStart())); + + m_gotoBlockEndAction = new QAction(tr("Goto Block End"), this); + command = am->registerAction(m_gotoBlockEndAction, Constants::GOTO_BLOCK_END, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+]"))); + connect(m_gotoBlockEndAction, SIGNAL(triggered()), this, SLOT(gotoBlockEnd())); + + m_gotoBlockStartWithSelectionAction = new QAction(tr("Goto Block Start With Selection"), this); + command = am->registerAction(m_gotoBlockStartWithSelectionAction, Constants::GOTO_BLOCK_START_WITH_SELECTION, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+{"))); + connect(m_gotoBlockStartWithSelectionAction, SIGNAL(triggered()), this, SLOT(gotoBlockStartWithSelection())); + + m_gotoBlockEndWithSelectionAction = new QAction(tr("Goto Block End With Selection"), this); + command = am->registerAction(m_gotoBlockEndWithSelectionAction, Constants::GOTO_BLOCK_END_WITH_SELECTION, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+}"))); + connect(m_gotoBlockEndWithSelectionAction, SIGNAL(triggered()), this, SLOT(gotoBlockEndWithSelection())); + } bool TextEditorActionHandler::supportsAction(const QString & /*id */) const @@ -365,54 +388,29 @@ void TextEditorActionHandler::setTextWrapping(bool checked) } } -void TextEditorActionHandler::unCommentSelection() -{ - if (m_currentEditor) - m_currentEditor->unCommentSelection(); -} - -void TextEditorActionHandler::deleteLine() -{ - if (m_currentEditor) - m_currentEditor->deleteLine(); -} - -void TextEditorActionHandler::unCollapseAll() -{ - if (m_currentEditor) - m_currentEditor->unCollapseAll(); -} - -void TextEditorActionHandler::collapse() -{ - if (m_currentEditor) - m_currentEditor->collapse(); -} - -void TextEditorActionHandler::expand() -{ - if (m_currentEditor) - m_currentEditor->expand(); -} - -void TextEditorActionHandler::selectEncoding() -{ - if (m_currentEditor) - m_currentEditor->selectEncoding(); -} - -void TextEditorActionHandler::increaseFontSize() -{ - if (m_currentEditor) - m_currentEditor->zoomIn(); -} - -void TextEditorActionHandler::decreaseFontSize() -{ - if (m_currentEditor) - m_currentEditor->zoomOut(); -} - +#define FUNCTION(funcname) void TextEditorActionHandler::funcname ()\ +{\ + if (m_currentEditor)\ + m_currentEditor->funcname ();\ +} +#define FUNCTION2(funcname, funcname2) void TextEditorActionHandler::funcname ()\ +{\ + if (m_currentEditor)\ + m_currentEditor->funcname2 ();\ +} + +FUNCTION(unCommentSelection) +FUNCTION(deleteLine) +FUNCTION(unCollapseAll) +FUNCTION(collapse) +FUNCTION(expand) +FUNCTION2(increaseFontSize, zoomIn) +FUNCTION2(decreaseFontSize, zoomOut) +FUNCTION(selectEncoding) +FUNCTION(gotoBlockStart) +FUNCTION(gotoBlockEnd) +FUNCTION(gotoBlockStartWithSelection) +FUNCTION(gotoBlockEndWithSelection) void TextEditorActionHandler::updateCurrentEditor(Core::IContext *object) { diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h index 79ac67c2178..f9fe9f249af 100644 --- a/src/plugins/texteditor/texteditoractionhandler.h +++ b/src/plugins/texteditor/texteditoractionhandler.h @@ -109,6 +109,10 @@ private slots: void selectEncoding(); void increaseFontSize(); void decreaseFontSize(); + void gotoBlockStart(); + void gotoBlockEnd(); + void gotoBlockStartWithSelection(); + void gotoBlockEndWithSelection(); void updateCurrentEditor(Core::IContext *object); private: @@ -131,6 +135,10 @@ private: QAction *m_selectEncodingAction; QAction *m_increaseFontSizeAction; QAction *m_decreaseFontSizeAction; + QAction *m_gotoBlockStartAction; + QAction *m_gotoBlockEndAction; + QAction *m_gotoBlockStartWithSelectionAction; + QAction *m_gotoBlockEndWithSelectionAction; uint m_optionalActions; QPointer<BaseTextEditor> m_currentEditor; diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index 8313f61fc3d..9415d732da9 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -48,9 +48,15 @@ const char * const UN_COLLAPSE_ALL = "TextEditor.UnCollapseAll"; const char * const AUTO_INDENT_SELECTION = "TextEditor.AutoIndentSelection"; const char * const INCREASE_FONT_SIZE = "TextEditor.IncreaseFontSize"; const char * const DECREASE_FONT_SIZE = "TextEditor.DecreaseFontSize"; +const char * const GOTO_BLOCK_START = "TextEditor.GotoBlockStart"; +const char * const GOTO_BLOCK_START_WITH_SELECTION = "TextEditor.GotoBlockStartWithSelection"; +const char * const GOTO_BLOCK_END = "TextEditor.GotoBlockEnd"; +const char * const GOTO_BLOCK_END_WITH_SELECTION = "TextEditor.GotoBlockEndWithSelection"; const char * const DELETE_LINE = "TextEditor.DeleteLine"; const char * const DELETE_WORD = "TextEditor.DeleteWord"; const char * const SELECT_ENCODING = "TextEditor.SelectEncoding"; +const char * const GOTO_OPENING_PARENTHESIS = "TextEditor.GotoOpeningParenthesis"; +const char * const GOTO_CLOSING_PARENTHESIS = "TextEditor.GotoOpeningParenthesis"; const char * const C_TEXTEDITOR_MIMETYPE_TEXT = "text/plain"; const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml"; -- GitLab