From: Leandro Melo Date: Tue, 2 Nov 2010 14:35:42 +0000 (+0100) Subject: Snippets: Synchronize editing of equivalent variables inside snippets. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=7eecf3940cc8d01e81db88454f86adbe88a12028;p=qt-creator-jp%2Fqt-creator-jp.git Snippets: Synchronize editing of equivalent variables inside snippets. When editing one variable from a code snippet, all other variables with the same name are updated accordingly. --- diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index d429277205..bf76217af7 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -1758,16 +1758,26 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) return; } - if (d->m_snippetOverlay->isVisible() - && (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)) { - d->snippetCheckCursor(textCursor()); - } - if (ro || e->text().isEmpty() || !e->text().at(0).isPrint()) { if (cursorMoveKeyEvent(e)) ; - else + else { + QTextCursor cursor = textCursor(); + bool cursorWithinSnippet = false; + if (d->m_snippetOverlay->isVisible() + && (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)) { + cursorWithinSnippet = d->snippetCheckCursor(cursor); + } + if (cursorWithinSnippet) + cursor.beginEditBlock(); + QPlainTextEdit::keyPressEvent(e); + + if (cursorWithinSnippet) { + cursor.endEditBlock(); + d->m_snippetOverlay->updateEquivalentSelections(textCursor()); + } + } } else if ((e->modifiers() & (Qt::ControlModifier|Qt::AltModifier)) != Qt::ControlModifier){ QTextCursor cursor = textCursor(); QString text = e->text(); @@ -1783,10 +1793,11 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) } } + bool cursorWithinSnippet = false; if (d->m_snippetOverlay->isVisible()) - d->snippetCheckCursor(cursor); + cursorWithinSnippet = d->snippetCheckCursor(cursor); - bool doEditBlock = !(electricChar.isNull() && autoText.isEmpty()); + bool doEditBlock = !electricChar.isNull() || !autoText.isEmpty() || cursorWithinSnippet; if (doEditBlock) cursor.beginEditBlock(); @@ -1806,8 +1817,11 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) cursor.setPosition(autoText.length() == 1 ? cursor.position() : cursor.anchor()); } - if (doEditBlock) + if (doEditBlock) { cursor.endEditBlock(); + if (cursorWithinSnippet) + d->m_snippetOverlay->updateEquivalentSelections(textCursor()); + } setTextCursor(cursor); } @@ -2431,10 +2445,10 @@ void BaseTextEditorPrivate::setupDocumentSignals(BaseTextDocument *document) } -void BaseTextEditorPrivate::snippetCheckCursor(const QTextCursor &cursor) +bool BaseTextEditorPrivate::snippetCheckCursor(const QTextCursor &cursor) { if (!m_snippetOverlay->isVisible() || m_snippetOverlay->isEmpty()) - return; + return false; QTextCursor start = cursor; start.setPosition(cursor.selectionStart()); @@ -2444,7 +2458,9 @@ void BaseTextEditorPrivate::snippetCheckCursor(const QTextCursor &cursor) || !m_snippetOverlay->hasCursorInSelection(end)) { m_snippetOverlay->setVisible(false); m_snippetOverlay->clear(); + return false; } + return true; } void BaseTextEditorPrivate::snippetTabOrBacktab(bool forward) @@ -2454,8 +2470,8 @@ void BaseTextEditorPrivate::snippetTabOrBacktab(bool forward) QTextCursor cursor = q->textCursor(); OverlaySelection final; if (forward) { - for (int i = 0; i < m_snippetOverlay->m_selections.count(); ++i){ - const OverlaySelection &selection = m_snippetOverlay->m_selections.at(i); + for (int i = 0; i < m_snippetOverlay->selections().count(); ++i){ + const OverlaySelection &selection = m_snippetOverlay->selections().at(i); if (selection.m_cursor_begin.position() >= cursor.position() && selection.m_cursor_end.position() > cursor.position()) { final = selection; @@ -2463,8 +2479,8 @@ void BaseTextEditorPrivate::snippetTabOrBacktab(bool forward) } } } else { - for (int i = m_snippetOverlay->m_selections.count()-1; i >= 0; --i){ - const OverlaySelection &selection = m_snippetOverlay->m_selections.at(i); + for (int i = m_snippetOverlay->selections().count()-1; i >= 0; --i){ + const OverlaySelection &selection = m_snippetOverlay->selections().at(i); if (selection.m_cursor_end.position() < cursor.position()) { final = selection; break; @@ -2473,7 +2489,7 @@ void BaseTextEditorPrivate::snippetTabOrBacktab(bool forward) } if (final.m_cursor_begin.isNull()) - final = forward ? m_snippetOverlay->m_selections.first() : m_snippetOverlay->m_selections.last(); + final = forward ? m_snippetOverlay->selections().first() : m_snippetOverlay->selections().last(); if (final.m_cursor_begin.position() == final.m_cursor_end.position()) { // empty tab stop cursor.setPosition(final.m_cursor_end.position()); @@ -2484,7 +2500,6 @@ void BaseTextEditorPrivate::snippetTabOrBacktab(bool forward) q->setTextCursor(cursor); } - bool BaseTextEditor::viewportEvent(QEvent *event) { d->m_contentsChanged = false; @@ -4382,18 +4397,17 @@ void BaseTextEditor::handleHomeKey(bool anchor) setTextCursor(cursor); } - -#define SET_AND_RETURN(cursor) setTextCursor(cursor); return // make cursor visible and reset vertical x movement void BaseTextEditor::handleBackspaceKey() { QTextCursor cursor = textCursor(); int pos = cursor.position(); QTC_ASSERT(!cursor.hasSelection(), return); + bool cursorWithinSnippet = false; if (d->m_snippetOverlay->isVisible()) { QTextCursor snippetCursor = cursor; snippetCursor.movePosition(QTextCursor::Left); - d->snippetCheckCursor(snippetCursor); + cursorWithinSnippet = d->snippetCheckCursor(snippetCursor); } const TextEditor::TabSettings &tabSettings = d->m_document->tabSettings(); @@ -4401,40 +4415,58 @@ void BaseTextEditor::handleBackspaceKey() if (tabSettings.m_autoIndent && d->m_autoCompleter->autoBackspace(cursor)) return; + bool handled = false; if (!tabSettings.m_smartBackspace) { + if (cursorWithinSnippet) + cursor.beginEditBlock(); cursor.deletePreviousChar(); - SET_AND_RETURN(cursor); + handled = true; + } else { + QTextBlock currentBlock = cursor.block(); + int positionInBlock = pos - currentBlock.position(); + const QString blockText = currentBlock.text(); + if (cursor.atBlockStart() || tabSettings.firstNonSpace(blockText) < positionInBlock) { + if (cursorWithinSnippet) + cursor.beginEditBlock(); + cursor.deletePreviousChar(); + handled = true; + } else { + int previousIndent = 0; + const int indent = tabSettings.columnAt(blockText, positionInBlock); + + for (QTextBlock previousNonEmptyBlock = currentBlock.previous(); + previousNonEmptyBlock.isValid(); + previousNonEmptyBlock = previousNonEmptyBlock.previous()) { + QString previousNonEmptyBlockText = previousNonEmptyBlock.text(); + if (previousNonEmptyBlockText.trimmed().isEmpty()) + continue; + previousIndent = + tabSettings.columnAt(previousNonEmptyBlockText, + tabSettings.firstNonSpace(previousNonEmptyBlockText)); + if (previousIndent < indent) { + cursor.beginEditBlock(); + cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor); + cursor.insertText(tabSettings.indentationString(previousNonEmptyBlockText)); + cursor.endEditBlock(); + handled = true; + break; + } + } + } } - QTextBlock currentBlock = cursor.block(); - int positionInBlock = pos - currentBlock.position(); - const QString blockText = currentBlock.text(); - if (cursor.atBlockStart() || tabSettings.firstNonSpace(blockText) < positionInBlock) { + if (!handled) { + if (cursorWithinSnippet) + cursor.beginEditBlock(); cursor.deletePreviousChar(); - SET_AND_RETURN(cursor); } - int previousIndent = 0; - const int indent = tabSettings.columnAt(blockText, positionInBlock); - - for (QTextBlock previousNonEmptyBlock = currentBlock.previous(); - previousNonEmptyBlock.isValid(); - previousNonEmptyBlock = previousNonEmptyBlock.previous()) { - QString previousNonEmptyBlockText = previousNonEmptyBlock.text(); - if (previousNonEmptyBlockText.trimmed().isEmpty()) - continue; - previousIndent = tabSettings.columnAt(previousNonEmptyBlockText, - tabSettings.firstNonSpace(previousNonEmptyBlockText)); - if (previousIndent < indent) { - cursor.beginEditBlock(); - cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor); - cursor.insertText(tabSettings.indentationString(previousNonEmptyBlockText)); - cursor.endEditBlock(); - SET_AND_RETURN(cursor); - } + if (cursorWithinSnippet) { + cursor.endEditBlock(); + d->m_snippetOverlay->updateEquivalentSelections(cursor); } - cursor.deletePreviousChar(); - SET_AND_RETURN(cursor); + + setTextCursor(cursor); } void BaseTextEditor::wheelEvent(QWheelEvent *e) @@ -4997,6 +5029,7 @@ void BaseTextEditor::setExtraSelections(ExtraSelectionKind kind, const QListm_snippetOverlay->mapEquivalentSelections(); d->m_snippetOverlay->setVisible(!d->m_snippetOverlay->isEmpty()); } else { QList all; diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index d658899cd1..f4d688c04f 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -215,7 +215,7 @@ public: TextEditorOverlay *m_overlay; TextEditorOverlay *m_snippetOverlay; TextEditorOverlay *m_searchResultOverlay; - void snippetCheckCursor(const QTextCursor &cursor); + bool snippetCheckCursor(const QTextCursor &cursor); void snippetTabOrBacktab(bool forward); QTextCharFormat m_occurrencesFormat; QTextCharFormat m_occurrenceRenameFormat; diff --git a/src/plugins/texteditor/texteditoroverlay.cpp b/src/plugins/texteditor/texteditoroverlay.cpp index 8cfb018a86..5059b20945 100644 --- a/src/plugins/texteditor/texteditoroverlay.cpp +++ b/src/plugins/texteditor/texteditoroverlay.cpp @@ -30,20 +30,22 @@ #include "texteditoroverlay.h" #include "basetexteditor.h" +#include #include #include using namespace TextEditor; using namespace TextEditor::Internal; -TextEditorOverlay::TextEditorOverlay(BaseTextEditor *editor) - :QObject(editor) { - m_visible = false; - m_borderWidth = 1; - m_dropShadowWidth = 2; - m_editor = editor; - m_alpha = true; - m_viewport = editor->viewport(); +TextEditorOverlay::TextEditorOverlay(BaseTextEditor *editor) : + QObject(editor), + m_visible(false), + m_borderWidth(1), + m_dropShadowWidth(2), + m_alpha(true), + m_editor(editor), + m_viewport(editor->viewport()) +{ } void TextEditorOverlay::update() @@ -448,11 +450,78 @@ void TextEditorOverlay::fill(QPainter *painter, const QColor &color, const QRect */ bool TextEditorOverlay::hasCursorInSelection(const QTextCursor &cursor) const { + if (selectionIndexForCursor(cursor) != -1) + return true; + return false; +} + +int TextEditorOverlay::selectionIndexForCursor(const QTextCursor &cursor) const +{ for (int i = 0; i < m_selections.size(); ++i) { const OverlaySelection &selection = m_selections.at(i); if (cursor.position() >= selection.m_cursor_begin.position() && cursor.position() <= selection.m_cursor_end.position()) - return true; + return i; + } + return -1; +} + +QString TextEditorOverlay::selectionText(int selectionIndex) const +{ + return assembleCursorForSelection(selectionIndex).selectedText(); +} + +QTextCursor TextEditorOverlay::assembleCursorForSelection(int selectionIndex) const +{ + const OverlaySelection &selection = m_selections.at(selectionIndex); + QTextCursor cursor(m_editor->document()); + cursor.setPosition(selection.m_cursor_begin.position()); + cursor.setPosition(selection.m_cursor_end.position(), QTextCursor::KeepAnchor); + return cursor; +} + +void TextEditorOverlay::mapEquivalentSelections() +{ + m_equivalentSelections.clear(); + m_equivalentSelections.resize(m_selections.size()); + + QMap all; + for (int i = 0; i < m_selections.size(); ++i) + all.insertMulti(selectionText(i), i); + + const QList &uniqueKeys = all.uniqueKeys(); + foreach (const QString &key, uniqueKeys) { + QList indexes; + QMap::const_iterator lbit = all.lowerBound(key); + QMap::const_iterator ubit = all.upperBound(key); + while (lbit != ubit) { + indexes.append(lbit.value()); + ++lbit; + } + + foreach (int index, indexes) + m_equivalentSelections[index] = indexes; + } +} + +void TextEditorOverlay::updateEquivalentSelections(const QTextCursor &cursor) +{ + int selectionIndex = selectionIndexForCursor(cursor); + if (selectionIndex == -1) + return; + + const QString ¤tText = selectionText(selectionIndex); + const QList &equivalents = m_equivalentSelections.at(selectionIndex); + foreach (int i, equivalents) { + if (i == selectionIndex) + continue; + const QString &equivalentText = selectionText(i); + if (currentText != equivalentText) { + QTextCursor selectionCursor = assembleCursorForSelection(i); + selectionCursor.joinPreviousEditBlock(); + selectionCursor.removeSelectedText(); + selectionCursor.insertText(currentText); + selectionCursor.endEditBlock(); + } } - return false; } diff --git a/src/plugins/texteditor/texteditoroverlay.h b/src/plugins/texteditor/texteditoroverlay.h index f64bb08bae..48a61ad1c8 100644 --- a/src/plugins/texteditor/texteditoroverlay.h +++ b/src/plugins/texteditor/texteditoroverlay.h @@ -31,7 +31,8 @@ #define TEXTEDITOROVERLAY_H #include - +#include +#include #include #include @@ -45,6 +46,7 @@ namespace Internal { struct OverlaySelection { OverlaySelection():m_fixedLength(-1), m_dropShadow(false){} + QTextCursor m_cursor_begin; QTextCursor m_cursor_end; QColor m_fg; @@ -56,18 +58,6 @@ struct OverlaySelection class TextEditorOverlay : public QObject { Q_OBJECT - BaseTextEditor *m_editor; - QWidget *m_viewport; - -public: - QList m_selections; - -private: - bool m_visible; - int m_borderWidth; - int m_dropShadowWidth; - bool m_alpha; - public: TextEditorOverlay(BaseTextEditor *editor); @@ -100,16 +90,33 @@ public: void addOverlaySelection(int begin, int end, const QColor &fg, const QColor &bg, uint overlaySelectionFlags = 0); + const QList &selections() const { return m_selections; } + inline bool isEmpty() const { return m_selections.isEmpty(); } inline int dropShadowWidth() const { return m_dropShadowWidth; } bool hasCursorInSelection(const QTextCursor &cursor) const; + void mapEquivalentSelections(); + void updateEquivalentSelections(const QTextCursor &cursor); + private: QPainterPath createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect& clip); void paintSelection(QPainter *painter, const OverlaySelection &selection); void fillSelection(QPainter *painter, const OverlaySelection &selection, const QColor &color); + int selectionIndexForCursor(const QTextCursor &cursor) const; + QString selectionText(int selectionIndex) const; + QTextCursor assembleCursorForSelection(int selectionIndex) const; + + bool m_visible; + int m_borderWidth; + int m_dropShadowWidth; + bool m_alpha; + BaseTextEditor *m_editor; + QWidget *m_viewport; + QList m_selections; + QVector > m_equivalentSelections; }; } // namespace Internal