diff --git a/src/plugins/coreplugin/filemanager.cpp b/src/plugins/coreplugin/filemanager.cpp
index 4036c7396dc2c33674666c38a0a26c7568031ac9..24e2178307af9528750574fa7c9df2f19b80ae55 100644
--- a/src/plugins/coreplugin/filemanager.cpp
+++ b/src/plugins/coreplugin/filemanager.cpp
@@ -781,6 +781,11 @@ void FileManager::setFileDialogLastVisitedDirectory(const QString &directory)
     d->m_lastVisitedDirectory = directory;
 }
 
+void FileManager::notifyFilesChangedInternally(const QStringList &files)
+{
+    emit filesChangedInternally(files);
+}
+
 // -------------- FileChangeBlocker
 
 FileChangeBlocker::FileChangeBlocker(const QString &fileName)
diff --git a/src/plugins/coreplugin/filemanager.h b/src/plugins/coreplugin/filemanager.h
index 1cc606425fb1bb44a152b5c6c3ac6589db8fff64..55dd392e40963de77db9eb881b8999c22c4523fd 100644
--- a/src/plugins/coreplugin/filemanager.h
+++ b/src/plugins/coreplugin/filemanager.h
@@ -106,8 +106,16 @@ public:
     QString projectsDirectory() const;
     void setProjectsDirectory(const QString &);
 
+public slots:
+    /* Used to notify e.g. the code model to update the given files. Does *not*
+       lead to any editors to reload or any other editor manager actions. */
+    void notifyFilesChangedInternally(const QStringList &files);
+
 signals:
     void currentFileChanged(const QString &filePath);
+    /* Used to notify e.g. the code model to update the given files. Does *not*
+       lead to any editors to reload or any other editor manager actions. */
+    void filesChangedInternally(const QStringList &files);
 
 private slots:
     void fileDestroyed(QObject *obj);
diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp
index 500454758798bad9ccdf4a0e1b64b8842c371439..2238d94bf44b3bf3cd62fe889a953658e9360002 100644
--- a/src/plugins/coreplugin/vcsmanager.cpp
+++ b/src/plugins/coreplugin/vcsmanager.cpp
@@ -29,6 +29,8 @@
 
 #include "vcsmanager.h"
 #include "iversioncontrol.h"
+#include "icore.h"
+#include "filemanager.h"
 
 #include <extensionsystem/pluginmanager.h>
 
@@ -74,9 +76,10 @@ VCSManager::~VCSManager()
 void VCSManager::extensionsInitialized()
 {
     // Change signal connections
+    FileManager *fileManager = ICore::instance()->fileManager();
     foreach (IVersionControl *versionControl, allVersionControls()) {
         connect(versionControl, SIGNAL(filesChanged(QStringList)),
-                this, SIGNAL(filesChanged(QStringList)));
+                fileManager, SIGNAL(filesChangedInternally(QStringList)));
         connect(versionControl, SIGNAL(repositoryChanged(QString)),
                 this, SIGNAL(repositoryChanged(QString)));
     }
diff --git a/src/plugins/coreplugin/vcsmanager.h b/src/plugins/coreplugin/vcsmanager.h
index eb5b67a1b2703c1c4d00483648e92f4eb43d1b56..df8932c2b3884516ec83dd87aaa4f66577ee3cac 100644
--- a/src/plugins/coreplugin/vcsmanager.h
+++ b/src/plugins/coreplugin/vcsmanager.h
@@ -78,7 +78,6 @@ public:
 
 signals:
     void repositoryChanged(const QString &repository);
-    void filesChanged(const QStringList &files);
 
 private:
     VCSManagerPrivate *m_d;
diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp
index 8758a9f4b4a8e150c8768a40bd850ce337ba0767..bf01f13fad8559911aec5314ed173debc7298ed5 100644
--- a/src/plugins/cpptools/cppfindreferences.cpp
+++ b/src/plugins/cpptools/cppfindreferences.cpp
@@ -32,6 +32,7 @@
 #include "cpptoolsconstants.h"
 
 #include <texteditor/basetexteditor.h>
+#include <texteditor/basefilefind.h>
 #include <find/searchresultwindow.h>
 #include <extensionsystem/pluginmanager.h>
 #include <utils/filesearch.h>
