summaryrefslogtreecommitdiff
path: root/src/plugins/cppeditor/cpplocalrenaming.cpp
diff options
context:
space:
mode:
authorNikolai Kosjar <nikolai.kosjar@digia.com>2014-05-20 12:24:32 -0400
committerNikolai Kosjar <nikolai.kosjar@digia.com>2014-06-13 18:04:40 +0200
commiteaecac2fd91de739d87e232807349589f5beb5ef (patch)
treecb43c2d1a4cf29e9917345f6ee929aa61f3ebd7e /src/plugins/cppeditor/cpplocalrenaming.cpp
parent98ae1bf67b2f369b52d5bb017f7a30e1d1558f13 (diff)
downloadqt-creator-eaecac2fd91de739d87e232807349589f5beb5ef.tar.gz
CppEditor: Extract CppLocalRenaming
Now CppEditorWidget is much less convoluted with the local rename mode. This class can be reused since there is no dependency on CPPEditorWidget. Change-Id: If513e59a03214cf9f2e3831f7e3616c001e1f036 Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
Diffstat (limited to 'src/plugins/cppeditor/cpplocalrenaming.cpp')
-rw-r--r--src/plugins/cppeditor/cpplocalrenaming.cpp335
1 files changed, 335 insertions, 0 deletions
diff --git a/src/plugins/cppeditor/cpplocalrenaming.cpp b/src/plugins/cppeditor/cpplocalrenaming.cpp
new file mode 100644
index 0000000000..4a5dd34644
--- /dev/null
+++ b/src/plugins/cppeditor/cpplocalrenaming.cpp
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "cpplocalrenaming.h"
+
+#include <texteditor/basetexteditor.h>
+#include <texteditor/fontsettings.h>
+
+#include <utils/qtcassert.h>
+
+/*!
+ \class CppEditor::Internal::CppLocalRenaming
+ \brief A helper class of CPPEditorWidget that implements renaming local usages.
+
+ \internal
+
+ Local use selections must be first set/updated with updateLocalUseSelections().
+ Afterwards the local renaming can be started with start(). The CPPEditorWidget
+ can then delegate work related to the local renaming mode to the handle*
+ functions.
+
+ \sa CppEditor::Internal::CPPEditorWidget
+ */
+
+namespace {
+
+void modifyCursorSelection(QTextCursor &cursor, int position, int anchor)
+{
+ cursor.setPosition(anchor);
+ cursor.setPosition(position, QTextCursor::KeepAnchor);
+}
+
+} // anonymous namespace
+
+namespace CppEditor {
+namespace Internal {
+
+CppLocalRenaming::CppLocalRenaming(TextEditor::BaseTextEditorWidget *editorWidget)
+ : m_editorWidget(editorWidget)
+ , m_modifyingSelections(false)
+ , m_renameSelectionChanged(false)
+ , m_firstRenameChangeExpected(false)
+{
+ forgetRenamingSelection();
+ connect(m_editorWidget->document(), SIGNAL(contentsChange(int,int,int)),
+ this, SLOT(onContentsChangeOfEditorWidgetDocument(int,int,int)));
+}
+
+void CppLocalRenaming::updateLocalUseSelections(const QList<QTextEdit::ExtraSelection> &selections)
+{
+ QTC_ASSERT(!isActive(), return);
+ m_selections = selections;
+}
+
+bool CppLocalRenaming::start()
+{
+ stop();
+
+ if (findRenameSelection(m_editorWidget->textCursor().position())) {
+ updateRenamingSelectionFormat(textCharFormat(TextEditor::C_OCCURRENCES_RENAME));
+ m_firstRenameChangeExpected = true;
+ updateEditorWidgetWithSelections();
+ return true;
+ }
+
+ return false;
+}
+
+bool CppLocalRenaming::handlePaste()
+{
+ if (!isActive())
+ return false;
+
+ startRenameChange();
+ m_editorWidget->BaseTextEditorWidget::paste();
+ finishRenameChange();
+ return true;
+}
+
+bool CppLocalRenaming::handleCut()
+{
+ if (!isActive())
+ return false;
+
+ startRenameChange();
+ m_editorWidget->BaseTextEditorWidget::paste();
+ finishRenameChange();
+ return true;
+}
+
+bool CppLocalRenaming::handleSelectAll()
+{
+ if (!isActive())
+ return false;
+
+ QTextCursor cursor = m_editorWidget->textCursor();
+ if (!isWithinRenameSelection(cursor.position()))
+ return false;
+
+ modifyCursorSelection(cursor, renameSelectionBegin(), renameSelectionEnd());
+ m_editorWidget->setTextCursor(cursor);
+ return true;
+}
+
+bool CppLocalRenaming::isActive() const
+{
+ return m_renameSelectionIndex != -1;
+}
+
+bool CppLocalRenaming::handleKeyPressEvent(QKeyEvent *e)
+{
+ if (!isActive())
+ return false;
+
+ QTextCursor cursor = m_editorWidget->textCursor();
+ const int cursorPosition = cursor.position();
+ const QTextCursor::MoveMode moveMode = (e->modifiers() & Qt::ShiftModifier)
+ ? QTextCursor::KeepAnchor
+ : QTextCursor::MoveAnchor;
+
+ switch (e->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_Escape:
+ stop();
+ e->accept();
+ return true;
+ case Qt::Key_Home: {
+ // Send home to start of name when within the name and not at the start
+ if (renameSelectionBegin() < cursorPosition && cursorPosition <= renameSelectionEnd()) {
+ cursor.setPosition(renameSelectionBegin(), moveMode);
+ m_editorWidget->setTextCursor(cursor);
+ e->accept();
+ return true;
+ }
+ break;
+ }
+ case Qt::Key_End: {
+ // Send end to end of name when within the name and not at the end
+ if (renameSelectionBegin() <= cursorPosition && cursorPosition < renameSelectionEnd()) {
+ cursor.setPosition(renameSelectionEnd(), moveMode);
+ m_editorWidget->setTextCursor(cursor);
+ e->accept();
+ return true;
+ }
+ break;
+ }
+ case Qt::Key_Backspace: {
+ if (cursorPosition == renameSelectionBegin() && !cursor.hasSelection()) {
+ // Eat backspace at start of name when there is no selection
+ e->accept();
+ return true;
+ }
+ break;
+ }
+ case Qt::Key_Delete: {
+ if (cursorPosition == renameSelectionEnd() && !cursor.hasSelection()) {
+ // Eat delete at end of name when there is no selection
+ e->accept();
+ return true;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ } // switch
+
+ startRenameChange();
+
+ const bool wantEditBlock = isWithinRenameSelection(cursorPosition);
+ if (wantEditBlock) {
+ if (m_firstRenameChangeExpected) // Change inside rename selection
+ cursor.beginEditBlock();
+ else
+ cursor.joinPreviousEditBlock();
+ m_firstRenameChangeExpected = false;
+ }
+ emit processKeyPressNormally(e);
+ if (wantEditBlock)
+ cursor.endEditBlock();
+ finishRenameChange();
+ return true;
+}
+
+QTextEdit::ExtraSelection &CppLocalRenaming::renameSelection()
+{
+ return m_selections[m_renameSelectionIndex];
+}
+
+void CppLocalRenaming::updateRenamingSelectionCursor(const QTextCursor &cursor)
+{
+ QTC_ASSERT(isActive(), return);
+ renameSelection().cursor = cursor;
+}
+
+void CppLocalRenaming::updateRenamingSelectionFormat(const QTextCharFormat &format)
+{
+ QTC_ASSERT(isActive(), return);
+ renameSelection().format = format;
+}
+
+void CppLocalRenaming::forgetRenamingSelection()
+{
+ m_renameSelectionIndex = -1;
+}
+
+bool CppLocalRenaming::isWithinRenameSelection(int position)
+{
+ return renameSelectionBegin() <= position && position <= renameSelectionEnd();
+}
+
+bool CppLocalRenaming::findRenameSelection(int cursorPosition)
+{
+ for (int i = 0, total = m_selections.size(); i < total; ++i) {
+ const QTextEdit::ExtraSelection &sel = m_selections.at(i);
+ if (sel.cursor.position() <= cursorPosition && cursorPosition <= sel.cursor.anchor()) {
+ m_renameSelectionIndex = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CppLocalRenaming::changeOtherSelectionsText(const QString &text)
+{
+ for (int i = 0, total = m_selections.size(); i < total; ++i) {
+ if (i == m_renameSelectionIndex)
+ continue;
+
+ QTextEdit::ExtraSelection &selection = m_selections[i];
+ const int pos = selection.cursor.selectionStart();
+ selection.cursor.removeSelectedText();
+ selection.cursor.insertText(text);
+ selection.cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ }
+}
+
+void CppLocalRenaming::onContentsChangeOfEditorWidgetDocument(int position,
+ int charsRemoved,
+ int charsAdded)
+{
+ Q_UNUSED(charsRemoved)
+
+ if (!isActive() || m_modifyingSelections)
+ return;
+
+ if (position + charsAdded == renameSelectionBegin()) // Insert at beginning, expand cursor
+ modifyCursorSelection(renameSelection().cursor, position, renameSelectionEnd());
+
+ // Keep in mind that cursor position and anchor move automatically
+ m_renameSelectionChanged = isWithinRenameSelection(position)
+ && isWithinRenameSelection(position + charsAdded);
+
+ if (!m_renameSelectionChanged)
+ stop();
+}
+
+void CppLocalRenaming::startRenameChange()
+{
+ m_renameSelectionChanged = false;
+}
+
+void CppLocalRenaming::updateEditorWidgetWithSelections()
+{
+ m_editorWidget->setExtraSelections(TextEditor::BaseTextEditorWidget::CodeSemanticsSelection,
+ m_selections);
+}
+
+QTextCharFormat CppLocalRenaming::textCharFormat(TextEditor::TextStyle category) const
+{
+ return m_editorWidget->baseTextDocument()->fontSettings().toTextCharFormat(category);
+}
+
+void CppLocalRenaming::finishRenameChange()
+{
+ if (!m_renameSelectionChanged)
+ return;
+
+ m_modifyingSelections = true;
+
+ QTextCursor cursor = m_editorWidget->textCursor();
+ cursor.joinPreviousEditBlock();
+
+ modifyCursorSelection(cursor, renameSelectionBegin(), renameSelectionEnd());
+ updateRenamingSelectionCursor(cursor);
+ changeOtherSelectionsText(cursor.selectedText());
+ updateEditorWidgetWithSelections();
+
+ cursor.endEditBlock();
+
+ m_modifyingSelections = false;
+}
+
+void CppLocalRenaming::stop()
+{
+ if (!isActive())
+ return;
+
+ updateRenamingSelectionFormat(textCharFormat(TextEditor::C_OCCURRENCES));
+ updateEditorWidgetWithSelections();
+ forgetRenamingSelection();
+
+ emit finished();
+}
+
+} // namespace Internal
+} // namespace CppEditor