From de49067803809e714b84eae70c1fc5dd16bd6948 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Tue, 8 Dec 2009 14:28:00 +0100
Subject: [PATCH] Mercurial: Adapt to 8097879d6d98ce304f742823ccb9bddfcec44839

Make use of VCS base class.
---
 src/plugins/mercurial/mercurialclient.cpp  | 186 ++++++++--------
 src/plugins/mercurial/mercurialclient.h    |  41 ++--
 src/plugins/mercurial/mercurialcontrol.cpp |  27 +--
 src/plugins/mercurial/mercurialcontrol.h   |   5 -
 src/plugins/mercurial/mercurialplugin.cpp  | 239 +++++++++------------
 src/plugins/mercurial/mercurialplugin.h    |  37 +---
 6 files changed, 240 insertions(+), 295 deletions(-)

diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp
index 596a289525e..c6effd96a38 100644
--- a/src/plugins/mercurial/mercurialclient.cpp
+++ b/src/plugins/mercurial/mercurialclient.cpp
@@ -78,48 +78,46 @@ MercurialClient::~MercurialClient()
     }
 }
 
-bool MercurialClient::add(const QString &filename)
+bool MercurialClient::add(const QString &workingDir, const QString &filename)
 {
-    QFileInfo file(filename);
     QStringList args;
-    args << QLatin1String("add") << file.absoluteFilePath();
-
-    return executeHgSynchronously(file, args);
+    args << QLatin1String("add") << filename;
+    return executeHgSynchronously(workingDir, args);
 }
 
-bool MercurialClient::remove(const QString &filename)
+bool MercurialClient::remove(const QString &workingDir, const QString &filename)
 {
-    QFileInfo file(filename);
     QStringList args;
-    args << QLatin1String("remove") << file.absoluteFilePath();
-
-    return executeHgSynchronously(file, args);
+    args << QLatin1String("remove") << filename;
+    return executeHgSynchronously(workingDir, args);
 }
 
-bool MercurialClient::manifestSync(const QString &filename)
+bool MercurialClient::manifestSync(const QString &repository, const QString &relativeFilename)
 {
-    QFileInfo file(filename);
-    QStringList args(QLatin1String("manifest"));
+    // This  only works when called from the repo and outputs paths relative to it.
+    const QStringList args(QLatin1String("manifest"));
 
     QByteArray output;
-    executeHgSynchronously(file, args, &output);
+    executeHgSynchronously(repository, args, &output);
+    const QDir repositoryDir(repository);
+    const QFileInfo needle = QFileInfo(repositoryDir, relativeFilename);
 
     const QStringList files = QString::fromLocal8Bit(output).split(QLatin1Char('\n'));
-
     foreach (const QString &fileName, files) {
-        const QFileInfo managedFile(fileName);
-        if (file == managedFile)
+        const QFileInfo managedFile(repositoryDir, fileName);
+        if (needle == managedFile)
             return true;
     }
-
     return false;
 }
 
-bool MercurialClient::executeHgSynchronously(const QFileInfo &file, const QStringList &args,
+bool MercurialClient::executeHgSynchronously(const QString  &workingDir,
+                                             const QStringList &args,
                                              QByteArray *output) const
 {
     QProcess hgProcess;
-    hgProcess.setWorkingDirectory(file.isDir() ? file.absoluteFilePath() : file.absolutePath());
+    if (!workingDir.isEmpty())
+        hgProcess.setWorkingDirectory(workingDir);
 
     const MercurialSettings &settings = MercurialPlugin::instance()->settings();
     const QString binary = settings.binary();
@@ -152,7 +150,7 @@ bool MercurialClient::executeHgSynchronously(const QFileInfo &file, const QStrin
     return false;
 }
 
-QString MercurialClient::branchQuerySync(const QFileInfo &repositoryRoot)
+QString MercurialClient::branchQuerySync(const QString &repositoryRoot)
 {
     QByteArray output;
     if (executeHgSynchronously(repositoryRoot, QStringList(QLatin1String("branch")), &output))
@@ -161,66 +159,53 @@ QString MercurialClient::branchQuerySync(const QFileInfo &repositoryRoot)
     return QLatin1String("Unknown Branch");
 }
 
-void MercurialClient::annotate(const QFileInfo &file)
+void MercurialClient::annotate(const QString &workingDir, const QString &file)
 {
     QStringList args;
-    args << QLatin1String("annotate") << QLatin1String("-u") << QLatin1String("-c") << QLatin1String("-d") << file.absoluteFilePath();
+    args << QLatin1String("annotate") << QLatin1String("-u") << QLatin1String("-c") << QLatin1String("-d") << file;
 
     const QString kind = QLatin1String(Constants::ANNOTATELOG);
-    const QString title = tr("Hg Annotate %1").arg(file.fileName());
+    const QString id   = VCSBase::VCSBaseEditor::getSource(workingDir, QStringList(file));
+    const QString title = tr("Hg Annotate %1").arg(id);
+    const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, file);
 
-    VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, file.absolutePath(), true,
-                                                     "annotate", file.absoluteFilePath());
+    VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, source, true,
+                                                     "annotate", id);
 
-    QSharedPointer<HgTask> job(new HgTask(file.absolutePath(), args, editor));
+    QSharedPointer<HgTask> job(new HgTask(workingDir, args, editor));
     enqueueJob(job);
 }
 
