From 7aa24116935249a840e1350a6f8de73bc794fb09 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Mon, 9 Nov 2009 15:57:56 +0100
Subject: [PATCH] Code model: Update on changes from the versioning system.

Add state logic to CppCodeModelManagerInterface, making it aware whether
an indexer is running, protect the update methods from another
invocation while running. Add changed signals to IVersionControl and
VCSManager and wire them to the update methods. Add a menu action for
manually updating.

Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
Reviewed-by: con <qtc-committer@nokia.com>
---
 src/plugins/coreplugin/iversioncontrol.h      |  4 ++
 src/plugins/coreplugin/mainwindow.cpp         |  3 +-
 src/plugins/coreplugin/vcsmanager.cpp         | 14 +++-
 src/plugins/coreplugin/vcsmanager.h           | 12 +++-
 src/plugins/cppeditor/cppeditorconstants.h    |  2 +
 src/plugins/cppeditor/cppplugin.cpp           | 67 ++++++++++++-------
 src/plugins/cppeditor/cppplugin.h             |  5 +-
 src/plugins/cpptools/cppmodelmanager.cpp      | 41 +++++++++++-
 src/plugins/cpptools/cppmodelmanager.h        |  7 ++
 .../cpptools/cppmodelmanagerinterface.h       |  6 ++
 src/plugins/cpptools/cpptoolsplugin.cpp       |  6 ++
 src/plugins/cvs/cvscontrol.cpp                | 11 +++
 src/plugins/cvs/cvscontrol.h                  |  3 +
 src/plugins/cvs/cvsplugin.cpp                 |  9 ++-
 src/plugins/cvs/cvsplugin.h                   |  3 +-
 src/plugins/git/gitclient.cpp                 | 48 ++++++++++---
 src/plugins/git/gitclient.h                   | 16 +++--
 src/plugins/git/gitcommand.cpp                |  2 +
 src/plugins/git/gitcommand.h                  |  1 +
 src/plugins/git/gitplugin.cpp                 | 14 ++--
 src/plugins/git/gitplugin.h                   |  3 +
 src/plugins/git/gitversioncontrol.cpp         |  5 ++
 src/plugins/git/gitversioncontrol.h           |  2 +
 src/plugins/perforce/perforceplugin.cpp       |  7 +-
 .../perforce/perforceversioncontrol.cpp       | 10 +++
 src/plugins/perforce/perforceversioncontrol.h |  3 +
 src/plugins/subversion/subversioncontrol.cpp  | 10 +++
 src/plugins/subversion/subversioncontrol.h    |  3 +
 src/plugins/subversion/subversionplugin.cpp   |  6 +-
 src/plugins/subversion/subversionplugin.h     |  3 +-
 30 files changed, 265 insertions(+), 61 deletions(-)

diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h
index 8cbd8240b36..edaab39fbdb 100644
--- a/src/plugins/coreplugin/iversioncontrol.h
+++ b/src/plugins/coreplugin/iversioncontrol.h
@@ -106,6 +106,10 @@ public:
      */
     virtual bool vcsDelete(const QString &filename) = 0;
 
+signals:
+    void repositoryChanged(const QString &repository);
+    void filesChanged(const QStringList &files);
+
     // TODO: ADD A WAY TO DETECT WHETHER A FILE IS MANAGED, e.g
     // virtual bool sccManaged(const QString &filename) = 0;
 };
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index 282b2bf6815..e7b8e7fa544 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -126,7 +126,7 @@ MainWindow::MainWindow() :
     m_progressManager(new ProgressManagerPrivate()),
     m_scriptManager(new ScriptManagerPrivate(this)),
     m_variableManager(new VariableManager(this)),
-    m_vcsManager(new VCSManager()),
+    m_vcsManager(new VCSManager),
     m_viewManager(0),
     m_modeManager(0),
     m_mimeDatabase(new MimeDatabase),
@@ -346,6 +346,7 @@ void MainWindow::extensionsInitialized()
     OutputPaneManager::instance()->init();
 
     m_actionManager->initialize();
+    m_vcsManager->extensionsInitialized();
     readSettings();
     updateContext();
 
diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp
index 33c7e484a02..e07ba2ff12e 100644
--- a/src/plugins/coreplugin/vcsmanager.cpp
+++ b/src/plugins/coreplugin/vcsmanager.cpp
@@ -57,7 +57,8 @@ struct VCSManagerPrivate {
     QMap<QString, IVersionControl *> m_cachedMatches;
 };
 
-VCSManager::VCSManager() :
+VCSManager::VCSManager(QObject *parent) :
+   QObject(parent),
    m_d(new VCSManagerPrivate)
 {
 }
@@ -67,6 +68,17 @@ VCSManager::~VCSManager()
     delete m_d;
 }
 
