From 0355e37e537751d4c9fd527c8a6ddf87e8d9dd43 Mon Sep 17 00:00:00 2001 From: Christian Kamm <christian.d.kamm@nokia.com> Date: Thu, 12 Aug 2010 13:46:18 +0200 Subject: [PATCH] QuickFix: Migrate to a nicer API for cross-file quick fixes. --- src/plugins/cppeditor/cppdeclfromdef.cpp | 11 +- src/plugins/cppeditor/cppquickfix.cpp | 12 +- src/plugins/cppeditor/cppquickfix.h | 7 +- src/plugins/cppeditor/cppquickfixes.cpp | 104 ++++---- .../cppeditor/cpprefactoringchanges.cpp | 12 +- src/plugins/cppeditor/cpprefactoringchanges.h | 3 +- .../qmljscomponentfromobjectdef.cpp | 13 +- src/plugins/qmljseditor/qmljsquickfix.cpp | 16 +- src/plugins/qmljseditor/qmljsquickfix.h | 8 +- src/plugins/qmljseditor/qmljsquickfixes.cpp | 11 +- .../qmljseditor/qmljsrefactoringchanges.cpp | 13 +- .../qmljseditor/qmljsrefactoringchanges.h | 3 +- src/plugins/qmljseditor/qmloutlinemodel.cpp | 6 +- src/plugins/texteditor/quickfix.cpp | 6 +- src/plugins/texteditor/quickfix.h | 9 +- src/plugins/texteditor/refactoringchanges.cpp | 231 +++++++----------- src/plugins/texteditor/refactoringchanges.h | 27 +- 17 files changed, 201 insertions(+), 291 deletions(-) diff --git a/src/plugins/cppeditor/cppdeclfromdef.cpp b/src/plugins/cppeditor/cppdeclfromdef.cpp index 73e1628d5c7..8608da134ee 100644 --- a/src/plugins/cppeditor/cppdeclfromdef.cpp +++ b/src/plugins/cppeditor/cppdeclfromdef.cpp @@ -82,16 +82,14 @@ public: "CppEditor::DeclFromDef").arg(type)); } - void perform() + void performChanges(TextEditor::RefactoringFile *, CppRefactoringChanges *refactoring) { - CppRefactoringChanges *changes = refactoringChanges(); - - Document::Ptr targetDoc = changes->document(m_targetFileName); + Document::Ptr targetDoc = refactoring->document(m_targetFileName); InsertionPointLocator locator(targetDoc); const InsertionLocation loc = locator.methodDeclarationInClass(m_targetSymbol, m_xsSpec); Q_ASSERT(loc.isValid()); - TextEditor::RefactoringFile targetFile = changes->file(m_targetFileName); + TextEditor::RefactoringFile targetFile = refactoring->file(m_targetFileName); int targetPosition1 = targetFile.position(loc.line(), loc.column()); int targetPosition2 = qMax(0, targetFile.position(loc.line(), 1) - 1); @@ -100,8 +98,7 @@ public: targetFile.change(target); targetFile.indent(Utils::ChangeSet::Range(targetPosition2, targetPosition1)); - changes->setActiveEditor(m_targetFileName, targetPosition1); - changes->apply(); + refactoring->activateEditor(m_targetFileName, targetPosition1); } private: diff --git a/src/plugins/cppeditor/cppquickfix.cpp b/src/plugins/cppeditor/cppquickfix.cpp index e3b910265a1..1441f1c1433 100644 --- a/src/plugins/cppeditor/cppquickfix.cpp +++ b/src/plugins/cppeditor/cppquickfix.cpp @@ -184,12 +184,19 @@ const Token &CppQuickFixState::tokenAt(unsigned index) const CppQuickFixOperation::CppQuickFixOperation(const CppQuickFixState &state, int priority) : QuickFixOperation(priority) , _state(state) - , _refactoringChanges(new CppRefactoringChanges(state.document(), state.snapshot())) {} CppQuickFixOperation::~CppQuickFixOperation() {} +void CppQuickFixOperation::perform() +{ + CppRefactoringChanges refactoring(_state.document(), _state.snapshot()); + TextEditor::RefactoringFile current = refactoring.file(fileName()); + + performChanges(¤t, &refactoring); +} + const CppQuickFixState &CppQuickFixOperation::state() const { return _state; @@ -198,9 +205,6 @@ const CppQuickFixState &CppQuickFixOperation::state() const QString CppQuickFixOperation::fileName() const { return state().document()->fileName(); } -CppRefactoringChanges *CppQuickFixOperation::refactoringChanges() const -{ return _refactoringChanges.data(); } - CppQuickFixFactory::CppQuickFixFactory() { } diff --git a/src/plugins/cppeditor/cppquickfix.h b/src/plugins/cppeditor/cppquickfix.h index 42399ebdc8e..6206ffdcac3 100644 --- a/src/plugins/cppeditor/cppquickfix.h +++ b/src/plugins/cppeditor/cppquickfix.h @@ -107,10 +107,12 @@ public: CppQuickFixOperation(const CppQuickFixState &state, int priority = -1); virtual ~CppQuickFixOperation(); + virtual void perform(); + protected: - QString fileName() const; + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *refactoring) = 0; - CppRefactoringChanges *refactoringChanges() const; + QString fileName() const; const CppQuickFixState &state() const; @@ -131,7 +133,6 @@ protected: // Utility functions forwarding to CppQuickFixState private: CppQuickFixState _state; - QScopedPointer<CppRefactoringChanges> _refactoringChanges; }; class CPPEDITOR_EXPORT CppQuickFixFactory: public TextEditor::QuickFixFactory diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index cc19c04ab26..a7a0e089cef 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -148,7 +148,7 @@ private: return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; if (negation) { @@ -161,8 +161,7 @@ private: changes.insert(state().endOf(binary), ")"); } changes.replace(range(binary->binary_op_token), replacement); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->apply(); + currentFile->change(changes); } }; }; @@ -244,7 +243,7 @@ private: return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; @@ -252,8 +251,7 @@ private: if (! replacement.isEmpty()) changes.replace(range(binary->binary_op_token), replacement); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->apply(); + currentFile->change(changes); } private: @@ -323,7 +321,7 @@ private: pattern = mk->BinaryExpression(left, right); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; changes.replace(range(pattern->binary_op_token), QLatin1String("||")); @@ -334,9 +332,8 @@ private: changes.insert(start, QLatin1String("!(")); changes.insert(end, QLatin1String(")")); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(pattern)); - refactoringChanges()->apply(); + currentFile->change(changes); + currentFile->indent(range(pattern)); } }; @@ -425,7 +422,7 @@ private: "Split Declaration")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; @@ -451,9 +448,8 @@ private: prevDeclarator = declarator; } - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(declaration)); - refactoringChanges()->apply(); + currentFile->change(changes); + currentFile->indent(range(declaration)); } private: @@ -509,7 +505,7 @@ private: "Add Curly Braces")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; @@ -519,9 +515,8 @@ private: const int end = endOf(_statement->lastToken() - 1); changes.insert(end, "\n}"); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(start, end)); - refactoringChanges()->apply(); + currentFile->change(changes); + currentFile->indent(range(start, end)); } private: @@ -581,7 +576,7 @@ private: pattern = mk.IfStatement(condition); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; @@ -591,9 +586,8 @@ private: changes.move(range(condition), insertPos); changes.insert(insertPos, QLatin1String(";\n")); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(pattern)); - refactoringChanges()->apply(); + currentFile->change(changes); + currentFile->indent(range(pattern)); } ASTMatcher matcher; @@ -664,7 +658,7 @@ private: pattern = mk.WhileStatement(condition); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; @@ -677,9 +671,8 @@ private: changes.copy(range(core), insertPos); changes.insert(insertPos, QLatin1String(";\n")); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(pattern)); - refactoringChanges()->apply(); + currentFile->change(changes); + currentFile->indent(range(pattern)); } ASTMatcher matcher; @@ -774,18 +767,17 @@ private: "Split if Statement")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { const Token binaryToken = state().tokenAt(condition->binary_op_token); if (binaryToken.is(T_AMPER_AMPER)) - splitAndCondition(); + splitAndCondition(currentFile); else - splitOrCondition(); - refactoringChanges()->apply(); + splitOrCondition(currentFile); } - void splitAndCondition() + void splitAndCondition(TextEditor::RefactoringFile *currentFile) { ChangeSet changes; @@ -798,11 +790,11 @@ private: changes.remove(lExprEnd, startOf(condition->right_expression)); changes.insert(endOf(pattern), QLatin1String("\n}")); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(pattern)); + currentFile->change(changes); + currentFile->indent(range(pattern)); } - void splitOrCondition() + void splitOrCondition(TextEditor::RefactoringFile *currentFile) { ChangeSet changes; @@ -826,8 +818,8 @@ private: const int lExprEnd = endOf(condition->left_expression); changes.remove(lExprEnd, startOf(condition->right_expression)); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(pattern)); + currentFile->change(changes); + currentFile->indent(range(pattern)); } private: @@ -913,7 +905,7 @@ private: "Enclose in QLatin1String(...)")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; @@ -928,8 +920,7 @@ private: changes.insert(endOf(literal), ")"); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->apply(); + currentFile->change(changes); } private: @@ -1035,7 +1026,7 @@ private: setDescription(QApplication::translate("CppTools::QuickFix", "Mark as translateable")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; @@ -1052,8 +1043,7 @@ private: changes.insert(startPos, replacement); changes.insert(endOf(m_literal), QLatin1String(")")); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->apply(); + currentFile->change(changes); } private: @@ -1117,7 +1107,7 @@ private: "Convert to Objective-C String Literal")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; @@ -1128,8 +1118,7 @@ private: changes.insert(startOf(stringLiteral), "@"); } - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->apply(); + currentFile->change(changes); } private: @@ -1266,12 +1255,11 @@ private: , replacement(replacement) {} - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; changes.replace(start, end, replacement); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->apply(); + currentFile->change(changes); } protected: @@ -1421,16 +1409,15 @@ private: } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { ChangeSet changes; int start = endOf(compoundStatement->lbrace_token); changes.insert(start, QLatin1String("\ncase ") + values.join(QLatin1String(":\nbreak;\ncase ")) + QLatin1String(":\nbreak;")); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(compoundStatement)); - refactoringChanges()->apply(); + currentFile->change(changes); + currentFile->indent(range(compoundStatement)); } CompoundStatementAST *compoundStatement; @@ -1498,7 +1485,7 @@ private: "#include header file")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { Q_ASSERT(fwdClass != 0); @@ -1555,9 +1542,8 @@ private: Utils::ChangeSet changes; changes.insert(pos, QString("#include <%1>\n").arg(QFileInfo(best).fileName())); - refactoringChanges()->changeFile(fileName(), changes); + currentFile->change(changes); } - refactoringChanges()->apply(); } private: @@ -1613,7 +1599,7 @@ private: setDescription(QApplication::translate("CppTools::QuickFix", "Add local declaration")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, CppRefactoringChanges *) { TypeOfExpression typeOfExpression; typeOfExpression.init(state().document(), state().snapshot(), state().context().bindings()); @@ -1642,10 +1628,9 @@ private: Utils::ChangeSet changes; changes.insert(startOf(binaryAST), ty); - refactoringChanges()->changeFile(fileName(), changes); + currentFile->change(changes); } } - refactoringChanges()->apply(); } private: @@ -1702,7 +1687,7 @@ private: "Convert to Camel Case ...")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *, CppRefactoringChanges *) { for (int i = 1; i < m_name.length(); ++i) { QCharRef c = m_name[i]; @@ -1715,7 +1700,6 @@ private: } } static_cast<CppEditor::Internal::CPPEditor*>(state().editor())->renameUsagesNow(m_name); - refactoringChanges()->apply(); } static bool isConvertibleUnderscore(const QString &name, int pos) diff --git a/src/plugins/cppeditor/cpprefactoringchanges.cpp b/src/plugins/cppeditor/cpprefactoringchanges.cpp index e10960f996f..3aaebc74b06 100644 --- a/src/plugins/cppeditor/cpprefactoringchanges.cpp +++ b/src/plugins/cppeditor/cpprefactoringchanges.cpp @@ -63,13 +63,6 @@ const LookupContext &CppRefactoringChanges::context() const return m_context; } -QStringList CppRefactoringChanges::apply() -{ - const QStringList changedFiles = TextEditor::RefactoringChanges::apply(); - m_modelManager->updateSourceFiles(changedFiles); - return changedFiles; -} - Document::Ptr CppRefactoringChanges::document(const QString &fileName) const { QString source; @@ -120,3 +113,8 @@ void CppRefactoringChanges::indentSelection(const QTextCursor &selection) const block = block.next(); } while (block.isValid() && block != end); } + +void CppRefactoringChanges::fileChanged(const QString &fileName) +{ + m_modelManager->updateSourceFiles(QStringList(fileName)); +} diff --git a/src/plugins/cppeditor/cpprefactoringchanges.h b/src/plugins/cppeditor/cpprefactoringchanges.h index c28908c3e41..cedb68bef20 100644 --- a/src/plugins/cppeditor/cpprefactoringchanges.h +++ b/src/plugins/cppeditor/cpprefactoringchanges.h @@ -46,8 +46,6 @@ public: CppRefactoringChanges(const CPlusPlus::Document::Ptr &thisDocument, const CPlusPlus::Snapshot &snapshot); - virtual QStringList apply(); - CPlusPlus::Document::Ptr thisDocument() const; const CPlusPlus::Snapshot &snapshot() const; CPlusPlus::Document::Ptr document(const QString &fileName) const; @@ -55,6 +53,7 @@ public: private: virtual void indentSelection(const QTextCursor &selection) const; + virtual void fileChanged(const QString &fileName); private: CPlusPlus::Document::Ptr m_thisDocument; diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp index f6ba8a2b1f3..9a831acfe40 100644 --- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp +++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp @@ -92,7 +92,7 @@ public: "Move Component into '%1.qml'").arg(m_componentName)); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, QmlJSRefactoringChanges *refactoring) { const QString newFileName = QFileInfo(fileName()).path() + QDir::separator() + m_componentName + QLatin1String(".qml"); @@ -110,14 +110,15 @@ public: const QString txt = imports + state().textOf(start, end) + QLatin1String("}\n"); + // stop if we can't create the new file + if (!refactoring->createFile(newFileName, txt)) + return; + Utils::ChangeSet changes; changes.replace(start, end, m_componentName + QLatin1String(" {\n")); - refactoringChanges()->changeFile(fileName(), changes); - refactoringChanges()->reindent(fileName(), range(start, end + 1)); + currentFile->change(changes); + currentFile->indent(range(start, end + 1)); - refactoringChanges()->createFile(newFileName, txt); - refactoringChanges()->reindent(newFileName, range(0, txt.length() - 1)); - refactoringChanges()->apply(); } }; diff --git a/src/plugins/qmljseditor/qmljsquickfix.cpp b/src/plugins/qmljseditor/qmljsquickfix.cpp index 8e536fe1951..5496acb38ae 100644 --- a/src/plugins/qmljseditor/qmljsquickfix.cpp +++ b/src/plugins/qmljseditor/qmljsquickfix.cpp @@ -75,8 +75,6 @@ unsigned QmlJSQuickFixState::startPosition(const QmlJS::AST::SourceLocation &loc QmlJSQuickFixOperation::QmlJSQuickFixOperation(const QmlJSQuickFixState &state, int priority) : QuickFixOperation(priority) , _state(state) - , _refactoringChanges(new QmlJSRefactoringChanges(ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>(), - state.snapshot())) { } @@ -84,6 +82,15 @@ QmlJSQuickFixOperation::~QmlJSQuickFixOperation() { } +void QmlJSQuickFixOperation::perform() +{ + QmlJSRefactoringChanges refactoring(ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>(), + _state.snapshot()); + TextEditor::RefactoringFile current = refactoring.file(fileName()); + + performChanges(¤t, &refactoring); +} + const QmlJSQuickFixState &QmlJSQuickFixOperation::state() const { return _state; @@ -94,11 +101,6 @@ QString QmlJSQuickFixOperation::fileName() const return state().document()->fileName(); } -QmlJSRefactoringChanges *QmlJSQuickFixOperation::refactoringChanges() const -{ - return _refactoringChanges.data(); -} - QmlJSQuickFixFactory::QmlJSQuickFixFactory() { } diff --git a/src/plugins/qmljseditor/qmljsquickfix.h b/src/plugins/qmljseditor/qmljsquickfix.h index 3b5938ed182..271bd226283 100644 --- a/src/plugins/qmljseditor/qmljsquickfix.h +++ b/src/plugins/qmljseditor/qmljsquickfix.h @@ -105,16 +105,17 @@ public: QmlJSQuickFixOperation(const QmlJSQuickFixState &state, int priority = -1); virtual ~QmlJSQuickFixOperation(); + virtual void perform(); + protected: + virtual void performChanges(TextEditor::RefactoringFile *currentFile, QmlJSRefactoringChanges *refactoring) = 0; + /// \returns A const-reference to the state of the operation. const QmlJSQuickFixState &state() const; /// \returns The name of the file for for which this operation is invoked. QString fileName() const; - /// \returns The refactoring changes associated with this quick-fix operation. - QmlJSRefactoringChanges *refactoringChanges() const; - protected: // Utility functions forwarding to QmlJSQuickFixState /// \see QmlJSQuickFixState#startPosition unsigned startPosition(const QmlJS::AST::SourceLocation &loc) const @@ -126,7 +127,6 @@ protected: // Utility functions forwarding to QmlJSQuickFixState private: QmlJSQuickFixState _state; - QScopedPointer<QmlJSRefactoringChanges> _refactoringChanges; }; class QmlJSQuickFixFactory: public TextEditor::QuickFixFactory diff --git a/src/plugins/qmljseditor/qmljsquickfixes.cpp b/src/plugins/qmljseditor/qmljsquickfixes.cpp index 9aaf194eead..a610329f5b4 100644 --- a/src/plugins/qmljseditor/qmljsquickfixes.cpp +++ b/src/plugins/qmljseditor/qmljsquickfixes.cpp @@ -88,7 +88,7 @@ private: "Split initializer")); } - virtual void perform() + virtual void performChanges(TextEditor::RefactoringFile *currentFile, QmlJSRefactoringChanges *) { Q_ASSERT(_objectInitializer != 0); @@ -107,12 +107,9 @@ private: changes.insert(startPosition(_objectInitializer->rbraceToken), QLatin1String("\n")); - RefactoringFile file = refactoringChanges()->file(fileName()); - file.change(changes); - file.indent(range(startPosition(_objectInitializer->lbraceToken), - startPosition(_objectInitializer->rbraceToken))); - - refactoringChanges()->apply(); + currentFile->change(changes); + currentFile->indent(range(startPosition(_objectInitializer->lbraceToken), + startPosition(_objectInitializer->rbraceToken))); } }; }; diff --git a/src/plugins/qmljseditor/qmljsrefactoringchanges.cpp b/src/plugins/qmljseditor/qmljsrefactoringchanges.cpp index 6a49ab6a0e5..d3f420fc693 100644 --- a/src/plugins/qmljseditor/qmljsrefactoringchanges.cpp +++ b/src/plugins/qmljseditor/qmljsrefactoringchanges.cpp @@ -34,7 +34,6 @@ #include <texteditor/texteditorsettings.h> #include <texteditor/tabsettings.h> - using namespace QmlJS; using namespace QmlJSEditor; @@ -46,13 +45,6 @@ QmlJSRefactoringChanges::QmlJSRefactoringChanges(ModelManagerInterface *modelMan Q_ASSERT(modelManager); } -QStringList QmlJSRefactoringChanges::apply() -{ - const QStringList changedFiles = TextEditor::RefactoringChanges::apply(); - m_modelManager->updateSourceFiles(changedFiles, true); - return changedFiles; -} - void QmlJSRefactoringChanges::indentSelection(const QTextCursor &selection) const { // ### shares code with QmlJSTextEditor::indent @@ -71,3 +63,8 @@ void QmlJSRefactoringChanges::indentSelection(const QTextCursor &selection) cons block = block.next(); } while (block.isValid() && block != end); } + +void QmlJSRefactoringChanges::fileChanged(const QString &fileName) +{ + m_modelManager->updateSourceFiles(QStringList(fileName), true); +} diff --git a/src/plugins/qmljseditor/qmljsrefactoringchanges.h b/src/plugins/qmljseditor/qmljsrefactoringchanges.h index 76228dd616a..b68756d718e 100644 --- a/src/plugins/qmljseditor/qmljsrefactoringchanges.h +++ b/src/plugins/qmljseditor/qmljsrefactoringchanges.h @@ -46,10 +46,9 @@ public: QmlJSRefactoringChanges(QmlJS::ModelManagerInterface *modelManager, const QmlJS::Snapshot &snapshot); - virtual QStringList apply(); - private: virtual void indentSelection(const QTextCursor &selection) const; + virtual void fileChanged(const QString &fileName); private: QmlJS::ModelManagerInterface *m_modelManager; diff --git a/src/plugins/qmljseditor/qmloutlinemodel.cpp b/src/plugins/qmljseditor/qmloutlinemodel.cpp index 441fd99c7e5..ef1bf06e84e 100644 --- a/src/plugins/qmljseditor/qmloutlinemodel.cpp +++ b/src/plugins/qmljseditor/qmloutlinemodel.cpp @@ -634,11 +634,11 @@ void QmlOutlineModel::reparentNodes(QmlOutlineItem *targetItem, int row, QList<Q } QmlJSRefactoringChanges refactoring(QmlJS::ModelManagerInterface::instance(), m_semanticInfo.snapshot); - refactoring.changeFile(m_semanticInfo.document->fileName(), changeSet); + TextEditor::RefactoringFile file = refactoring.file(m_semanticInfo.document->fileName()); + file.change(changeSet); foreach (const Utils::ChangeSet::Range &range, changedRanges) { - refactoring.reindent(m_semanticInfo.document->fileName(), range); + file.indent(range); } - refactoring.apply(); } void QmlOutlineModel::moveObjectMember(AST::UiObjectMember *toMove, diff --git a/src/plugins/texteditor/quickfix.cpp b/src/plugins/texteditor/quickfix.cpp index 31baf34519b..6a269dbedae 100644 --- a/src/plugins/texteditor/quickfix.cpp +++ b/src/plugins/texteditor/quickfix.cpp @@ -89,9 +89,9 @@ QString QuickFixState::textOf(int start, int end) const return tc.selectedText(); } -TextEditor::RefactoringChanges::Range QuickFixState::range(int start, int end) +Utils::ChangeSet::Range QuickFixState::range(int start, int end) { - return TextEditor::RefactoringChanges::Range(start, end); + return Utils::ChangeSet::Range(start, end); } QuickFixOperation::QuickFixOperation(int priority) @@ -123,6 +123,8 @@ void QuickFixOperation::setDescription(const QString &description) _description = description; } + + QuickFixFactory::QuickFixFactory(QObject *parent) : QObject(parent) { diff --git a/src/plugins/texteditor/quickfix.h b/src/plugins/texteditor/quickfix.h index b3bdd540f4a..f632ac32c8b 100644 --- a/src/plugins/texteditor/quickfix.h +++ b/src/plugins/texteditor/quickfix.h @@ -33,7 +33,6 @@ #include "texteditor_global.h" #include "icompletioncollector.h" -#include <texteditor/refactoringchanges.h> #include <utils/changeset.h> #include <QtCore/QSharedPointer> @@ -88,7 +87,7 @@ public: QString textOf(int start, int end) const; /// Utility method to create a range. - static TextEditor::RefactoringChanges::Range range(int start, int end); + static Utils::ChangeSet::Range range(int start, int end); private: TextEditor::BaseTextEditor *_editor; @@ -136,14 +135,10 @@ public: /*! Perform this quick-fix's operation. - Subclasses should implement this method to do the actual changes by using the - RefactoringChanges. + Subclasses should implement this method to do the actual changes. */ virtual void perform() = 0; -protected: - virtual TextEditor::RefactoringChanges *refactoringChanges() const = 0; - private: TextEditor::BaseTextEditor *_editor; int _priority; diff --git a/src/plugins/texteditor/refactoringchanges.cpp b/src/plugins/texteditor/refactoringchanges.cpp index d44acc23614..9f0575b8afe 100644 --- a/src/plugins/texteditor/refactoringchanges.cpp +++ b/src/plugins/texteditor/refactoringchanges.cpp @@ -45,99 +45,6 @@ RefactoringChanges::RefactoringChanges() RefactoringChanges::~RefactoringChanges() {} -QStringList RefactoringChanges::apply() -{ - QSet<QString> changed; - - { // open editors - QHashIterator<QString, int> it(m_cursorByFile); - while (it.hasNext()) { - it.next(); - const QString &fileName = it.key(); - int pos = it.value(); - - BaseTextEditor *editor = editorForFile(fileName, true); - if (pos != -1) { - QTextCursor cursor = editor->textCursor(); - cursor.setPosition(pos); - editor->setTextCursor(cursor); - } - - if (m_fileNameToShow == fileName) { - Core::EditorManager *editorManager = Core::EditorManager::instance(); - editorManager->activateEditor(editor->editableInterface()); - } - } - } - - { // change and indent files - QHashIterator<QString, Utils::ChangeSet> it(m_changesByFile); - while (it.hasNext()) { - it.next(); - const QString &fileName = it.key(); - Utils::ChangeSet changes = it.value(); - - QTextDocument *document; - QScopedPointer<QFile> file; - QTextCursor cursor; - { - if (BaseTextEditor *editor = editorForFile(fileName, false)) { - document = editor->document(); - cursor = editor->textCursor(); - } else { - file.reset(new QFile(fileName)); - if (!file->open(QIODevice::ReadWrite)) { - qWarning() << "RefactoringChanges could not open" << fileName << "for read/write, skipping"; - continue; - } - document = new QTextDocument(file->readAll()); - cursor = QTextCursor(document); - } - } - - { - cursor.beginEditBlock(); - - // build indent selections now, applying the changeset will change locations - const QList<QTextCursor> &indentSelections = rangesToSelections( - document, m_indentRangesByFile.values(fileName)); - - // apply changes and reindent - changes.apply(&cursor); - - // newly created files must be indented specially - there's no way to select everything in an empty file - if (m_filesToCreate.contains(fileName) && m_indentRangesByFile.contains(fileName)) { - QTextCursor completeSelection(cursor); - completeSelection.select(QTextCursor::Document); - indentSelection(completeSelection); - } else { - foreach (const QTextCursor &selection, indentSelections) - indentSelection(selection); - } - - cursor.endEditBlock(); - } - - // if this document came from a file, write the result to it - if (file) { - const QByteArray &newContents = document->toPlainText().toUtf8(); - file->resize(newContents.size()); - file->seek(0); - file->write(newContents); - delete document; - } - - changed.insert(fileName); - } - } - - { // Delete files - // ### - } - - return changed.toList(); -} - BaseTextEditor *RefactoringChanges::editorForFile(const QString &fileName, bool openIfClosed) { @@ -185,19 +92,37 @@ bool RefactoringChanges::createFile(const QString &fileName, const QString &cont { if (QFile::exists(fileName)) return false; - if (m_changesByFile.contains(fileName)) - return false; - m_filesToCreate.insert(fileName); + BaseTextEditor *editor = editorForFile(fileName, openEditor); + + QTextDocument *document; + if (editor) + document = editor->document(); + else + document = new QTextDocument; - Utils::ChangeSet changes; - changes.insert(0, contents); - m_changesByFile.insert(fileName, changes); + { + QTextCursor cursor(document); + cursor.beginEditBlock(); - if (reindent) - m_indentRangesByFile.insert(fileName, Range(0, 0)); - if (openEditor) - m_cursorByFile.insert(fileName, -1); + cursor.insertText(contents); + + if (reindent) { + cursor.select(QTextCursor::Document); + indentSelection(cursor); + } + + cursor.endEditBlock(); + } + + if (!editor) { + QFile file(fileName); + file.open(QFile::WriteOnly); + file.write(document->toPlainText().toUtf8()); + delete document; + } + + fileChanged(fileName); return true; } @@ -219,34 +144,25 @@ RefactoringFile RefactoringChanges::file(const QString &fileName) return RefactoringFile(); } -void RefactoringChanges::openEditor(const QString &fileName, int pos) -{ - m_cursorByFile.insert(fileName, pos); -} - -void RefactoringChanges::setActiveEditor(const QString &fileName, int pos) +BaseTextEditor *RefactoringChanges::openEditor(const QString &fileName, int pos) { - m_cursorByFile.insert(fileName, pos); - m_fileNameToShow = fileName; + BaseTextEditor *editor = editorForFile(fileName, true); + if (pos != -1) { + QTextCursor cursor = editor->textCursor(); + cursor.setPosition(pos); + editor->setTextCursor(cursor); + } + return editor; } -void RefactoringChanges::changeFile(const QString &fileName, const Utils::ChangeSet &changes, bool openEditor) +BaseTextEditor *RefactoringChanges::activateEditor(const QString &fileName, int pos) { - m_changesByFile.insert(fileName, changes); - - if (openEditor) - m_cursorByFile.insert(fileName, -1); -} + BaseTextEditor *editor = openEditor(fileName, pos); -void RefactoringChanges::reindent(const QString &fileName, const Range &range, bool openEditor) -{ - m_indentRangesByFile.insert(fileName, range); + Core::EditorManager *editorManager = Core::EditorManager::instance(); + editorManager->activateEditor(editor->editableInterface()); - // simplify apply by never having files indented that are not also changed - if (!m_changesByFile.contains(fileName)) - m_changesByFile.insert(fileName, Utils::ChangeSet()); - if (openEditor) - m_cursorByFile.insert(fileName, -1); + return editor; } @@ -254,6 +170,7 @@ RefactoringFile::RefactoringFile() : m_refactoringChanges(0) , m_document(0) , m_editor(0) + , m_openEditor(false) { } RefactoringFile::RefactoringFile(const QString &fileName, RefactoringChanges *refactoringChanges) @@ -261,6 +178,7 @@ RefactoringFile::RefactoringFile(const QString &fileName, RefactoringChanges *re , m_refactoringChanges(refactoringChanges) , m_document(0) , m_editor(0) + , m_openEditor(false) { m_editor = RefactoringChanges::editorForFile(fileName, false); } @@ -271,12 +189,48 @@ RefactoringFile::RefactoringFile(const RefactoringFile &other) , m_document(0) , m_editor(other.m_editor) { - if (other.m_document) - m_document = new QTextDocument(other.m_document); + Q_ASSERT_X(!other.m_document && other.m_changes.isEmpty() && other.m_indentRanges.isEmpty(), + "RefactoringFile", "A refactoring file with changes is not copyable"); } RefactoringFile::~RefactoringFile() { + if (m_openEditor) + m_editor = m_refactoringChanges->openEditor(m_fileName, -1); + + // apply changes, if any + if (!m_indentRanges.isEmpty() || !m_changes.isEmpty()) { + QTextDocument *doc = mutableDocument(); + { + QTextCursor c = cursor(); + c.beginEditBlock(); + + // build indent selections now, applying the changeset will change locations + const QList<QTextCursor> &indentSelections = + RefactoringChanges::rangesToSelections( + doc, m_indentRanges); + + // apply changes and reindent + m_changes.apply(&c); + foreach (const QTextCursor &selection, indentSelections) { + m_refactoringChanges->indentSelection(selection); + } + + c.endEditBlock(); + } + + // if this document doesn't have an editor, write the result to a file + if (!m_editor) { + const QByteArray &newContents = doc->toPlainText().toUtf8(); + QFile file(m_fileName); + file.open(QFile::WriteOnly); + //file->resize(newContents.size()); // ### necessary? + file.write(newContents); + } + + m_refactoringChanges->fileChanged(m_fileName); + } + delete m_document; } @@ -287,15 +241,14 @@ bool RefactoringFile::isValid() const const QTextDocument *RefactoringFile::document() const { - if (m_editor) - return m_editor->document(); - return mutableDocument(); } QTextDocument *RefactoringFile::mutableDocument() const { - if (!m_document && !m_fileName.isEmpty()) { + if (m_editor) + return m_editor->document(); + else if (!m_document && !m_fileName.isEmpty()) { QString fileContents; { QFile file(m_fileName); @@ -350,13 +303,11 @@ bool RefactoringFile::change(const Utils::ChangeSet &changeSet, bool openEditor) { if (m_fileName.isEmpty()) return false; - if (!m_refactoringChanges->m_changesByFile.value(m_fileName).isEmpty()) + if (!m_changes.isEmpty()) return false; - m_refactoringChanges->m_changesByFile.insert(m_fileName, changeSet); - - if (openEditor) - m_refactoringChanges->m_cursorByFile.insert(m_fileName, -1); + m_changes = changeSet; + m_openEditor = openEditor; return true; } @@ -366,14 +317,10 @@ bool RefactoringFile::indent(const Range &range, bool openEditor) if (m_fileName.isEmpty()) return false; - m_refactoringChanges->m_indentRangesByFile.insert(m_fileName, range); - - // simplify apply by never having files indented that are not also changed - if (!m_refactoringChanges->m_changesByFile.contains(m_fileName)) - m_refactoringChanges->m_changesByFile.insert(m_fileName, Utils::ChangeSet()); + m_indentRanges.append(range); if (openEditor) - m_refactoringChanges->m_cursorByFile.insert(m_fileName, -1); + m_openEditor = true; return true; } diff --git a/src/plugins/texteditor/refactoringchanges.h b/src/plugins/texteditor/refactoringchanges.h index 13b8bbd9adb..267ed2e6e20 100644 --- a/src/plugins/texteditor/refactoringchanges.h +++ b/src/plugins/texteditor/refactoringchanges.h @@ -50,7 +50,6 @@ public: public: RefactoringFile(); RefactoringFile(const QString &fileName, RefactoringChanges *refactoringChanges); - RefactoringFile(const RefactoringFile &other); ~RefactoringFile(); @@ -71,7 +70,7 @@ public: private: // not assignable - const RefactoringFile &operator=(const RefactoringFile &other); + //const RefactoringFile &operator=(const RefactoringFile &other); QTextDocument *mutableDocument() const; @@ -80,6 +79,9 @@ private: RefactoringChanges *m_refactoringChanges; mutable QTextDocument *m_document; BaseTextEditor *m_editor; + Utils::ChangeSet m_changes; + QList<Range> m_indentRanges; + bool m_openEditor; }; /*! @@ -95,28 +97,19 @@ public: RefactoringChanges(); virtual ~RefactoringChanges(); - /*! - Applies all changes to open editors or to text files. - - \return The list of changed files, including newly-created ones. - */ - virtual QStringList apply(); - bool createFile(const QString &fileName, const QString &contents, bool reindent = true, bool openEditor = true); bool removeFile(const QString &fileName); RefactoringFile file(const QString &fileName); - void openEditor(const QString &fileName, int pos = -1); + BaseTextEditor *openEditor(const QString &fileName, int pos = -1); /** * \param fileName the file to activate the editor for * \param pos, 0-based offset to put the cursor on, -1 means don't move */ - void setActiveEditor(const QString &fileName, int pos = -1); + BaseTextEditor *activateEditor(const QString &fileName, int pos = -1); - QT_DEPRECATED void changeFile(const QString &fileName, const Utils::ChangeSet &changes, bool openEditor = true); - QT_DEPRECATED void reindent(const QString &fileName, const Range &range, bool openEditor = true); private: static BaseTextEditor *editorForFile(const QString &fileName, @@ -124,13 +117,7 @@ private: static QList<QTextCursor> rangesToSelections(QTextDocument *document, const QList<Range> &ranges); virtual void indentSelection(const QTextCursor &selection) const = 0; - -private: - QSet<QString> m_filesToCreate; - QHash<QString, int> m_cursorByFile; - QHash<QString, Utils::ChangeSet> m_changesByFile; - QMultiHash<QString, Range> m_indentRangesByFile; - QString m_fileNameToShow; + virtual void fileChanged(const QString &fileName) = 0; friend class RefactoringFile; }; -- GitLab