-void MercurialClient::diff(const QFileInfo &fileOrDir)
+void MercurialClient::diff(const QString &workingDir, const QStringList &files)
 {
     QStringList args;
-    QString id;
-    QString workingPath;
-
     args << QLatin1String("diff") << QLatin1String("-g") << QLatin1String("-p")
          << QLatin1String("-U 8");
-
-    if (!fileOrDir.isDir()) {
-        args.append(fileOrDir.absoluteFilePath());
-        id = fileOrDir.absoluteFilePath();
-        workingPath = fileOrDir.absolutePath();
-    } else {
-        id = MercurialPlugin::instance()->currentProjectName();
-        workingPath = fileOrDir.absoluteFilePath();
-    }
+    if (!files.isEmpty())
+        args.append(files);
 
     const QString kind = QLatin1String(Constants::DIFFLOG);
-    const QString title = tr("Hg diff %1").arg(fileOrDir.isDir() ? id : fileOrDir.fileName());
-
-    VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingPath, true,
+    const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir,files);
+    const QString title = tr("Hg diff %1").arg(id);
+    const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files);
+    VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, source, true,
                                                      "diff", id);
 
-    QSharedPointer<HgTask> job(new HgTask(workingPath, args, editor));
+    QSharedPointer<HgTask> job(new HgTask(workingDir, args, editor));
     enqueueJob(job);
 }
 
-void MercurialClient::log(const QFileInfo &fileOrDir)
+
+void MercurialClient::log(const QString &workingDir, const QStringList &files)
 {
     QStringList args(QLatin1String("log"));
-    QString id;
-    QString workingDir;
-
-    if (!fileOrDir.isDir()) {
-        args.append(fileOrDir.absoluteFilePath());
-        id = fileOrDir.absoluteFilePath();
-        workingDir = fileOrDir.absolutePath();
-    } else {
-        id = MercurialPlugin::instance()->currentProjectName();
-        workingDir = fileOrDir.absoluteFilePath();
-    }
+    if (!files.empty())
+        args.append(files);
 
     const QString kind = QLatin1String(Constants::FILELOG);
-    const QString title = tr("Hg log %1").arg(fileOrDir.isDir() ? id : fileOrDir.fileName());
+    const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir,files);
+    const QString title = tr("Hg log %1").arg(id);
+    const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files);
 
     VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingDir, true,
                                                      "log", id);
@@ -229,42 +214,51 @@ void MercurialClient::log(const QFileInfo &fileOrDir)
     enqueueJob(job);
 }
 
-void MercurialClient::revert(const QFileInfo &fileOrDir, const QString &revision)
+void MercurialClient::revertFile(const QString &workingDir,
+                                 const QString &file,
+                                 const QString &revision)
 {
-    const QString filePath = fileOrDir.absoluteFilePath();
-    const QString workingDir = fileOrDir.isDir() ? filePath : fileOrDir.absolutePath();
+    const QStringList cookieList(workingDir + QLatin1Char('/') + file);
+    revert(workingDir, file, revision, QVariant(cookieList));
+}
 
+void MercurialClient::revertRepository(const QString &workingDir,
+                                       const QString &revision)
+{
+    revert(workingDir, QLatin1String("--all"), revision, QVariant(workingDir));
+}
+
+void MercurialClient::revert(const QString &workingDir,
+                             const QString &argument,
+                             const QString &revision,
+                             const QVariant &cookie)
+{
     QStringList args(QLatin1String("revert"));    
     if (!revision.isEmpty())
         args << QLatin1String("-r") << revision;
-    args.append(fileOrDir.isDir() ? QString(QLatin1String("--all")) : filePath);
+    args.append(argument);
 
     // Indicate repository change or file list
-    const QVariant cookie = fileOrDir.isDir() ? QVariant(filePath) : QVariant(QStringList(filePath));
     QSharedPointer<HgTask> job(new HgTask(workingDir, args, false, cookie));
     connect(job.data(), SIGNAL(succeeded(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection);
     enqueueJob(job);
 }
 
-void MercurialClient::status(const QFileInfo &fileOrDir)
+void MercurialClient::status(const QString &workingDir, const QString &file)
 {
     QStringList args(QLatin1String("status"));
-    if (!fileOrDir.isDir())
-        args.append(fileOrDir.absoluteFilePath());
-
-    QSharedPointer<HgTask> job(new HgTask(fileOrDir.isDir() ? fileOrDir.absoluteFilePath() :
-                                          fileOrDir.absolutePath(), args, false));
+    if (!file.isEmpty())
+        args.append(file);
+    QSharedPointer<HgTask> job(new HgTask(workingDir, args, false));
     enqueueJob(job);
 }
 
-void MercurialClient::statusWithSignal(const QFileInfo &repositoryRoot)
+void MercurialClient::statusWithSignal(const QString &repositoryRoot)
 {
     const QStringList args(QLatin1String("status"));
-
-    QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, true));
+    QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, true));
     connect(job.data(), SIGNAL(rawData(QByteArray)),
             this, SLOT(statusParser(QByteArray)));
-
     enqueueJob(job);
 }
 
@@ -299,72 +293,71 @@ void MercurialClient::statusParser(const QByteArray &data)
     emit parsedStatus(statusList);
 }
 