@@ -294,63 +295,11 @@ void CppFindReferences::onReplaceButtonClicked(const QString &text,
 {
     Core::EditorManager::instance()->hideEditorInfoBar(QLatin1String("CppEditor.Rename"));
 
-    if (text.isEmpty())
-        return;
-
-    QHash<QString, QList<Find::SearchResultItem> > changes;
-
-    foreach (const Find::SearchResultItem &item, items)
-        changes[item.fileName].append(item);
-
-    Core::EditorManager *editorManager = Core::EditorManager::instance();
-
-    QHashIterator<QString, QList<Find::SearchResultItem> > it(changes);
-    while (it.hasNext()) {
-        it.next();
-
-        const QString fileName = it.key();
-        const QList<Find::SearchResultItem> items = it.value();
-
-        const QList<Core::IEditor *> editors = editorManager->editorsForFileName(fileName);
-        TextEditor::BaseTextEditor *textEditor = 0;
-        foreach (Core::IEditor *editor, editors) {
-            textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
-            if (textEditor != 0)
-                break;
-        }
-
-        if (textEditor != 0) {
-            QTextCursor tc = textEditor->textCursor();
-            tc.beginEditBlock();
-            applyChanges(textEditor->document(), text, items);
-            tc.endEditBlock();
-        } else {
-            QFile file(fileName);
-
-            if (file.open(QFile::ReadOnly)) {
-                QTextStream stream(&file);
-                // ### set the encoding
-                const QString plainText = stream.readAll();
-                file.close();
-
-                QTextDocument doc;
-                doc.setPlainText(plainText);
-
-                applyChanges(&doc, text, items);
-
-                QFile newFile(fileName);
-                if (newFile.open(QFile::WriteOnly)) {
-                    QTextStream stream(&newFile);
-                    // ### set the encoding
-                    stream << doc.toPlainText();
-                }
-            }
-        }
+    const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items);
+    if (!fileNames.isEmpty()) {
+        _modelManager->updateSourceFiles(fileNames);
+        _resultWindow->hide();
     }
-
-    const QStringList fileNames = changes.keys();
-    _modelManager->updateSourceFiles(fileNames);
-    _resultWindow->hide();
 }
 
 void CppFindReferences::displayResults(int first, int last)
diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp
index 5f5e0011a71801ca64a7825f54f5dc793254d060..7b758237c041230fd91551e626fb462a0d10ce67 100644
--- a/src/plugins/cpptools/cpptoolsplugin.cpp
+++ b/src/plugins/cpptools/cpptoolsplugin.cpp
@@ -48,6 +48,7 @@
 #include <coreplugin/editormanager/editormanager.h>
 #include <coreplugin/progressmanager/progressmanager.h>
 #include <coreplugin/vcsmanager.h>
+#include <coreplugin/filemanager.h>
 #include <cppeditor/cppeditorconstants.h>
 
 #include <QtCore/QtConcurrentRun>
@@ -99,10 +100,11 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
     // Objects
     m_modelManager = new CppModelManager(this);
     Core::VCSManager *vcsManager = core->vcsManager();
+    Core::FileManager *fileManager = core->fileManager();
     connect(vcsManager, SIGNAL(repositoryChanged(QString)),
             m_modelManager, SLOT(updateModifiedSourceFiles()));
-    connect(vcsManager, SIGNAL(filesChanged(QStringList)),
-            m_modelManager, SLOT(updateModifiedSourceFiles()));
+    connect(fileManager, SIGNAL(filesChangedInternally(QStringList)),
+            m_modelManager, SLOT(updateSourceFiles(QStringList)));
     addAutoReleasedObject(m_modelManager);
 
     m_completion = new CppCodeCompletion(m_modelManager);
diff --git a/src/plugins/find/finddialog.ui b/src/plugins/find/finddialog.ui
index 479299316f6d6b68d2ed4259593a5a814f215464..a88929fee8b32665e6b5c3bcb61a0aa0995dcb54 100644
--- a/src/plugins/find/finddialog.ui
+++ b/src/plugins/find/finddialog.ui
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>426</width>
+    <width>454</width>
     <height>168</height>
    </rect>
   </property>
@@ -117,6 +117,13 @@
        </property>
       </widget>
      </item>
+     <item row="2" column="2">
+      <widget class="QPushButton" name="replaceButton">
+       <property name="text">
+        <string>Search &amp;&amp; Replace</string>
+       </property>
+      </widget>
+     </item>
     </layout>
    </item>
    <item>
@@ -139,6 +146,7 @@
   <tabstop>searchTerm</tabstop>
   <tabstop>searchButton</tabstop>
   <tabstop>closeButton</tabstop>
+  <tabstop>replaceButton</tabstop>
   <tabstop>matchCase</tabstop>
   <tabstop>wholeWords</tabstop>
  </tabstops>
diff --git a/src/plugins/find/findtoolwindow.cpp b/src/plugins/find/findtoolwindow.cpp
index e687b21227354ee65125a95c8c4b8277bc5e71de..873473b3cd2eb113e8e2ff3a8fce7be3e68523c2 100644
--- a/src/plugins/find/findtoolwindow.cpp
+++ b/src/plugins/find/findtoolwindow.cpp
@@ -46,11 +46,11 @@ FindToolWindow::FindToolWindow(FindPlugin *plugin)
 {
     m_ui.setupUi(this);
     connect(m_ui.closeButton, SIGNAL(clicked()), this, SLOT(reject()));
-    connect(m_ui.searchButton, SIGNAL(clicked()), this, SLOT(accept()));
+    connect(m_ui.searchButton, SIGNAL(clicked()), this, SLOT(search()));
+    connect(m_ui.replaceButton, SIGNAL(clicked()), this, SLOT(replace()));
     connect(m_ui.matchCase, SIGNAL(toggled(bool)), m_plugin, SLOT(setCaseSensitive(bool)));
     connect(m_ui.wholeWords, SIGNAL(toggled(bool)), m_plugin, SLOT(setWholeWord(bool)));
     connect(m_ui.filterList, SIGNAL(activated(int)), this, SLOT(setCurrentFilter(int)));
-    connect(this, SIGNAL(accepted()), this, SLOT(search()));
     m_findCompleter->setModel(m_plugin->findCompletionModel());
     m_ui.searchTerm->setCompleter(m_findCompleter);
     QVBoxLayout *layout = new QVBoxLayout;
@@ -108,12 +108,14 @@ void FindToolWindow::setCurrentFilter(int index)
         if (!configWidget)
             continue;
         if (i == index) {
+            IFindFilter *filter = m_filters.at(i);
             m_ui.configWidget->layout()->addWidget(configWidget);
-            bool enabled = m_filters.at(i)->isEnabled();
+            bool enabled = filter->isEnabled();
             m_ui.matchCase->setEnabled(enabled);
             m_ui.wholeWords->setEnabled(enabled);
             m_ui.searchTerm->setEnabled(enabled);
             m_ui.searchButton->setEnabled(enabled);
+            m_ui.replaceButton->setEnabled(filter->isReplaceSupported() && enabled);
             configWidget->setEnabled(enabled);
         } else {
             configWidget->setParent(0);
@@ -122,17 +124,38 @@ void FindToolWindow::setCurrentFilter(int index)
     m_currentFilter = m_filters.at(index);
 }
 
-void FindToolWindow::search()
+void FindToolWindow::acceptAndGetParameters(QString *term, IFindFilter **filter)
 {
+    if (filter)
+        *filter = 0;
+    accept();
     m_plugin->updateFindCompletion(m_ui.searchTerm->text());
     int index = m_ui.filterList->currentIndex();
-    QString term = m_ui.searchTerm->text();
-    if (term.isEmpty() || index < 0)
+    QString searchTerm = m_ui.searchTerm->text();
+    if (term)
+        *term = searchTerm;
+    if (searchTerm.isEmpty() || index < 0)
         return;
-    IFindFilter *filter = m_filters.at(index);
+    if (filter)
+        *filter = m_filters.at(index);
+}
+
+void FindToolWindow::search()
+{
+    QString term;
+    IFindFilter *filter;
+    acceptAndGetParameters(&term, &filter);
     filter->findAll(term, m_plugin->findFlags());
 }
 
+void FindToolWindow::replace()
+{
+    QString term;
+    IFindFilter *filter;
+    acceptAndGetParameters(&term, &filter);
+    filter->replaceAll(term, m_plugin->findFlags());
+}
+
 void FindToolWindow::writeSettings()
 {
     QSettings *settings = Core::ICore::instance()->settings();
diff --git a/src/plugins/find/findtoolwindow.h b/src/plugins/find/findtoolwindow.h
index a187efa73004b63d4224c614faaf4daadbe3f838..57dc15b4e345ac0f6876ad27776209e6433c5a58 100644
--- a/src/plugins/find/findtoolwindow.h
+++ b/src/plugins/find/findtoolwindow.h
@@ -59,9 +59,12 @@ public:
 
 private slots:
     void search();
+    void replace();
     void setCurrentFilter(int index);
 
 private:
+    void acceptAndGetParameters(QString *term, IFindFilter **filter);
+
     Ui::FindDialog m_ui;
     FindPlugin *m_plugin;
     QList<IFindFilter *> m_filters;
diff --git a/src/plugins/find/ifindfilter.h b/src/plugins/find/ifindfilter.h
index 9878835b8988bf5fd79fc9eb36aca92714c85b64..e9a38511df3fcc138e639067943ec47e1dd28d67 100644
--- a/src/plugins/find/ifindfilter.h
+++ b/src/plugins/find/ifindfilter.h
@@ -53,7 +53,11 @@ public:
     virtual QString name() const = 0;
     virtual bool isEnabled() const = 0;
     virtual QKeySequence defaultShortcut() const = 0;
+    virtual bool isReplaceSupported() const { return false; }
+
     virtual void findAll(const QString &txt, QTextDocument::FindFlags findFlags) = 0;
+    virtual void replaceAll(const QString &txt, QTextDocument::FindFlags findFlags)
+    { Q_UNUSED(txt) Q_UNUSED(findFlags) }
 
     virtual QWidget *createConfigWidget() { return 0; }
     virtual void writeSettings(QSettings *settings) { Q_UNUSED(settings) }
diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp
index b4379631607f943ac7d371b427362f4b98cbd2e2..385cfe32581bc80f8350907bece0ba042b2b4624 100644
--- a/src/plugins/texteditor/basefilefind.cpp
+++ b/src/plugins/texteditor/basefilefind.cpp
@@ -32,6 +32,7 @@
 #include <coreplugin/icore.h>
 #include <coreplugin/progressmanager/progressmanager.h>
 #include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/filemanager.h>
 #include <find/textfindconstants.h>
 #include <find/searchresultwindow.h>
 #include <texteditor/itexteditor.h>
@@ -106,6 +107,41 @@ void BaseFileFind::findAll(const QString &txt, QTextDocument::FindFlags findFlag
     connect(progress, SIGNAL(clicked()), m_resultWindow, SLOT(popup()));
 }
 
+void BaseFileFind::replaceAll(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+    m_isSearching = true;
+    emit changed();
+    if (m_filterCombo)
+        updateComboEntries(m_filterCombo, false);
+    m_watcher.setFuture(QFuture<FileSearchResult>());
+    SearchResult *result = m_resultWindow->startNewSearch(SearchResultWindow::SearchAndReplace);
+    connect(result, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem)));
+    connect(result, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
+            this, SLOT(doReplace(QString,QList<Find::SearchResultItem>)));
+    m_resultWindow->popup(true);
+    if (m_useRegExp)
+        m_watcher.setFuture(Utils::findInFilesRegExp(txt, files(), findFlags, ITextEditor::openedTextEditorsContents()));
+    else
+        m_watcher.setFuture(Utils::findInFiles(txt, files(), findFlags, ITextEditor::openedTextEditorsContents()));
+    Core::FutureProgress *progress =
+        Core::ICore::instance()->progressManager()->addTask(m_watcher.future(),
+                                                                        "Search",
+                                                                        Constants::TASK_SEARCH);
+    progress->setWidget(createProgressWidget());
+    connect(progress, SIGNAL(clicked()), m_resultWindow, SLOT(popup()));
+}
+
+void BaseFileFind::doReplace(const QString &text,
+                               const QList<Find::SearchResultItem> &items)
+{
+    QStringList files = replaceAll(text, items);
+    Core::FileManager *fileManager = Core::ICore::instance()->fileManager();
+    if (!files.isEmpty()) {
+        fileManager->notifyFilesChangedInternally(files);
+        m_resultWindow->hide();
+    }
+}
+
 void BaseFileFind::displayResult(int index) {
     Utils::FileSearchResult result = m_watcher.future().resultAt(index);
     m_resultWindow->addResult(result.fileName,
@@ -237,3 +273,96 @@ void BaseFileFind::openEditor(const Find::SearchResultItem &item)
 {
     TextEditor::BaseTextEditor::openEditorAt(item.fileName, item.lineNumber, item.searchTermStart);
 }
+
+#pragma mark Static methods
+
+static void applyChanges(QTextDocument *doc, const QString &text, const QList<Find::SearchResultItem> &items)
+{
+    QList<QTextCursor> cursors;
+
+    foreach (const Find::SearchResultItem &item, items) {
+        const int blockNumber = item.lineNumber - 1;
+        QTextCursor tc(doc->findBlockByNumber(blockNumber));
+
+        const int cursorPosition = tc.position() + item.searchTermStart;
+
+        int cursorIndex = 0;
+        for (; cursorIndex < cursors.size(); ++cursorIndex) {
+            const QTextCursor &tc = cursors.at(cursorIndex);
+
+            if (tc.position() == cursorPosition)
+                break;
+        }
+
+        if (cursorIndex != cursors.size())
+            continue; // skip this change.
+
+        tc.setPosition(cursorPosition);
+        tc.setPosition(tc.position() + item.searchTermLength,
+                       QTextCursor::KeepAnchor);
+        cursors.append(tc);
+    }
+
+    foreach (QTextCursor tc, cursors)
+        tc.insertText(text);
+}
+
+QStringList BaseFileFind::replaceAll(const QString &text,
+                               const QList<Find::SearchResultItem> &items)
+{
+    if (text.isEmpty() || items.isEmpty())
+        return QStringList();
+
+    QHash<QString, QList<Find::SearchResultItem> > changes;
+
+    foreach (const Find::SearchResultItem &item, items)
+        changes[item.fileName].append(item);
+
+    Core::EditorManager *editorManager = Core::EditorManager::instance();
+
+    QHashIterator<QString, QList<Find::SearchResultItem> > it(changes);
+    while (it.hasNext()) {
+        it.next();
+
+        const QString fileName = it.key();
+        const QList<Find::SearchResultItem> items = it.value();
+
+        const QList<Core::IEditor *> editors = editorManager->editorsForFileName(fileName);
+        TextEditor::BaseTextEditor *textEditor = 0;
+        foreach (Core::IEditor *editor, editors) {
+            textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
+            if (textEditor != 0)
+                break;
+        }
+
+        if (textEditor != 0) {
+            QTextCursor tc = textEditor->textCursor();
+            tc.beginEditBlock();
+            applyChanges(textEditor->document(), text, items);
+            tc.endEditBlock();
+        } else {
+            QFile file(fileName);
+
+            if (file.open(QFile::ReadOnly)) {
+                QTextStream stream(&file);
+                // ### set the encoding
+                const QString plainText = stream.readAll();
+                file.close();
+
+                QTextDocument doc;
+                doc.setPlainText(plainText);
+
+                applyChanges(&doc, text, items);
+
+                QFile newFile(fileName);
+                if (newFile.open(QFile::WriteOnly)) {
+                    QTextStream stream(&newFile);
+                    // ### set the encoding
+                    stream << doc.toPlainText();
+                }
+            }
+        }
+    }
+
+    return changes.keys();
+}
diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h
index c31858d2409932b6bd9ea8fee0c1d7395cb72eef..3da9ca3c2c9911b38547b82841d5bc987bdcaba0 100644
--- a/src/plugins/texteditor/basefilefind.h
+++ b/src/plugins/texteditor/basefilefind.h
@@ -62,8 +62,13 @@ public:
     explicit BaseFileFind(Find::SearchResultWindow *resultWindow);
 
     bool isEnabled() const;
+    bool isReplaceSupported() const { return true; }
     void findAll(const QString &txt, QTextDocument::FindFlags findFlags);
+    void replaceAll(const QString &txt, QTextDocument::FindFlags findFlags);
 
+    /* returns the list of unique files that were passed in items */
+    static QStringList replaceAll(const QString &txt,
+                                  const QList<Find::SearchResultItem> &items);
 protected:
     virtual QStringList files() = 0;
     void writeCommonSettings(QSettings *settings);
@@ -79,6 +84,8 @@ private slots:
     void searchFinished();
     void openEditor(const Find::SearchResultItem &item);
     void syncRegExpSetting(bool useRegExp);
+    void doReplace(const QString &txt,
+                    const QList<Find::SearchResultItem> &items);
 
 private:
     QWidget *createProgressWidget();