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(&current, &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(&current, &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