-void MercurialClient::import(const QFileInfo &repositoryRoot, const QStringList &files)
+void MercurialClient::import(const QString &repositoryRoot, const QStringList &files)
 {
     QStringList args;
     args << QLatin1String("import") << QLatin1String("--no-commit");
     args += files;
 
-    QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
+    QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, false));
     enqueueJob(job);
 }
 
-void MercurialClient::pull(const QFileInfo &repositoryRoot, const QString &repository)
+void MercurialClient::pull(const QString &repositoryRoot, const QString &repository)
 {
     QStringList args(QLatin1String("pull"));
     if (!repository.isEmpty())
         args.append(repository);
-
-    const QString path = repositoryRoot.absoluteFilePath();
-
-    QSharedPointer<HgTask> job(new HgTask(path, args, false, QVariant(path)));
+    QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, false, QVariant(repositoryRoot)));
     connect(job.data(), SIGNAL(succeeded(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection);
     enqueueJob(job);
 }
 
-void MercurialClient::push(const QFileInfo &repositoryRoot, const QString &repository)
+void MercurialClient::push(const QString &repositoryRoot, const QString &repository)
 {
     QStringList args(QLatin1String("push"));
     if (!repository.isEmpty())
         args.append(repository);
 
-    QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
+    QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, false));
     enqueueJob(job);
 }
 
-void MercurialClient::incoming(const QFileInfo &repositoryRoot, const QString &repository)
+void MercurialClient::incoming(const QString &repositoryRoot, const QString &repository)
 {
     QStringList args;
     args << QLatin1String("incoming") << QLatin1String("-g") << QLatin1String("-p");
     if (!repository.isEmpty())
         args.append(repository);
 
-    QString id = MercurialPlugin::instance()->currentProjectName();
+    QString id = repositoryRoot;
+    if (!repository.isEmpty()) {
+        id += QDir::separator();
+        id += repository;
+    }
 
     const QString kind = QLatin1String(Constants::DIFFLOG);
     const QString title = tr("Hg incoming %1").arg(id);
 
-    VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, repositoryRoot.absoluteFilePath(),
+    VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, repositoryRoot,
                                                      true, "incoming", id);
 
-    QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, editor));
+    QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, editor));
     enqueueJob(job);
 }
 
-void MercurialClient::outgoing(const QFileInfo &repositoryRoot)
+void MercurialClient::outgoing(const QString &repositoryRoot)
 {
     QStringList args;
     args << QLatin1String("outgoing") << QLatin1String("-g") << QLatin1String("-p");
 
-    QString id = MercurialPlugin::instance()->currentProjectName();
-
     const QString kind = QLatin1String(Constants::DIFFLOG);
-    const QString title = tr("Hg outgoing %1").arg(id);
+    const QString title = tr("Hg outgoing %1").arg(repositoryRoot);
 
-    VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, repositoryRoot.absoluteFilePath(), true,
-                                                     "outgoing", id);
+    VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, repositoryRoot, true,
+                                                     "outgoing", repositoryRoot);
 
-    QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, editor));
+    QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, editor));
     enqueueJob(job);
 }
 
@@ -384,26 +377,25 @@ void MercurialClient::view(const QString &source, const QString &id)
     enqueueJob(job);
 }
 
-void MercurialClient::update(const QFileInfo &repositoryRoot, const QString &revision)
+void MercurialClient::update(const QString &repositoryRoot, const QString &revision)
 {
     QStringList args(QLatin1String("update"));
     if (!revision.isEmpty())
         args << revision;
 
-    const QString path = repositoryRoot.absoluteFilePath();
-    QSharedPointer<HgTask> job(new HgTask(path, args, false, QVariant(path)));
+    QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, false, QVariant(repositoryRoot)));
     connect(job.data(), SIGNAL(succeeded(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection);
     enqueueJob(job);
 }
 
-void MercurialClient::commit(const QFileInfo &repositoryRoot, const QStringList &files,
+void MercurialClient::commit(const QString &repositoryRoot, const QStringList &files,
                              const QString &committerInfo, const QString &commitMessageFile)
 {
     QStringList args(QLatin1String("commit"));
     if (!committerInfo.isEmpty())
         args << QLatin1String("-u") << committerInfo;
     args << QLatin1String("-l") << commitMessageFile << files;
-    QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
+    QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, false));
     enqueueJob(job);
 }
 
diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h
index 87c5b25c6e8..3224908c196 100644
--- a/src/plugins/mercurial/mercurialclient.h
+++ b/src/plugins/mercurial/mercurialclient.h
@@ -31,6 +31,7 @@
 #define MERCURIALCLIENT_H
 
 #include <QtCore/QObject>
+#include <QtCore/QStringList>
 #include <QtCore/QPair>
 #include <QtCore/QSharedPointer>
 
@@ -59,23 +60,24 @@ class MercurialClient : public QObject
 public:
     MercurialClient();
     ~MercurialClient();