+void VCSManager::extensionsInitialized()
+{
+    // Change signal connections
+    foreach (IVersionControl *versionControl, allVersionControls()) {
+        connect(versionControl, SIGNAL(filesChanged(QStringList)),
+                this, SIGNAL(filesChanged(QStringList)));
+        connect(versionControl, SIGNAL(repositoryChanged(QString)),
+                this, SIGNAL(repositoryChanged(QString)));
+    }
+}
+
 void VCSManager::setVCSEnabled(const QString &directory)
 {
     if (debug)
diff --git a/src/plugins/coreplugin/vcsmanager.h b/src/plugins/coreplugin/vcsmanager.h
index fa94efc618c..772243dd957 100644
--- a/src/plugins/coreplugin/vcsmanager.h
+++ b/src/plugins/coreplugin/vcsmanager.h
@@ -33,6 +33,7 @@
 #include "core_global.h"
 
 #include <QtCore/QString>
+#include <QtCore/QObject>
 
 namespace Core {
 
@@ -49,13 +50,16 @@ class IVersionControl;
 // for the topmost directory it manages. This information is cached and
 // VCSManager thus knows pretty fast which IVersionControl * is responsible.
 
-class CORE_EXPORT VCSManager
+class CORE_EXPORT VCSManager : public QObject
 {
+    Q_OBJECT
     Q_DISABLE_COPY(VCSManager)
 public:
-    VCSManager();
+    explicit VCSManager(QObject *parent = 0);
     virtual ~VCSManager();
 
+    void extensionsInitialized();
+
     IVersionControl *findVersionControlForDirectory(const QString &directory);
 
     // Enable the VCS managing a certain directory only. This should
@@ -69,6 +73,10 @@ public:
     // if a failure occurs
     bool showDeleteDialog(const QString &fileName);
 
+signals:
+    void repositoryChanged(const QString &repository);
+    void filesChanged(const QStringList &files);
+
 private:
     VCSManagerPrivate *m_d;
 };
diff --git a/src/plugins/cppeditor/cppeditorconstants.h b/src/plugins/cppeditor/cppeditorconstants.h
index 356f711ba9e..85d02021251 100644
--- a/src/plugins/cppeditor/cppeditorconstants.h
+++ b/src/plugins/cppeditor/cppeditorconstants.h
@@ -41,8 +41,10 @@ const char * const SWITCH_DECLARATION_DEFINITION = "CppEditor.SwitchDeclarationD
 const char * const RENAME_SYMBOL_UNDER_CURSOR = "CppEditor.RenameSymbolUnderCursor";
 const char * const FIND_USAGES = "CppEditor.FindUsages";
 const char * const SEPARATOR = "CppEditor.Separator";
+const char * const SEPARATOR2 = "CppEditor.Separator2";
 const char * const FIND_REFERENCES = "CppEditor.FindReferences";
 const char * const JUMP_TO_DEFINITION = "CppEditor.JumpToDefinition";
+const char * const UPDATE_CODEMODEL = "CppEditor.UpdateCodeModel";
 
 const char * const HEADER_FILE_TYPE = "CppHeaderFiles";
 const char * const SOURCE_FILE_TYPE = "CppSourceFiles";
diff --git a/src/plugins/cppeditor/cppplugin.cpp b/src/plugins/cppeditor/cppplugin.cpp
index f98fb680873..16d7ce4b914 100644
--- a/src/plugins/cppeditor/cppplugin.cpp
+++ b/src/plugins/cppeditor/cppplugin.cpp
@@ -43,7 +43,7 @@
 #include <coreplugin/actionmanager/actionmanager.h>
 #include <coreplugin/actionmanager/command.h>
 #include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/progressmanager/progressmanager.h>
+#include <cpptools/cppmodelmanagerinterface.h>
 #include <texteditor/completionsupport.h>
 #include <texteditor/fontsettings.h>
 #include <texteditor/storagesettings.h>
@@ -112,7 +112,11 @@ CppPlugin *CppPlugin::m_instance = 0;
 
 CppPlugin::CppPlugin() :
     m_actionHandler(0),
-    m_sortedMethodOverview(false)
+    m_sortedMethodOverview(false),
+    m_renameSymbolUnderCursorAction(0),
+    m_findUsagesAction(0),
+    m_updateCodeModelAction(0)
+
 {
     m_instance = this;
 }
@@ -158,6 +162,17 @@ bool CppPlugin::sortedMethodOverview() const
     return m_sortedMethodOverview;
 }
 
+static inline
+        Core::Command *createSeparator(Core::ActionManager *am,
+                                       QObject *parent,
+                                       const QList<int> &context,
+                                       const char *id)
+{
+    QAction *separator = new QAction(parent);
+    separator->setSeparator(true);
+    return am->registerAction(separator, QLatin1String(id), context);
+}
+
 bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
 {
     Core::ICore *core = Core::ICore::instance();
@@ -192,6 +207,7 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
     Core::ActionContainer *contextMenu= am->createMenu(CppEditor::Constants::M_CONTEXT);
 
     Core::Command *cmd;
+    Core::ActionContainer *cppToolsMenu = am->actionContainer(QLatin1String(CppTools::Constants::M_TOOLS_CPP));
 
     QAction *jumpToDefinition = new QAction(tr("Follow Symbol under Cursor"), this);
     cmd = am->registerAction(jumpToDefinition,
@@ -200,7 +216,7 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
     connect(jumpToDefinition, SIGNAL(triggered()),
             this, SLOT(jumpToDefinition()));
     contextMenu->addAction(cmd);
-    am->actionContainer(CppTools::Constants::M_TOOLS_CPP)->addAction(cmd);
+    cppToolsMenu->addAction(cmd);
 
     QAction *switchDeclarationDefinition = new QAction(tr("Switch between Method Declaration/Definition"), this);
     cmd = am->registerAction(switchDeclarationDefinition,
@@ -209,14 +225,14 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
     connect(switchDeclarationDefinition, SIGNAL(triggered()),
             this, SLOT(switchDeclarationDefinition()));
     contextMenu->addAction(cmd);
-    am->actionContainer(CppTools::Constants::M_TOOLS_CPP)->addAction(cmd);
+    cppToolsMenu->addAction(cmd);
 
     m_findUsagesAction = new QAction(tr("Find Usages"), this);
     cmd = am->registerAction(m_findUsagesAction, Constants::FIND_USAGES, context);
     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+U")));
     connect(m_findUsagesAction, SIGNAL(triggered()), this, SLOT(findUsages()));
     contextMenu->addAction(cmd);
-    am->actionContainer(CppTools::Constants::M_TOOLS_CPP)->addAction(cmd);
+    cppToolsMenu->addAction(cmd);
 
     m_renameSymbolUnderCursorAction = new QAction(tr("Rename Symbol under Cursor"), this);
     cmd = am->registerAction(m_renameSymbolUnderCursorAction,
@@ -224,7 +240,17 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
     cmd->setDefaultKeySequence(QKeySequence("CTRL+SHIFT+R"));
     connect(m_renameSymbolUnderCursorAction, SIGNAL(triggered()), this, SLOT(renameSymbolUnderCursor()));
     contextMenu->addAction(cmd);
-    am->actionContainer(CppTools::Constants::M_TOOLS_CPP)->addAction(cmd);
+    cppToolsMenu->addAction(cmd);
+
+    // Update context in global context
+    QList<int> globalContext;
+    globalContext.append(Core::Constants::C_GLOBAL_ID);
+    cppToolsMenu->addAction(createSeparator(am, this, globalContext, CppEditor::Constants::SEPARATOR2));
+    m_updateCodeModelAction = new QAction(tr("Update code model"), this);
+    cmd = am->registerAction(m_updateCodeModelAction, QLatin1String(Constants::UPDATE_CODEMODEL), globalContext);
+    CppTools::CppModelManagerInterface *cppModelManager = CppTools::CppModelManagerInterface::instance();
+    connect(m_updateCodeModelAction, SIGNAL(triggered()), cppModelManager, SLOT(updateModifiedSourceFiles()));
+    cppToolsMenu->addAction(cmd);
 
     m_actionHandler = new TextEditor::TextEditorActionHandler(CppEditor::Constants::C_CPPEDITOR,
         TextEditor::TextEditorActionHandler::Format
@@ -233,10 +259,7 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
 
     m_actionHandler->initializeActions();
     
-    QAction *separator = new QAction(this);
-    separator->setSeparator(true);
-    cmd = am->registerAction(separator, CppEditor::Constants::SEPARATOR, context);
-    contextMenu->addAction(cmd);
+    contextMenu->addAction(createSeparator(am, this, context, CppEditor::Constants::SEPARATOR));
 
     cmd = am->command(TextEditor::Constants::AUTO_INDENT_SELECTION);
     contextMenu->addAction(cmd);
@@ -244,10 +267,8 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
     cmd = am->command(TextEditor::Constants::UN_COMMENT_SELECTION);
     contextMenu->addAction(cmd);
 
-    connect(core->progressManager(), SIGNAL(taskStarted(QString)),
-            this, SLOT(onTaskStarted(QString)));
-    connect(core->progressManager(), SIGNAL(allTasksFinished(QString)),
-            this, SLOT(onAllTasksFinished(QString)));
+    connect(cppModelManager, SIGNAL(indexingStarted()), this, SLOT(onCppModelIndexingStarted()));
+    connect(cppModelManager, SIGNAL(indexingFinished()), this, SLOT(onCppModelIndexingFinished()));
     readSettings();
     return true;
 }
@@ -303,20 +324,18 @@ void CppPlugin::findUsages()
         editor->findUsages();
 }
 
-void CppPlugin::onTaskStarted(const QString &type)
+void CppPlugin::onCppModelIndexingStarted()
 {
-    if (type == CppTools::Constants::TASK_INDEX) {
-        m_renameSymbolUnderCursorAction->setEnabled(false);
-        m_findUsagesAction->setEnabled(false);
-    }
+    m_renameSymbolUnderCursorAction->setEnabled(false);
+    m_findUsagesAction->setEnabled(false);
+    m_updateCodeModelAction->setEnabled(false);
 }
 
-void CppPlugin::onAllTasksFinished(const QString &type)
+void CppPlugin::onCppModelIndexingFinished()
 {
-    if (type == CppTools::Constants::TASK_INDEX) {
-        m_renameSymbolUnderCursorAction->setEnabled(true);
-        m_findUsagesAction->setEnabled(true);
-    }
+    m_renameSymbolUnderCursorAction->setEnabled(true);
+    m_findUsagesAction->setEnabled(true);
+    m_updateCodeModelAction->setEnabled(true);
 }
 
 Q_EXPORT_PLUGIN(CppPlugin)
diff --git a/src/plugins/cppeditor/cppplugin.h b/src/plugins/cppeditor/cppplugin.h
index 3456bd9baf2..e0ccc7ac64e 100644
--- a/src/plugins/cppeditor/cppplugin.h
+++ b/src/plugins/cppeditor/cppplugin.h
@@ -75,8 +75,8 @@ private slots:
     void switchDeclarationDefinition();
     void jumpToDefinition();
     void renameSymbolUnderCursor();
-    void onTaskStarted(const QString &type);
-    void onAllTasksFinished(const QString &type);
+    void onCppModelIndexingStarted();
+    void onCppModelIndexingFinished();
     void findUsages();
 
 private:
@@ -90,6 +90,7 @@ private:
     bool m_sortedMethodOverview;
     QAction *m_renameSymbolUnderCursorAction;
     QAction *m_findUsagesAction;
+    QAction *m_updateCodeModelAction;
 };
 
 class CppEditorFactory : public Core::IEditorFactory
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
index 5cae6bdeaf3..6a490518401 100644
--- a/src/plugins/cpptools/cppmodelmanager.cpp
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -595,6 +595,8 @@ Document::Ptr CppPreprocessor::switchDocument(Document::Ptr doc)
 
 void CppTools::CppModelManagerInterface::updateModifiedSourceFiles()
 {
+    if (isIndexing())
+        return;
     const Snapshot snapshot = this->snapshot();
     QStringList sourceFiles;
 
@@ -630,7 +632,8 @@ CppTools::CppModelManagerInterface *CppTools::CppModelManagerInterface::instance
 */
 
 CppModelManager::CppModelManager(QObject *parent)
-    : CppModelManagerInterface(parent)
+    : CppModelManagerInterface(parent),
+      m_indexing(false)
 {
     m_findReferences = new CppFindReferences(this);
 
@@ -675,6 +678,11 @@ CppModelManager::CppModelManager(QObject *parent)
 
     connect(m_core->editorManager(), SIGNAL(editorAboutToClose(Core::IEditor *)),
         this, SLOT(editorAboutToClose(Core::IEditor *)));
+
+    connect(m_core->progressManager(), SIGNAL(taskStarted(QString)),
+            this, SLOT(onTaskStarted(QString)));
+    connect(m_core->progressManager(), SIGNAL(allTasksFinished(QString)),
+            this, SLOT(onAllTasksFinished(QString)));
 }
 
 CppModelManager::~CppModelManager()
@@ -871,7 +879,7 @@ QStringList CppModelManager::includesInPath(const QString &path) const
 
 QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles)
 {
-    if (! sourceFiles.isEmpty() && qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull()) {
+    if (!m_indexing && !sourceFiles.isEmpty() && qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull()) {
         const QMap<QString, QString> workingCopy = buildWorkingCopyList();
 
         CppPreprocessor *preproc = new CppPreprocessor(this);
@@ -897,7 +905,7 @@ QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles
 
         m_synchronizer.addFuture(result);
 
-        if (sourceFiles.count() > 1) {
+        if (sourceFiles.count() > 1) {            
             m_core->progressManager()->addTask(result, tr("Indexing"),
                             CppTools::Constants::TASK_INDEX,
                             Core::ProgressManager::CloseOnSuccess);
@@ -1391,4 +1399,31 @@ void CppModelManager::GC()
     protectSnapshot.unlock();
 }
 
+bool CppModelManager::isIndexing() const
+{
+    return m_indexing;
+}
+
+void CppModelManager::setIndexing(bool v)
+{
+    if (m_indexing == v)
+        return;
+    m_indexing = v;
+    if (v) {
+        emit indexingStarted();
+    } else {
+        emit indexingFinished();
+    }
+}
+
+void CppModelManager::onTaskStarted(const QString &type)
+{
+    if (type == QLatin1String(CppTools::Constants::TASK_INDEX))
+        setIndexing(true);
+}
 
+void CppModelManager::onAllTasksFinished(const QString &type)
+{
+    if (type == QLatin1String(CppTools::Constants::TASK_INDEX))
+        setIndexing(false);
+}
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
index 4222ccab6be..ca13b44a242 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -111,6 +111,8 @@ public:
     void setHeaderSuffixes(const QStringList &suffixes)
     { m_headerSuffixes = suffixes; }
 
+    virtual bool isIndexing() const;
+
 Q_SIGNALS:
     void projectPathChanged(const QString &projectPath);
 
@@ -129,6 +131,8 @@ private Q_SLOTS:
     void onProjectAdded(ProjectExplorer::Project *project);
     void postEditorUpdate();
     void updateEditorSelections();
+    void onTaskStarted(const QString &type);
+    void onAllTasksFinished(const QString &type);
 
 private:
     QMap<QString, QString> buildWorkingCopyList();
@@ -175,10 +179,13 @@ private:
                       CppPreprocessor *preproc,
                       QStringList files);
 
+    void setIndexing(bool);
+
 private:
     Core::ICore *m_core;
     CPlusPlus::Snapshot m_snapshot;
 
+    bool m_indexing;
     // cache
     bool m_dirty;
     QStringList m_projectFiles;
diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h
index 1976df75eab..1ec38abe304 100644
--- a/src/plugins/cpptools/cppmodelmanagerinterface.h
+++ b/src/plugins/cpptools/cppmodelmanagerinterface.h
@@ -102,6 +102,12 @@ public:
     virtual void renameUsages(CPlusPlus::Symbol *symbol) = 0;
     virtual void findUsages(CPlusPlus::Symbol *symbol) = 0;
 
+    virtual bool isIndexing() const = 0;
+
+signals:
+    void indexingStarted();
+    void indexingFinished();
+
 public Q_SLOTS:
     void updateModifiedSourceFiles();
     virtual void updateSourceFiles(const QStringList &sourceFiles) = 0;    
diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp
index bbc894390c8..d321b7c39b3 100644
--- a/src/plugins/cpptools/cpptoolsplugin.cpp
+++ b/src/plugins/cpptools/cpptoolsplugin.cpp
@@ -47,6 +47,7 @@
 #include <coreplugin/actionmanager/actionmanager.h>
 #include <coreplugin/editormanager/editormanager.h>
 #include <coreplugin/progressmanager/progressmanager.h>
+#include <coreplugin/vcsmanager.h>
 #include <cppeditor/cppeditorconstants.h>
 
 #include <QtCore/QtConcurrentRun>
@@ -97,6 +98,11 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
 
     // Objects
     m_modelManager = new CppModelManager(this);
+    Core::VCSManager *vcsManager = core->vcsManager();
+    connect(vcsManager, SIGNAL(repositoryChanged(QString)),
+            m_modelManager, SLOT(updateModifiedSourceFiles()));
+    connect(vcsManager, SIGNAL(filesChanged(QStringList)),
+            m_modelManager, SLOT(updateModifiedSourceFiles()));
     addAutoReleasedObject(m_modelManager);
 
     m_completion = new CppCodeCompletion(m_modelManager);
diff --git a/src/plugins/cvs/cvscontrol.cpp b/src/plugins/cvs/cvscontrol.cpp
index 51edeec5a69..1689f220527 100644
--- a/src/plugins/cvs/cvscontrol.cpp
+++ b/src/plugins/cvs/cvscontrol.cpp
@@ -96,3 +96,14 @@ QString CVSControl::findTopLevelForDirectory(const QString &directory) const
 {
     return m_plugin->findTopLevelForDirectory(directory);
 }
+
+void CVSControl::emitRepositoryChanged(const QString &s)
+{
+    emit repositoryChanged(s);
+}
+
+void CVSControl::emitFilesChanged(const QStringList &l)
+{
+    emit filesChanged(l);
+}
+
diff --git a/src/plugins/cvs/cvscontrol.h b/src/plugins/cvs/cvscontrol.h
index 52067ad3702..c6adb7ffa9c 100644
--- a/src/plugins/cvs/cvscontrol.h
+++ b/src/plugins/cvs/cvscontrol.h
@@ -56,6 +56,9 @@ public:
     virtual bool vcsAdd(const QString &fileName);
     virtual bool vcsDelete(const QString &filename);
 
+    void emitRepositoryChanged(const QString &s);
+    void emitFilesChanged(const QStringList &l);
+
 signals:
     void enabledChanged(bool);
 
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index 654fce42bb3..0fa8619e270 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -551,9 +551,11 @@ void CVSPlugin::revertCurrentFile()
     QStringList args(QLatin1String("update"));
     args.push_back(QLatin1String("-C"));
 
-    const CVSResponse revertResponse = runCVS(args, QStringList(file), cvsShortTimeOut, true);
+    const QStringList files = QStringList(file);
+    const CVSResponse revertResponse = runCVS(args, files, cvsShortTimeOut, true);
     if (revertResponse.result == CVSResponse::Ok) {
         fcb.setModifiedReload(true);
+        m_versionControl->emitFilesChanged(files);
     }
 }
 
@@ -734,7 +736,10 @@ void CVSPlugin::updateProject()
     if (!topLevels.empty()) {
         QStringList args(QLatin1String("update"));
         args.push_back(QLatin1String("-dR"));
-        runCVS(args, topLevels, cvsLongTimeOut, true);
+        const CVSResponse response = runCVS(args, topLevels, cvsLongTimeOut, true);
+        if (response.result == CVSResponse::Ok)
+            foreach(const QString &topLevel, topLevels)
+                m_versionControl->emitRepositoryChanged(topLevel);
     }
 }
 
diff --git a/src/plugins/cvs/cvsplugin.h b/src/plugins/cvs/cvsplugin.h
index c0f63473b2b..a1515cfc931 100644
--- a/src/plugins/cvs/cvsplugin.h
+++ b/src/plugins/cvs/cvsplugin.h
@@ -59,6 +59,7 @@ namespace CVS {
 namespace Internal {
 
 class CVSSubmitEditor;
+class CVSControl;
 
 struct CVSResponse
 {
@@ -153,7 +154,7 @@ private:
     void cleanCommitMessageFile();
 
     CVSSettings m_settings;
-    Core::IVersionControl *m_versionControl;
+    CVSControl *m_versionControl;
     QString m_commitMessageFileName;
 
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 419784887f0..486196174af 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -34,6 +34,7 @@
 #include "gitconstants.h"
 #include "gitplugin.h"
 #include "gitsubmiteditor.h"
+#include "gitversioncontrol.h"
 
 #include <coreplugin/actionmanager/actionmanager.h>
 #include <coreplugin/coreconstants.h>
@@ -43,6 +44,9 @@
 #include <coreplugin/progressmanager/progressmanager.h>
 #include <coreplugin/uniqueidmanager.h>
 #include <coreplugin/filemanager.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/iversioncontrol.h>
+
 #include <texteditor/itexteditor.h>
 #include <utils/qtcassert.h>
 #include <vcsbase/vcsbaseeditor.h>
@@ -55,6 +59,7 @@
 #include <QtCore/QTime>
 #include <QtCore/QFileInfo>
 #include <QtCore/QDir>
+#include <QtCore/QSignalMapper>
 
 #include <QtGui/QMainWindow> // for msg box parent
 #include <QtGui/QMessageBox>
@@ -102,7 +107,8 @@ static QString formatCommand(const QString &binary, const QStringList &args)
 GitClient::GitClient(GitPlugin* plugin)
   : m_msgWait(tr("Waiting for data...")),
     m_plugin(plugin),
-    m_core(Core::ICore::instance())
+    m_core(Core::ICore::instance()),
+    m_repositoryChangedSignalMapper(0)
 {
     if (QSettings *s = m_core->settings()) {
         m_settings.fromSettings(s);
@@ -317,7 +323,8 @@ void GitClient::checkoutBranch(const QString &workingDirectory, const QString &b
 {
     QStringList arguments(QLatin1String("checkout"));
     arguments <<  branch;
-    executeGit(workingDirectory, arguments, 0, true);
+    GitCommand *cmd = executeGit(workingDirectory, arguments, 0, true);
+    connectRepositoryChanged(workingDirectory, cmd);
 }
 
 void GitClient::checkout(const QString &workingDirectory, const QString &fileName)
@@ -341,7 +348,8 @@ void GitClient::hardReset(const QString &workingDirectory, const QString &commit
     if (!commit.isEmpty())
         arguments << commit;
 
-    executeGit(workingDirectory, arguments, 0, true);
+    GitCommand *cmd = executeGit(workingDirectory, arguments, 0, true);
+    connectRepositoryChanged(workingDirectory, cmd);
 }
 
 void GitClient::addFile(const QString &workingDirectory, const QString &fileName)
@@ -500,18 +508,19 @@ GitCommand *GitClient::createCommand(const QString &workingDirectory,
 }
 
 // Execute a single command
-void GitClient::executeGit(const QString &workingDirectory,
-                           const QStringList &arguments,
-                           VCSBase::VCSBaseEditor* editor,
-                           bool outputToWindow,
-                           GitCommand::TerminationReportMode tm,
-                           int editorLineNumber)
+GitCommand *GitClient::executeGit(const QString &workingDirectory,
+                                  const QStringList &arguments,
+                                  VCSBase::VCSBaseEditor* editor,
+                                  bool outputToWindow,
+                                  GitCommand::TerminationReportMode tm,
+                                  int editorLineNumber)
 {
     VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(QLatin1String(Constants::GIT_BINARY), arguments));
     GitCommand *command = createCommand(workingDirectory, editor, outputToWindow, editorLineNumber);
     command->addJob(arguments, m_settings.timeout);
     command->setTerminationReportMode(tm);
     command->execute();
+    return command;
 }
 
 // Return fixed arguments required to run
@@ -903,6 +912,8 @@ void GitClient::revert(const QStringList &files)
     QString errorMessage;
     switch (revertI(files, &isDirectory, &errorMessage)) {
     case RevertOk:
+        m_plugin->versionControl()->emitFilesChanged(files);
+        break;
     case RevertCanceled:
         break;
     case RevertUnchanged: {
@@ -918,7 +929,8 @@ void GitClient::revert(const QStringList &files)
 
 void GitClient::pull(const QString &workingDirectory)
 {
-    executeGit(workingDirectory, QStringList(QLatin1String("pull")), 0, true, GitCommand::ReportStderr);
+    GitCommand *cmd = executeGit(workingDirectory, QStringList(QLatin1String("pull")), 0, true, GitCommand::ReportStderr);
+    connectRepositoryChanged(workingDirectory, cmd);
 }
 
 void GitClient::push(const QString &workingDirectory)
@@ -952,7 +964,8 @@ void GitClient::stashPop(const QString &workingDirectory)
 {
     QStringList arguments(QLatin1String("stash"));
     arguments << QLatin1String("pop");
-    executeGit(workingDirectory, arguments, 0, true);
+    GitCommand *cmd = executeGit(workingDirectory, arguments, 0, true);
+    connectRepositoryChanged(workingDirectory, cmd);
 }
 
 void GitClient::branchList(const QString &workingDirectory)
@@ -1000,3 +1013,16 @@ void GitClient::setSettings(const GitSettings &s)
         m_binaryPath = m_settings.gitBinaryPath();
     }
 }
+
+void GitClient::connectRepositoryChanged(const QString & repository, GitCommand *cmd)
+{
+    // Bind command success termination with repository to changed signal
+    if (!m_repositoryChangedSignalMapper) {
+        m_repositoryChangedSignalMapper = new QSignalMapper(this);
+        connect(m_repositoryChangedSignalMapper, SIGNAL(mapped(QString)),
+                m_plugin->versionControl(), SIGNAL(repositoryChanged(QString)));
+    }
+    m_repositoryChangedSignalMapper->setMapping(cmd, repository);
+    connect(cmd, SIGNAL(success()), m_repositoryChangedSignalMapper, SLOT(map()),
+            Qt::QueuedConnection);
+}
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index 341e177f353..76da3120347 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -33,7 +33,6 @@
 #include "gitsettings.h"
 #include "gitcommand.h"
 
-#include <coreplugin/iversioncontrol.h>
 #include <coreplugin/editormanager/ieditor.h>
 
 #include <QtCore/QString>
@@ -41,6 +40,7 @@
 
 QT_BEGIN_NAMESPACE
 class QErrorMessage;
+class QSignalMapper;
 QT_END_NAMESPACE
 
 namespace Core {
@@ -158,12 +158,12 @@ private:
                              bool outputToWindow = false,
                              int editorLineNumber = -1);
 
-    void executeGit(const QString &workingDirectory,
-                    const QStringList &arguments,
-                    VCSBase::VCSBaseEditor* editor = 0,
-                    bool outputToWindow = false,
-                    GitCommand::TerminationReportMode tm = GitCommand::NoReport,
-                    int editorLineNumber = -1);
+    GitCommand *executeGit(const QString &workingDirectory,
+                           const QStringList &arguments,
+                           VCSBase::VCSBaseEditor* editor = 0,
+                           bool outputToWindow = false,
+                           GitCommand::TerminationReportMode tm = GitCommand::NoReport,
+                           int editorLineNumber = -1);
 
     bool synchronousGit(const QString &workingDirectory,
                         const QStringList &arguments,
@@ -173,12 +173,14 @@ private:
 
     enum RevertResult { RevertOk, RevertUnchanged, RevertCanceled, RevertFailed };
     RevertResult revertI(QStringList files, bool *isDirectory, QString *errorMessage);
+    void connectRepositoryChanged(const QString & repository, GitCommand *cmd);
 
     const QString m_msgWait;
     GitPlugin     *m_plugin;
     Core::ICore   *m_core;
     GitSettings   m_settings;
     QString m_binaryPath;
+    QSignalMapper *m_repositoryChangedSignalMapper;
 };
 
 
diff --git a/src/plugins/git/gitcommand.cpp b/src/plugins/git/gitcommand.cpp
index 3f7a97095e6..ea6c17dab13 100644
--- a/src/plugins/git/gitcommand.cpp
+++ b/src/plugins/git/gitcommand.cpp
@@ -177,6 +177,8 @@ void GitCommand::run()
         emit errorText(error);
 
     emit finished(ok, m_cookie);
+    if (ok)
+        emit success();
     // As it is used asynchronously, we need to delete ourselves
     this->deleteLater();
 }
diff --git a/src/plugins/git/gitcommand.h b/src/plugins/git/gitcommand.h
index 7acf167750f..8f1c5aad0ec 100644
--- a/src/plugins/git/gitcommand.h
+++ b/src/plugins/git/gitcommand.h
@@ -73,6 +73,7 @@ Q_SIGNALS:
     void outputData(const QByteArray&);
     void errorText(const QString&);
     void finished(bool ok, const QVariant &cookie);
+    void success();
 
 private:
     struct Job {
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index 7b51b39fbf8..8ce1b1938d3 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -142,6 +142,7 @@ GitPlugin::GitPlugin() :
     m_stashListAction(0),
     m_branchListAction(0),
     m_gitClient(0),
+    m_versionControl(0),
     m_changeSelectionDialog(0),
     m_submitActionTriggered(false)
 {
@@ -215,8 +216,8 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
 
     addAutoReleasedObject(new GitSubmitEditorFactory(&submitParameters));
 
-    GitVersionControl *versionControl = new GitVersionControl(m_gitClient);
-    addAutoReleasedObject(versionControl);
+    m_versionControl = new GitVersionControl(m_gitClient);
+    addAutoReleasedObject(m_versionControl);
 
     addAutoReleasedObject(new CloneWizard);
     addAutoReleasedObject(new Gitorious::Internal::GitoriousCloneWizard);
@@ -232,8 +233,8 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
     gitContainer->menu()->setTitle(tr("&Git"));
     toolsContainer->addMenu(gitContainer);
     if (QAction *ma = gitContainer->menu()->menuAction()) {
-        ma->setEnabled(versionControl->isEnabled());
-        connect(versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool)));
+        ma->setEnabled(m_versionControl->isEnabled());
+        connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool)));
     }
 
     Core::Command *command;
@@ -398,6 +399,11 @@ void GitPlugin::extensionsInitialized()
 {
 }
 
+GitVersionControl *GitPlugin::versionControl() const
+{
+    return m_versionControl;
+}
+
 void GitPlugin::submitEditorDiff(const QStringList &unstaged, const QStringList &staged)
 {
     m_gitClient->diff(m_submitRepository, QStringList(), unstaged, staged);
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
index 4f934a89393..0d6ad7fbdd5 100644
--- a/src/plugins/git/gitplugin.h
+++ b/src/plugins/git/gitplugin.h
@@ -59,6 +59,7 @@ namespace Git {
 namespace Internal {
 
 class GitPlugin;
+class GitVersionControl;
 class GitClient;
 class ChangeSelectionDialog;
 class GitSubmitEditor;
@@ -96,6 +97,7 @@ public:
     void setSettings(const GitSettings &s);
 
     GitClient *gitClient() const;
+    GitVersionControl *versionControl() const;
 
 public slots:
     void updateActions();
@@ -159,6 +161,7 @@ private:
     QAction *m_branchListAction;
 
     GitClient                   *m_gitClient;
+    GitVersionControl           *m_versionControl;
     ChangeSelectionDialog       *m_changeSelectionDialog;
     QString                     m_submitRepository;
     QStringList                 m_submitOrigCommitFiles;
diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp
index 559d296220e..c64a683bea0 100644
--- a/src/plugins/git/gitversioncontrol.cpp
+++ b/src/plugins/git/gitversioncontrol.cpp
@@ -96,5 +96,10 @@ QString GitVersionControl::findTopLevelForDirectory(const QString &directory) co
     return GitClient::findRepositoryForDirectory(directory);
 }
 
+void GitVersionControl::emitFilesChanged(const QStringList &l)
+{
+    emit filesChanged(l);
+}
+
 } // Internal
 } // Git
diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h
index 72908b0da22..44598000638 100644
--- a/src/plugins/git/gitversioncontrol.h
+++ b/src/plugins/git/gitversioncontrol.h
@@ -57,6 +57,8 @@ public:
     virtual bool vcsAdd(const QString &fileName);
     virtual bool vcsDelete(const QString &filename);
 
+    void emitFilesChanged(const QStringList &);
+
 signals:
     void enabledChanged(bool);
 
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 7039798b094..a80d8f55973 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -454,6 +454,8 @@ void PerforcePlugin::revertCurrentFile()
     Core::FileChangeBlocker fcb(fileName);
     fcb.setModifiedReload(true);
     PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    if (!result2.error)
+        m_versionControl->emitFilesChanged(QStringList(fileName));
 }
 
 void PerforcePlugin::diffCurrentFile()
@@ -514,7 +516,10 @@ void PerforcePlugin::updateCheckout(const QStringList &dirs)
 {
     QStringList args(QLatin1String("sync"));
     args.append(dirs);
-    runP4Cmd(args, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    const PerforceResponse resp = runP4Cmd(args, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    if (!dirs.empty())
+        foreach(const QString &dir, dirs)
+            m_versionControl->emitRepositoryChanged(dir);
 }
 
 void PerforcePlugin::printOpenedFileList()
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
index 040692428d8..ad915b2a208 100644
--- a/src/plugins/perforce/perforceversioncontrol.cpp
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -94,5 +94,15 @@ QString PerforceVersionControl::findTopLevelForDirectory(const QString &director
     return m_plugin->findTopLevelForDirectory(directory);
 }
 
+void PerforceVersionControl::emitRepositoryChanged(const QString &s)
+{
+    emit repositoryChanged(s);
+}
+
+void PerforceVersionControl::emitFilesChanged(const QStringList &l)
+{
+    emit filesChanged(l);
+}
+
 } // Internal
 } // Perforce
diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h
index 2992e5518be..dd385061cbc 100644
--- a/src/plugins/perforce/perforceversioncontrol.h
+++ b/src/plugins/perforce/perforceversioncontrol.h
@@ -56,6 +56,9 @@ public:
     virtual bool vcsAdd(const QString &fileName);
     virtual bool vcsDelete(const QString &filename);
 
+    void emitRepositoryChanged(const QString &s);
+    void emitFilesChanged(const QStringList &l);
+
 signals:
     void enabledChanged(bool);
 
diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp
index 32ef57e5ecc..ff0e0f1c81e 100644
--- a/src/plugins/subversion/subversioncontrol.cpp
+++ b/src/plugins/subversion/subversioncontrol.cpp
@@ -96,3 +96,13 @@ QString SubversionControl::findTopLevelForDirectory(const QString &directory) co
 {
     return m_plugin->findTopLevelForDirectory(directory);
 }
+
+void SubversionControl::emitRepositoryChanged(const QString &s)
+{
+    emit repositoryChanged(s);
+}
+
+void SubversionControl::emitFilesChanged(const QStringList &l)
+{
+    emit filesChanged(l);
+}
diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h
index 42f64ab147e..325cfd10989 100644
--- a/src/plugins/subversion/subversioncontrol.h
+++ b/src/plugins/subversion/subversioncontrol.h
@@ -56,6 +56,9 @@ public:
     virtual bool vcsAdd(const QString &fileName);
     virtual bool vcsDelete(const QString &filename);
 
+    void emitRepositoryChanged(const QString &);
+    void emitFilesChanged(const QStringList &);
+
 signals:
     void enabledChanged(bool);
 
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index 676ffc2b8ad..0060e023953 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -574,6 +574,7 @@ void SubversionPlugin::revertCurrentFile()
     const SubversionResponse revertResponse = runSvn(args, subversionShortTimeOut, true);
     if (!revertResponse.error) {
         fcb.setModifiedReload(true);
+        m_versionControl->emitFilesChanged(QStringList(file));
     }
 }
 
@@ -750,7 +751,10 @@ void SubversionPlugin::updateProject()
     QStringList args(QLatin1String("update"));
     args.push_back(QLatin1String(nonInteractiveOptionC));
     args.append(topLevels);
-    runSvn(args, subversionLongTimeOut, true);
+    const SubversionResponse response = runSvn(args, subversionLongTimeOut, true);
+    if (!response.error)
+        foreach(const QString &repo, topLevels)
+            m_versionControl->emitRepositoryChanged(repo);
 }
 
 void SubversionPlugin::annotateCurrentFile()
diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h
index 1dcfce68032..6e3dab7e5d3 100644
--- a/src/plugins/subversion/subversionplugin.h
+++ b/src/plugins/subversion/subversionplugin.h
@@ -56,6 +56,7 @@ namespace Subversion {
 namespace Internal {
 
 class SubversionSubmitEditor;
+class SubversionControl;
 
 struct SubversionResponse
 {
@@ -131,7 +132,7 @@ private:
     const QStringList m_svnDirectories;
 
     SubversionSettings m_settings;
-    Core::IVersionControl *m_versionControl;
+    SubversionControl *m_versionControl;
     QString m_commitMessageFileName;
 
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
-- 
GitLab