-    bool add(const QString &fileName);
-    bool remove(const QString &fileName);
-    bool manifestSync(const QString &filename);
-    QString branchQuerySync(const QFileInfo &repositoryRoot);
-    void annotate(const QFileInfo &file);
-    void diff(const QFileInfo &fileOrDir);
-    void log(const QFileInfo &fileOrDir);
-    void import(const QFileInfo &repositoryRoot, const QStringList &files);
-    void pull(const QFileInfo &repositoryRoot, const QString &repository);
-    void push(const QFileInfo &repositoryRoot, const QString &repository);
-    void incoming(const QFileInfo &repositoryRoot, const QString &repository);
-    void outgoing(const QFileInfo &repositoryRoot);
-    void status(const QFileInfo &fileOrDir);
-    void statusWithSignal(const QFileInfo &fileOrDir);
-    void revert(const QFileInfo &fileOrDir, const QString &revision);
-    void update(const QFileInfo &repositoryRoot, const QString &revision);
-    void commit(const QFileInfo &repositoryRoot, const QStringList &files,
+    bool add(const QString &workingDir, const QString &fileName);
+    bool remove(const QString &workingDir, const QString &fileName);
+    bool manifestSync(const QString &repository, const QString &filename);
+    QString branchQuerySync(const QString &repositoryRoot);
+    void annotate(const QString &workingDir, const QString &files);
+    void diff(const QString &workingDir, const QStringList &files = QStringList());
+    void log(const QString &workingDir, const QStringList &files = QStringList());
+    void import(const QString &repositoryRoot, const QStringList &files);
+    void pull(const QString &repositoryRoot, const QString &repository = QString());
+    void push(const QString &repositoryRoot, const QString &repository = QString());
+    void incoming(const QString &repositoryRoot, const QString &repository = QString());
+    void outgoing(const QString &repositoryRoot);
+    void status(const QString &workingDir, const QString &file = QString());
+    void statusWithSignal(const QString &repository);
+    void revertFile(const QString &workingDir, const QString &file, const QString &revision = QString());
+    void revertRepository(const QString &workingDir, const QString &revision = QString());
+    void update(const QString &repositoryRoot, const QString &revision = QString());
+    void commit(const QString &repositoryRoot, const QStringList &files,
                 const QString &commiterInfo, const QString &commitMessageFile);
 
     static QString findTopLevelForFile(const QFileInfo &file);
@@ -93,9 +95,12 @@ private slots:
     void statusParser(const QByteArray &data);
 
 private:
-    bool executeHgSynchronously(const QFileInfo &file, const QStringList &args,
+    bool executeHgSynchronously(const QString  &workingDir,
+                                const QStringList &args,
                                 QByteArray *output=0) const;
     void enqueueJob(const QSharedPointer<HgTask> &);
+    void revert(const QString &workingDir, const QString &argument,
+                const QString &revision, const QVariant &cookie);
 
     MercurialJobRunner *jobManager;
     Core::ICore *core;
diff --git a/src/plugins/mercurial/mercurialcontrol.cpp b/src/plugins/mercurial/mercurialcontrol.cpp
index 8dd3cd94bba..c118aa0d3f4 100644
--- a/src/plugins/mercurial/mercurialcontrol.cpp
+++ b/src/plugins/mercurial/mercurialcontrol.cpp
@@ -33,6 +33,7 @@
 #include <QtCore/QFileInfo>
 #include <QtCore/QVariant>
 #include <QtCore/QStringList>
+#include <QtCore/QDir>
 
 using namespace Mercurial::Internal;
 
@@ -47,19 +48,6 @@ QString MercurialControl::name() const
     return tr("Mercurial");
 }
 
-bool MercurialControl::isEnabled() const
-{
-    return mercurialEnabled;
-}
-
-void MercurialControl::setEnabled(bool enabled)
-{
-    if (mercurialEnabled != enabled) {
-        mercurialEnabled = enabled;
-        emit enabledChanged(mercurialEnabled);
-    }
-}
-
 bool MercurialControl::managesDirectory(const QString &directory) const
 {
     QFileInfo dir(directory);
@@ -97,17 +85,24 @@ bool MercurialControl::vcsOpen(const QString &filename)
 
 bool MercurialControl::vcsAdd(const QString &filename)
 {
-    return mercurialClient->add(filename);
+    const QFileInfo fi(filename);
+    return mercurialClient->add(fi.absolutePath(), fi.fileName());
 }
 
 bool MercurialControl::vcsDelete(const QString &filename)
 {
-    return mercurialClient->remove(filename);
+    const QFileInfo fi(filename);
+    return mercurialClient->remove(fi.absolutePath(), fi.fileName());
 }
 
 bool MercurialControl::sccManaged(const QString &filename)
 {
-    return mercurialClient->manifestSync(filename);
+    const QFileInfo fi(filename);
+    const QString topLevel = findTopLevelForDirectory(fi.absolutePath());
+    if (topLevel.isEmpty())
+        return false;
+    const QDir topLevelDir(topLevel);
+    return mercurialClient->manifestSync(topLevel, topLevelDir.relativeFilePath(filename));
 }
 
 void MercurialControl::changed(const QVariant &v)
diff --git a/src/plugins/mercurial/mercurialcontrol.h b/src/plugins/mercurial/mercurialcontrol.h
index 01c77e47bcf..8e2c2fb1532 100644
--- a/src/plugins/mercurial/mercurialcontrol.h
+++ b/src/plugins/mercurial/mercurialcontrol.h
@@ -50,8 +50,6 @@ public:
     explicit MercurialControl(MercurialClient *mercurialClient);
 
     QString name() const;
-    bool isEnabled() const;
-    void setEnabled(bool enabled);
     bool managesDirectory(const QString &filename) const;
     QString findTopLevelForDirectory(const QString &directory) const;
     bool supportsOperation(Operation operation) const;
@@ -66,9 +64,6 @@ public slots:
     // String -> repository, StringList -> files
     void changed(const QVariant&);
 
-signals:
-    void enabledChanged(bool);
-
 private:
     MercurialClient *mercurialClient;
     bool mercurialEnabled;
diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp
index 49963698ec7..b858e8ab124 100644
--- a/src/plugins/mercurial/mercurialplugin.cpp
+++ b/src/plugins/mercurial/mercurialplugin.cpp
@@ -48,10 +48,8 @@
 #include <coreplugin/filemanager.h>
 #include <coreplugin/editormanager/editormanager.h>
 
-
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/project.h>
 #include <utils/parameteraction.h>
+#include <utils/qtcassert.h>
 
 #include <vcsbase/basevcseditorfactory.h>
 #include <vcsbase/basevcssubmiteditorfactory.h>
@@ -73,11 +71,6 @@
 using namespace Mercurial::Internal;
 using namespace Mercurial;
 
-bool ListenForClose::editorAboutToClose(Core::IEditor *editor)
-{
-    return MercurialPlugin::instance()->closeEditor(editor);
-}
-
 static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
 {
     VCSBase::RegularCommandOutput, //type
@@ -122,11 +115,11 @@ static inline const VCSBase::VCSBaseEditorParameters *findType(int ie)
 MercurialPlugin *MercurialPlugin::m_instance = 0;
 
 MercurialPlugin::MercurialPlugin() :
+        VCSBase::VCSBasePlugin(QLatin1String(Constants::COMMITKIND)),
         optionsPage(0),
         client(0),
-        mercurialVC(0),
-        projectExplorer(0),
-        changeLog(0)
+        changeLog(0),
+        m_menuAction(0)
 {
     m_instance = this;
 }
@@ -143,13 +136,12 @@ MercurialPlugin::~MercurialPlugin()
     m_instance = 0;
 }
 
-bool MercurialPlugin::initialize(const QStringList &arguments, QString *error_message)
+bool MercurialPlugin::initialize(const QStringList & /* arguments */, QString * /*error_message */)
 {
-    Q_UNUSED(arguments)
-    Q_UNUSED(error_message)
-
     typedef VCSBase::VCSEditorFactory<MercurialEditor> MercurialEditorFactory;
 
+    VCSBase::VCSBasePlugin::initialize(new MercurialControl(client));
+
     core = Core::ICore::instance();
     actionManager = core->actionManager();
 
@@ -160,9 +152,7 @@ bool MercurialPlugin::initialize(const QStringList &arguments, QString *error_me
     client = new MercurialClient();
     connect(optionsPage, SIGNAL(settingsChanged()), client, SLOT(settingsChanged()));
 
-    mercurialVC = new MercurialControl(client);
-    addAutoReleasedObject(mercurialVC);
-    connect(client, SIGNAL(changed(QVariant)), mercurialVC, SLOT(changed(QVariant)));
+    connect(client, SIGNAL(changed(QVariant)), versionControl(), SLOT(changed(QVariant)));
 
     static const char *describeSlot = SLOT(view(QString,QString));
     const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
@@ -173,8 +163,6 @@ bool MercurialPlugin::initialize(const QStringList &arguments, QString *error_me
 
     addAutoReleasedObject(new CloneWizard);
 
-    addAutoReleasedObject(new ListenForClose);
-
     createMenu();
 
     createSubmitEditorActions();
@@ -184,10 +172,6 @@ bool MercurialPlugin::initialize(const QStringList &arguments, QString *error_me
 
 void MercurialPlugin::extensionsInitialized()
 {
-    projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
-    if (projectExplorer)
-        connect(projectExplorer, SIGNAL(currentProjectChanged(ProjectExplorer::Project *)),
-                this, SLOT(currentProjectChanged(ProjectExplorer::Project *)));
 }
 
 const MercurialSettings &MercurialPlugin::settings() const
@@ -216,11 +200,6 @@ void MercurialPlugin::createMenu()
     QMenu *menu = mercurialContainer->menu();
     menu->setTitle(tr("Mercurial"));
 
-    if (QAction *visibleAction = menu->menuAction()) {
-        visibleAction->setEnabled(mercurialVC->isEnabled());
-        connect(mercurialVC, SIGNAL(enabledChanged(bool)), visibleAction, SLOT(setVisible(bool)));
-    }
-
     createFileActions(context);
     createSeparator(context, QLatin1String("FileDirSeperator"));
     createDirectoryActions(context);
@@ -234,11 +213,7 @@ void MercurialPlugin::createMenu()
     // Request the Tools menu and add the Mercurial menu to it
     Core::ActionContainer *toolsMenu = actionManager->actionContainer(QLatin1String(Core::Constants::M_TOOLS));
     toolsMenu->addMenu(mercurialContainer);
-
-    connect(core, SIGNAL(contextChanged(Core::IContext *)), this, SLOT(updateActions()));
-    connect(core->fileManager(), SIGNAL(currentFileChanged(const QString &)),
-            this, SLOT(updateActions()));
-
+    m_menuAction = mercurialContainer->menu()->menuAction();
 }
 
 void MercurialPlugin::createFileActions(const QList<int> &context)
@@ -281,30 +256,41 @@ void MercurialPlugin::createFileActions(const QList<int> &context)
 
 void MercurialPlugin::annotateCurrentFile()
 {
-    client->annotate(currentFile());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    client->annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void MercurialPlugin::diffCurrentFile()
 {
-    client->diff(currentFile());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    client->diff(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
 }
 
 void MercurialPlugin::logCurrentFile()
 {
-    client->log(currentFile());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    client->log(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
 }
 
 void MercurialPlugin::revertCurrentFile()
 {
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+
     RevertDialog reverter;
     if (reverter.exec() != QDialog::Accepted)
         return;
-    client->revert(currentFile(), reverter.revision());
+    client->revertFile(state.currentFileTopLevel(), state.relativeCurrentFile(), reverter.revision());
 }
 
 void MercurialPlugin::statusCurrentFile()
 {
-    client->status(currentFile());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    client->status(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void MercurialPlugin::createDirectoryActions(const QList<int> &context)
@@ -313,25 +299,25 @@ void MercurialPlugin::createDirectoryActions(const QList<int> &context)
     Core::Command *command;
 
     action = new QAction(tr("Diff"), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::DIFFMULTI), context);
     connect(action, SIGNAL(triggered()), this, SLOT(diffRepository()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Log"), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::LOGMULTI), context);
     connect(action, SIGNAL(triggered()), this, SLOT(logRepository()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Revert..."), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::REVERTMULTI), context);
     connect(action, SIGNAL(triggered()), this, SLOT(revertMulti()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Status"), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::STATUSMULTI), context);
     connect(action, SIGNAL(triggered()), this, SLOT(statusMulti()));
     mercurialContainer->addAction(command);
@@ -339,67 +325,77 @@ void MercurialPlugin::createDirectoryActions(const QList<int> &context)
 
 void MercurialPlugin::diffRepository()
 {
-    client->diff(currentProjectRoot());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    client->diff(state.topLevel());
 }
 
 void MercurialPlugin::logRepository()
 {
-    client->log(currentProjectRoot());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    client->log(state.topLevel());
 }
 
 void MercurialPlugin::revertMulti()
 {
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+
     RevertDialog reverter;
     if (reverter.exec() != QDialog::Accepted)
         return;
-    client->revert(currentProjectRoot(), reverter.revision());
+    client->revertRepository(state.topLevel(), reverter.revision());
 }
 
 void MercurialPlugin::statusMulti()
 {
-    client->status(currentProjectRoot());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+
+    client->status(state.topLevel());
 }
 
 void MercurialPlugin::createRepositoryActions(const QList<int> &context)
 {
     QAction *action = new QAction(tr("Pull..."), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     Core::Command *command = actionManager->registerAction(action, QLatin1String(Constants::PULL), context);
     connect(action, SIGNAL(triggered()), this, SLOT(pull()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Push..."), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::PUSH), context);
     connect(action, SIGNAL(triggered()), this, SLOT(push()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Update..."), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::UPDATE), context);
     connect(action, SIGNAL(triggered()), this, SLOT(update()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Import..."), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::IMPORT), context);
     connect(action, SIGNAL(triggered()), this, SLOT(import()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Incoming..."), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::INCOMING), context);
     connect(action, SIGNAL(triggered()), this, SLOT(incoming()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Outgoing..."), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::OUTGOING), context);
     connect(action, SIGNAL(triggered()), this, SLOT(outgoing()));
     mercurialContainer->addAction(command);
 
     action = new QAction(tr("Commit..."), this);
-    actionList.append(action);
+    m_repositoryActionList.append(action);
     command = actionManager->registerAction(action, QLatin1String(Constants::COMMIT), context);
     command->setDefaultKeySequence(QKeySequence(tr("Alt+H,Alt+C")));
     connect(action, SIGNAL(triggered()), this, SLOT(commit()));
@@ -408,35 +404,45 @@ void MercurialPlugin::createRepositoryActions(const QList<int> &context)
 
 void MercurialPlugin::pull()
 {
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+
     SrcDestDialog dialog;
     dialog.setWindowTitle(tr("Pull Source"));
     if (dialog.exec() != QDialog::Accepted)
         return;
-    QString repository = dialog.getRepositoryString();
-    client->pull(currentProjectRoot(), repository);
+    client->pull(state.topLevel(), dialog.getRepositoryString());
 }
 
 void MercurialPlugin::push()
 {
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+
     SrcDestDialog dialog;
     dialog.setWindowTitle(tr("Push Destination"));
     if (dialog.exec() != QDialog::Accepted)
         return;
-    QString repository = dialog.getRepositoryString();
-    client->push(currentProjectRoot(), repository);
+    client->push(state.topLevel(), dialog.getRepositoryString());
 }
 
 void MercurialPlugin::update()
 {
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+
     RevertDialog updateDialog;
     updateDialog.setWindowTitle(tr("Update"));
     if (updateDialog.exec() != QDialog::Accepted)
         return;
-    client->update(currentProjectRoot(), updateDialog.revision());
+    client->update(state.topLevel(), updateDialog.revision());
 }
 
 void MercurialPlugin::import()
 {
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+
     QFileDialog importDialog;
     importDialog.setFileMode(QFileDialog::ExistingFiles);
     importDialog.setViewMode(QFileDialog::Detail);
@@ -445,22 +451,26 @@ void MercurialPlugin::import()
         return;
 
     const QStringList fileNames = importDialog.selectedFiles();
-    client->import(currentProjectRoot(), fileNames);
+    client->import(state.topLevel(), fileNames);
 }
 
 void MercurialPlugin::incoming()
 {
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+
     SrcDestDialog dialog;
     dialog.setWindowTitle(tr("Incoming Source"));
     if (dialog.exec() != QDialog::Accepted)
         return;
-    QString repository = dialog.getRepositoryString();
-    client->incoming(currentProjectRoot(), repository);
+    client->incoming(state.topLevel(), dialog.getRepositoryString());
 }
 
 void MercurialPlugin::outgoing()
 {
-    client->outgoing(currentProjectRoot());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    client->outgoing(state.topLevel());
 }
 
 void MercurialPlugin::createSubmitEditorActions()
@@ -487,9 +497,14 @@ void MercurialPlugin::commit()
     if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
         return;
 
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+
+    m_submitRepository = state.topLevel();
+
     connect(client, SIGNAL(parsedStatus(QList<QPair<QString,QString> >)),
             this, SLOT(showCommitWidget(QList<QPair<QString,QString> >)));
-    client->statusWithSignal(currentProjectRoot());
+    client->statusWithSignal(m_submitRepository);
 }
 
 void MercurialPlugin::showCommitWidget(const QList<QPair<QString, QString> > &status)
@@ -528,25 +543,23 @@ void MercurialPlugin::showCommitWidget(const QList<QPair<QString, QString> > &st
         outputWindow->appendError(tr("Unable to create a commit editor."));
         return;
     }
-    const QString msg = tr("Commit changes for \"%1\".").arg(currentProjectName());
+
+    const QString msg = tr("Commit changes for \"%1\".").arg(m_submitRepository);
     commitEditor->setDisplayName(msg);
 
-    QString branch = client->branchQuerySync(currentProjectRoot());
+    QString branch = client->branchQuerySync(m_submitRepository);
 
-    commitEditor->setFields(currentProjectRoot(), branch, mercurialSettings.userName(),
+    commitEditor->setFields(m_submitRepository, branch, mercurialSettings.userName(),
                             mercurialSettings.email(), status);
 
     commitEditor->registerActions(editorUndo, editorRedo, editorCommit, editorDiff);
-    connect(commitEditor, SIGNAL(diffSelectedFiles(const QStringList &)),
-            this, SLOT(diffFromEditorSelected(const QStringList &)));
+    connect(commitEditor, SIGNAL(diffSelectedFiles(QStringList)),
+            this, SLOT(diffFromEditorSelected(QStringList)));
 }
 
 void MercurialPlugin::diffFromEditorSelected(const QStringList &files)
 {
-    foreach (const QString &file, files) {
-        const QFileInfo toDiff(QDir(currentProjectRoot().absoluteFilePath()).absoluteFilePath(file));
-        client->diff(toDiff);
-    }
+    client->diff(m_submitRepository, files);
 }
 
 void MercurialPlugin::commitFromEditor()
@@ -558,12 +571,12 @@ void MercurialPlugin::commitFromEditor()
     core->editorManager()->closeEditors(core->editorManager()->editorsForFileName(changeLog->fileName()));
 }
 
-bool MercurialPlugin::closeEditor(Core::IEditor *editor)
+bool MercurialPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor)
 {
-    if (!changeLog || !editor || qstrcmp(editor->kind(), Constants::COMMITKIND))
+    if (!changeLog)
         return true;
-    Core::IFile *editorFile = editor->file();
-    CommitEditor *commitEditor = qobject_cast<CommitEditor *>(editor);
+    Core::IFile *editorFile = submitEditor->file();
+    CommitEditor *commitEditor = qobject_cast<CommitEditor *>(submitEditor);
     if (!editorFile || !commitEditor)
         return true;
 
@@ -590,8 +603,7 @@ bool MercurialPlugin::closeEditor(Core::IEditor *editor)
         editorFile->save();
         core->fileManager()->unblockFileChange(editorFile);
 
-        const QFileInfo repoRoot(commitEditor->repoRoot());
-        client->commit(repoRoot, files, commitEditor->committerInfo(),
+        client->commit(commitEditor->repoRoot(), files, commitEditor->committerInfo(),
                        editorFile->fileName());
     }
     return true;
@@ -601,6 +613,7 @@ void MercurialPlugin::deleteCommitLog()
     if (changeLog) {
         delete changeLog;
         changeLog = 0;
+        m_submitRepository.clear();
     }
 }
 
@@ -630,68 +643,28 @@ void MercurialPlugin::createSeparator(const QList<int> &context, const QString &
     mercurialContainer->addAction(actionManager->registerAction(action, id, context));
 }
 
-void MercurialPlugin::updateActions()
+void MercurialPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
 {
-    const QFileInfo  file = currentFile();
-    const QString filename = file.fileName();
-    const QString repoRoot = client->findTopLevelForFile(file);
-    bool enable = false;
+    if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction))
+        return;
+
+    const QString filename = currentState().currentFileName();
+    const bool fileEnabled = !filename.isEmpty();
+    const bool repoEnabled = currentState().hasTopLevel();
 
-    //File menu Items should only be enabled for files that are below a mercurial repository
-    enable = !repoRoot.isEmpty();
     annotateFile->setParameter(filename);
-    annotateFile->setEnabled(enable);
+    annotateFile->setEnabled(fileEnabled);
     diffFile->setParameter(filename);
-    diffFile->setEnabled(enable);
+    diffFile->setEnabled(fileEnabled);
     logFile->setParameter(filename);
-    logFile->setEnabled(enable);
+    logFile->setEnabled(fileEnabled);
     revertFile->setParameter(filename);
-    revertFile->setEnabled(enable);
+    revertFile->setEnabled(fileEnabled);
     statusFile->setParameter(filename);
-    statusFile->setEnabled(enable);
-
-    //repository actions
-    if (projectMapper.contains(currentProjectName()))
-        enable = true;
-    else
-        enable = false;
-
-    foreach (QAction *action, actionList)
-        action->setEnabled(enable);
-}
-
-QFileInfo MercurialPlugin::currentFile()
-{
-    QString fileName = core->fileManager()->currentFile();
-    QFileInfo fileInfo(fileName);
-    return fileInfo;
-}
-
-QString MercurialPlugin::currentProjectName()
-{
-    if (projectExplorer)
-        if (projectExplorer->currentProject())
-            return projectExplorer->currentProject()->name();
-    return QString();
-}
-
-void MercurialPlugin::currentProjectChanged(ProjectExplorer::Project *project)
-{
-    if (!project)
-        return;
+    statusFile->setEnabled(fileEnabled);
 
-    if (projectMapper.contains(project->name()))
-        return;
-
-    QString repoRoot = client->findTopLevelForFile(QFileInfo(project->file()->fileName()));
-
-    if (!repoRoot.isEmpty())
-        projectMapper.insert(project->name(), QFileInfo(repoRoot));
-}
-
-QFileInfo MercurialPlugin::currentProjectRoot()
-{
-    return projectMapper.value(currentProjectName());
+    foreach (QAction *repoAction, m_repositoryActionList)
+        repoAction->setEnabled(repoEnabled);
 }
 
 Q_EXPORT_PLUGIN(MercurialPlugin)
diff --git a/src/plugins/mercurial/mercurialplugin.h b/src/plugins/mercurial/mercurialplugin.h
index fa3318d38ac..c11d5590a07 100644
--- a/src/plugins/mercurial/mercurialplugin.h
+++ b/src/plugins/mercurial/mercurialplugin.h
@@ -32,8 +32,7 @@
 
 #include "mercurialsettings.h"
 
-#include <extensionsystem/iplugin.h>
-#include <coreplugin/icorelistener.h>
+#include <vcsbase/vcsbaseplugin.h>
 
 #include <QtCore/QFileInfo>
 #include <QtCore/QHash>
@@ -57,9 +56,8 @@ namespace Utils {
 class ParameterAction;
 } //namespace Utils
 
-namespace ProjectExplorer {
-class ProjectExplorerPlugin;
-class Project;
+namespace VCSBase {
+class VCSBaseSubmitEditor;
 }
 
 namespace Mercurial {
@@ -71,7 +69,7 @@ class MercurialControl;
 class MercurialEditor;
 class MercurialSettings;
 
-class MercurialPlugin : public ExtensionSystem::IPlugin
+class MercurialPlugin : public VCSBase::VCSBasePlugin
 {
     Q_OBJECT
 
@@ -81,10 +79,7 @@ public:
     bool initialize(const QStringList &arguments, QString *error_message);
     void extensionsInitialized();
     static MercurialPlugin *instance() { return m_instance; }
-    QFileInfo currentFile();
-    QString currentProjectName();
-    QFileInfo currentProjectRoot();
-    bool closeEditor(Core::IEditor *editor);
+
     QStringList standardArguments() const;
 
     const MercurialSettings &settings() const;
@@ -130,10 +125,9 @@ private slots:
     void init();
     void serve();*/
 
-    //change the sates of the actions in the Mercurial Menu i.e. 2 be context sensitive
-    void updateActions();
-    void currentProjectChanged(ProjectExplorer::Project *project);
-
+protected:
+    virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
+    virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor);
 
 private:
     //methods
@@ -153,15 +147,11 @@ private:
     OptionsPage *optionsPage;
     MercurialClient *client;
 
-    MercurialControl *mercurialVC;
     Core::ICore *core;
     Core::ActionManager *actionManager;
     Core::ActionContainer *mercurialContainer;
-    ProjectExplorer::ProjectExplorerPlugin *projectExplorer;
 
-    //provide a mapping of projectName -> repositoryRoot for each project
-    QHash<QString, QFileInfo> projectMapper;
-    QList<QAction *> actionList;
+    QList<QAction *> m_repositoryActionList;
     QTemporaryFile *changeLog;
 
     //Menu Items (file actions)
@@ -177,14 +167,9 @@ private:
     QAction *editorDiff;
     QAction *editorUndo;
     QAction *editorRedo;
-};
+    QAction *m_menuAction;
 
-class ListenForClose : public Core::ICoreListener
-{
-    Q_OBJECT
-public:
-    ListenForClose(QObject *parent=0) : Core::ICoreListener(parent) {}
-    bool editorAboutToClose(Core::IEditor *editor);
+    QString m_submitRepository;
 };
 
 } //namespace Internal
-- 
GitLab