From 751d7d043cb09dab2d37a0799c0b172de1aed6f6 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Fri, 19 Mar 2010 17:22:18 +0100
Subject: [PATCH] VCS: Add 'Annotate' context menu entry to build issues task
 window.

---
 src/plugins/coreplugin/iversioncontrol.h      |  8 +++-
 src/plugins/cvs/cvscontrol.cpp                |  7 +++
 src/plugins/cvs/cvscontrol.h                  |  1 +
 src/plugins/cvs/cvsplugin.cpp                 |  4 +-
 src/plugins/cvs/cvsplugin.h                   |  4 +-
 src/plugins/git/gitversioncontrol.cpp         | 10 ++++
 src/plugins/git/gitversioncontrol.h           |  2 +
 src/plugins/mercurial/mercurialcontrol.cpp    |  8 ++++
 src/plugins/mercurial/mercurialcontrol.h      |  1 +
 src/plugins/perforce/perforceplugin.cpp       |  4 +-
 src/plugins/perforce/perforceplugin.h         |  2 +-
 .../perforce/perforceversioncontrol.cpp       |  7 +++
 src/plugins/perforce/perforceversioncontrol.h |  1 +
 src/plugins/projectexplorer/taskwindow.cpp    | 47 ++++++++++++++-----
 src/plugins/projectexplorer/taskwindow.h      |  2 +
 src/plugins/subversion/subversioncontrol.cpp  |  8 ++++
 src/plugins/subversion/subversioncontrol.h    |  2 +
 src/plugins/subversion/subversionplugin.cpp   |  6 +--
 src/plugins/subversion/subversionplugin.h     |  6 ++-
 19 files changed, 107 insertions(+), 23 deletions(-)

diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h
index 4b3b7c4cc75..13b43a687ad 100644
--- a/src/plugins/coreplugin/iversioncontrol.h
+++ b/src/plugins/coreplugin/iversioncontrol.h
@@ -44,7 +44,8 @@ public:
     enum Operation {
         AddOperation, DeleteOperation, OpenOperation,
         CreateRepositoryOperation,
-        SnapshotOperations
+        SnapshotOperations,
+        AnnotateOperation
         };
 
     explicit IVersionControl(QObject *parent = 0) : QObject(parent) {}
@@ -126,6 +127,11 @@ public:
      */
     virtual bool vcsRemoveSnapshot(const QString &topLevel, const QString &name) = 0;
 
+    /*!
+     * Display annotation for a file and scroll to line
+     */
+    virtual bool vcsAnnotate(const QString &file, int line) = 0;
+
 signals:
     void repositoryChanged(const QString &repository);
     void filesChanged(const QStringList &files);
diff --git a/src/plugins/cvs/cvscontrol.cpp b/src/plugins/cvs/cvscontrol.cpp
index e2c559174b1..33e08c03a05 100644
--- a/src/plugins/cvs/cvscontrol.cpp
+++ b/src/plugins/cvs/cvscontrol.cpp
@@ -52,6 +52,7 @@ bool CVSControl::supportsOperation(Operation operation) const
     switch (operation) {
     case AddOperation:
     case DeleteOperation:
+    case AnnotateOperation:
         break;
     case OpenOperation:
     case CreateRepositoryOperation:
@@ -105,6 +106,12 @@ bool CVSControl::vcsRemoveSnapshot(const QString &, const QString &)
     return false;
 }
 
+bool CVSControl::vcsAnnotate(const QString &file, int line)
+{
+    m_plugin->vcsAnnotate(file, QString(), line);
+    return true;
+}
+
 bool CVSControl::managesDirectory(const QString &directory) const
 {
     return m_plugin->managesDirectory(directory);
diff --git a/src/plugins/cvs/cvscontrol.h b/src/plugins/cvs/cvscontrol.h
index 74bb1cda882..24483afed33 100644
--- a/src/plugins/cvs/cvscontrol.h
+++ b/src/plugins/cvs/cvscontrol.h
@@ -57,6 +57,7 @@ public:
     virtual QStringList vcsSnapshots(const QString &topLevel);
     virtual bool vcsRestoreSnapshot(const QString &topLevel, const QString &name);
     virtual bool vcsRemoveSnapshot(const QString &topLevel, const QString &name);
+    virtual bool vcsAnnotate(const QString &file, int line);
 
     void emitRepositoryChanged(const QString &s);
     void emitFilesChanged(const QStringList &l);
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index 78df829fcda..b45deb226f9 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -771,7 +771,7 @@ void CVSPlugin::annotateCurrentFile()
     annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
-void CVSPlugin::annotateVersion(const QString &file, const QString &revision, int lineNumber)
+void CVSPlugin::vcsAnnotate(const QString &file, const QString &revision, int lineNumber)
 {
     const QFileInfo fi(file);
     annotate(fi.absolutePath(), fi.fileName(), revision, lineNumber);
@@ -1072,7 +1072,7 @@ Core::IEditor * CVSPlugin::showOutputInEditor(const QString& title, const QStrin
     QString s = title;
     Core::IEditor *editor = Core::EditorManager::instance()->openEditorWithContents(id, &s, output.toLocal8Bit());
     connect(editor, SIGNAL(annotateRevisionRequested(QString,QString,int)),
-            this, SLOT(annotateVersion(QString,QString,int)));
+            this, SLOT(vcsAnnotate(QString,QString,int)));
     CVSEditor *e = qobject_cast<CVSEditor*>(editor->widget());
     if (!e)
         return 0;
diff --git a/src/plugins/cvs/cvsplugin.h b/src/plugins/cvs/cvsplugin.h
index 312a0858435..12a1ee674f3 100644
--- a/src/plugins/cvs/cvsplugin.h
+++ b/src/plugins/cvs/cvsplugin.h
@@ -101,6 +101,9 @@ public:
 
     static CVSPlugin *cvsPluginInstance();
 
+public slots:
+    void vcsAnnotate(const QString &file, const QString &revision /* = QString() */, int lineNumber);
+
 private slots:
     void addCurrentFile();
     void revertCurrentFile();
@@ -111,7 +114,6 @@ private slots:
     void startCommitCurrentFile();
     void filelogCurrentFile();
     void annotateCurrentFile();
-    void annotateVersion(const QString &file, const QString &revision, int lineNumber);
     void projectStatus();
     void slotDescribe(const QString &source, const QString &changeNr);
     void updateProject();
diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp
index 65308fb1748..07ff9521343 100644
--- a/src/plugins/git/gitversioncontrol.cpp
+++ b/src/plugins/git/gitversioncontrol.cpp
@@ -81,6 +81,9 @@ bool GitVersionControl::supportsOperation(Operation operation) const
     case SnapshotOperations:
         rc = true;
         break;
+    case AnnotateOperation:
+        rc = true;
+        break;
     }
     return rc;
 }
@@ -203,6 +206,13 @@ QString GitVersionControl::findTopLevelForDirectory(const QString &directory) co
     return GitClient::findRepositoryForDirectory(directory);
 }
 
+bool GitVersionControl::vcsAnnotate(const QString &file, int line)
+{
+    const QFileInfo fi(file);
+    gitClient()->blame(fi.absolutePath(), fi.fileName(), QString(), line);
+    return true;
+}
+
 void GitVersionControl::emitFilesChanged(const QStringList &l)
 {
     emit filesChanged(l);
diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h
index 44e65df84db..c53c1f2ab5c 100644
--- a/src/plugins/git/gitversioncontrol.h
+++ b/src/plugins/git/gitversioncontrol.h
@@ -59,6 +59,8 @@ public:
     virtual bool vcsRestoreSnapshot(const QString &topLevel, const QString &name);
     virtual bool vcsRemoveSnapshot(const QString &topLevel, const QString &name);
 
+    virtual bool vcsAnnotate(const QString &file, int line);
+
     void emitFilesChanged(const QStringList &);
     void emitRepositoryChanged(const QString &);
 
diff --git a/src/plugins/mercurial/mercurialcontrol.cpp b/src/plugins/mercurial/mercurialcontrol.cpp
index a0af2093104..1b707b9c8b7 100644
--- a/src/plugins/mercurial/mercurialcontrol.cpp
+++ b/src/plugins/mercurial/mercurialcontrol.cpp
@@ -66,6 +66,7 @@ bool MercurialControl::supportsOperation(Operation operation) const
     case Core::IVersionControl::AddOperation:
     case Core::IVersionControl::DeleteOperation:
     case Core::IVersionControl::CreateRepositoryOperation:
+    case Core::IVersionControl::AnnotateOperation:
         break;
     case Core::IVersionControl::OpenOperation:
     case Core::IVersionControl::SnapshotOperations:
@@ -118,6 +119,13 @@ bool MercurialControl::vcsRemoveSnapshot(const QString &, const QString &)
     return false;
 }
 
+bool MercurialControl::vcsAnnotate(const QString &file, int line)
+{
+    const QFileInfo fi(file);
+    mercurialClient->annotate(fi.absolutePath(), fi.fileName(), QString(), line);
+    return true;
+}
+
 bool MercurialControl::sccManaged(const QString &filename)
 {
     const QFileInfo fi(filename);
diff --git a/src/plugins/mercurial/mercurialcontrol.h b/src/plugins/mercurial/mercurialcontrol.h
index c82401bad89..b6ee396b1c7 100644
--- a/src/plugins/mercurial/mercurialcontrol.h
+++ b/src/plugins/mercurial/mercurialcontrol.h
@@ -62,6 +62,7 @@ public:
     bool vcsRestoreSnapshot(const QString &topLevel, const QString &name);
     bool vcsRemoveSnapshot(const QString &topLevel, const QString &name);
     bool sccManaged(const QString &filename);
+    virtual bool vcsAnnotate(const QString &file, int line);
 
 public slots:
     // To be connected to the HgTask's success signal to emit the repository/
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 287d9bcfe21..fe3cbb5a29a 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -723,7 +723,7 @@ void PerforcePlugin::annotate()
     }
 }
 
-void PerforcePlugin::annotateVersion(const QString &file, const QString &revision, int lineNumber)
+void PerforcePlugin::vcsAnnotate(const QString &file, const QString &revision, int lineNumber)
 {
     const QFileInfo fi(file);
     annotate(fi.absolutePath(), fi.fileName(), revision, lineNumber);
@@ -1175,7 +1175,7 @@ Core::IEditor * PerforcePlugin::showOutputInEditor(const QString& title, const Q
     QString s = title;
     Core::IEditor *editor = Core::EditorManager::instance()->openEditorWithContents(id, &s, output);
     connect(editor, SIGNAL(annotateRevisionRequested(QString,QString,int)),
-            this, SLOT(annotateVersion(QString,QString,int)));
+            this, SLOT(vcsAnnotate(QString,QString,int)));
     PerforceEditor *e = qobject_cast<PerforceEditor*>(editor->widget());
     if (!e)
         return 0;
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
index 2e62b5d5f95..7c88baef1a9 100644
--- a/src/plugins/perforce/perforceplugin.h
+++ b/src/plugins/perforce/perforceplugin.h
@@ -106,6 +106,7 @@ public:
 
 public slots:
     void describe(const QString &source, const QString &n);
+    void vcsAnnotate(const QString &file, const QString &revision /* = QString() */, int lineNumber);
 
 private slots:
     void openCurrentFile();
@@ -123,7 +124,6 @@ private slots:
     void describeChange();
     void annotateCurrentFile();
     void annotate();
-    void annotateVersion(const QString &file, const QString &revision, int lineNumber);
     void filelogCurrentFile();
     void filelog();
     void logProject();
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
index 69602d88113..ecd75e7bfdf 100644
--- a/src/plugins/perforce/perforceversioncontrol.cpp
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -54,6 +54,7 @@ bool PerforceVersionControl::supportsOperation(Operation operation) const
     case AddOperation:
     case DeleteOperation:
     case OpenOperation:
+    case AnnotateOperation:
         return true;
     case CreateRepositoryOperation:
     case SnapshotOperations:
@@ -105,6 +106,12 @@ bool PerforceVersionControl::vcsRemoveSnapshot(const QString &, const QString &)
     return false;
 }
 
+bool PerforceVersionControl::vcsAnnotate(const QString &file, int line)
+{
+    m_plugin->vcsAnnotate(file, QString(), line);
+    return true;
+}
+
 bool PerforceVersionControl::managesDirectory(const QString &directory) const
 {
     const bool rc = m_plugin->managesDirectory(directory);
diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h
index 063a3be77ce..5be2ac9826b 100644
--- a/src/plugins/perforce/perforceversioncontrol.h
+++ b/src/plugins/perforce/perforceversioncontrol.h
@@ -57,6 +57,7 @@ public:
     virtual QStringList vcsSnapshots(const QString &topLevel);
     virtual bool vcsRestoreSnapshot(const QString &topLevel, const QString &name);
     virtual bool vcsRemoveSnapshot(const QString &topLevel, const QString &name);
+    virtual bool vcsAnnotate(const QString &file, int line);
 
     void emitRepositoryChanged(const QString &s);
     void emitFilesChanged(const QStringList &l);
diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp
index 6b7a446e1f0..493c5039324 100644
--- a/src/plugins/projectexplorer/taskwindow.cpp
+++ b/src/plugins/projectexplorer/taskwindow.cpp
@@ -31,6 +31,8 @@
 
 #include <coreplugin/actionmanager/actionmanager.h>
 #include <coreplugin/coreconstants.h>
+#include <coreplugin/vcsmanager.h>
+#include <coreplugin/iversioncontrol.h>
 #include <coreplugin/editormanager/editormanager.h>
 #include <coreplugin/icore.h>
 #include <coreplugin/uniqueidmanager.h>
@@ -40,6 +42,7 @@
 
 #include <QtCore/QDir>
 #include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
 #include <QtGui/QApplication>
 #include <QtGui/QClipboard>
 #include <QtGui/QKeyEvent>
@@ -464,16 +467,21 @@ TaskWindow::TaskWindow()
     Core::Command *command = core->actionManager()->
             registerAction(m_copyAction, Core::Constants::COPY, m_taskWindowContext->context());
     m_listview->addAction(command->action());
+    connect(m_copyAction, SIGNAL(triggered()), SLOT(copy()));
 
-    connect(m_listview->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
-            tld, SLOT(currentChanged(const QModelIndex &, const QModelIndex &)));
+    m_vcsAnnotateAction = new QAction(tr("&Annotate"), this);
+    command = core->actionManager()->
+            registerAction(m_vcsAnnotateAction, QLatin1String("ProjectExplorer.Task.VCS_Annotate"), m_taskWindowContext->context());
+    m_listview->addAction(command->action());
+    connect(m_vcsAnnotateAction, SIGNAL(triggered()), SLOT(vcsAnnotate()));
 
-    connect(m_listview, SIGNAL(activated(const QModelIndex &)),
-            this, SLOT(showTaskInFile(const QModelIndex &)));
-    connect(m_listview, SIGNAL(clicked(const QModelIndex &)),
-            this, SLOT(showTaskInFile(const QModelIndex &)));
+    connect(m_listview->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+            tld, SLOT(currentChanged(QModelIndex,QModelIndex)));
 
-    connect(m_copyAction, SIGNAL(triggered()), SLOT(copy()));
+    connect(m_listview, SIGNAL(activated(QModelIndex)),
+            this, SLOT(showTaskInFile(QModelIndex)));
+    connect(m_listview, SIGNAL(clicked(QModelIndex)),
+            this, SLOT(showTaskInFile(QModelIndex)));
 
     m_filterWarningsButton = createFilterButton(Task::Warning,
                                                 tr("Show Warnings"), m_model,
@@ -563,12 +571,29 @@ void TaskWindow::showTaskInFile(const QModelIndex &index)
     m_listview->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
 }
 
+// Right-click VCS annotate: Find version control and point it to line
+void TaskWindow::vcsAnnotate()
+{
+    const QModelIndex index = m_listview->selectionModel()->currentIndex();
+    if (!index.isValid())
+        return;
+    const QString file = index.data(TaskModel::File).toString();
+    const int line = index.data(TaskModel::Line).toInt();
+    const QFileInfo fi(file);
+    if (fi.exists())
+        if (Core::IVersionControl *vc = Core::ICore::instance()->vcsManager()->findVersionControlForDirectory(fi.absolutePath()))
+            if (vc->supportsOperation(Core::IVersionControl::AnnotateOperation))
+                vc->vcsAnnotate(fi.absoluteFilePath(), line);
+}
+
 void TaskWindow::copy()
 {
-    QModelIndex index = m_listview->selectionModel()->currentIndex();
-    QString file = index.data(TaskModel::File).toString();
-    QString line = index.data(TaskModel::Line).toString();
-    QString description = index.data(TaskModel::Description).toString();
+    const QModelIndex index = m_listview->selectionModel()->currentIndex();
+    if (!index.isValid())
+        return;
+    const QString file = index.data(TaskModel::File).toString();
+    const QString line = index.data(TaskModel::Line).toString();
+    const QString description = index.data(TaskModel::Description).toString();
     QString type;
     switch (index.data(TaskModel::Type).toInt()) {
     case Task::Error:
diff --git a/src/plugins/projectexplorer/taskwindow.h b/src/plugins/projectexplorer/taskwindow.h
index 3592591f400..e2f02245933 100644
--- a/src/plugins/projectexplorer/taskwindow.h
+++ b/src/plugins/projectexplorer/taskwindow.h
@@ -119,6 +119,7 @@ signals:
 private slots:
     void showTaskInFile(const QModelIndex &index);
     void copy();
+    void vcsAnnotate();
     void setShowWarnings(bool);
     void updateCategoriesMenu();
     void filterCategoryTriggered(QAction *action);
@@ -132,6 +133,7 @@ private:
     Internal::TaskView *m_listview;
     Internal::TaskWindowContext *m_taskWindowContext;
     QAction *m_copyAction;
+    QAction *m_vcsAnnotateAction;
     QToolButton *m_filterWarningsButton;
     QToolButton *m_categoriesButton;
     QMenu *m_categoriesMenu;
diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp
index ef6a5677fc7..c58159ff60b 100644
--- a/src/plugins/subversion/subversioncontrol.cpp
+++ b/src/plugins/subversion/subversioncontrol.cpp
@@ -52,6 +52,7 @@ bool SubversionControl::supportsOperation(Operation operation) const
     switch (operation) {
     case AddOperation:
     case DeleteOperation:
+    case AnnotateOperation:
         break;
     case OpenOperation:
     case CreateRepositoryOperation:
@@ -115,6 +116,13 @@ QString SubversionControl::findTopLevelForDirectory(const QString &directory) co
     return m_plugin->findTopLevelForDirectory(directory);
 }
 
+bool SubversionControl::vcsAnnotate(const QString &file, int line)
+{
+    const QFileInfo fi(file);
+    m_plugin->vcsAnnotate(fi.absolutePath(), fi.fileName(), QString(), line);
+    return true;
+}
+
 void SubversionControl::emitRepositoryChanged(const QString &s)
 {
     emit repositoryChanged(s);
diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h
index 43e803ace9b..132aca4d8ec 100644
--- a/src/plugins/subversion/subversioncontrol.h
+++ b/src/plugins/subversion/subversioncontrol.h
@@ -59,6 +59,8 @@ public:
     virtual bool vcsRestoreSnapshot(const QString &topLevel, const QString &name);
     virtual bool vcsRemoveSnapshot(const QString &topLevel, const QString &name);
 
+    virtual bool vcsAnnotate(const QString &file, int line);
+
     void emitRepositoryChanged(const QString &);
     void emitFilesChanged(const QStringList &);
 
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index ee1a1169641..bcc249ef5f8 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -799,7 +799,7 @@ void SubversionPlugin::annotateCurrentFile()
 {
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasFile(), return);
-    annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
+    vcsAnnotate(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void SubversionPlugin::annotateVersion(const QString &file,
@@ -807,10 +807,10 @@ void SubversionPlugin::annotateVersion(const QString &file,
                                        int lineNr)
 {
     const QFileInfo fi(file);
-    annotate(fi.absolutePath(), fi.fileName(), revision, lineNr);
+    vcsAnnotate(fi.absolutePath(), fi.fileName(), revision, lineNr);
 }
 
-void SubversionPlugin::annotate(const QString &workingDir, const QString &file,
+void SubversionPlugin::vcsAnnotate(const QString &workingDir, const QString &file,
                                 const QString &revision /* = QString() */,
                                 int lineNumber /* = -1 */)
 {
diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h
index 9acf0926b2a..2a9283da2fa 100644
--- a/src/plugins/subversion/subversionplugin.h
+++ b/src/plugins/subversion/subversionplugin.h
@@ -100,6 +100,10 @@ public:
 
     static SubversionPlugin *subversionPluginInstance();
 
+public slots:
+    void vcsAnnotate(const QString &workingDir, const QString &file,
+                     const QString &revision = QString(), int lineNumber = -1);
+
 private slots:
     void addCurrentFile();
     void revertCurrentFile();
@@ -132,8 +136,6 @@ private:
     SubversionResponse runSvn(const QString &workingDir,
                               const QStringList &arguments, int timeOut,
                               bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0);
-    void annotate(const QString &workingDir, const QString &file,
-                  const QString &revision = QString(), int lineNumber = -1);
     void filelog(const QString &workingDir,
                  const QStringList &file = QStringList(),
                  bool enableAnnotationContextMenu = false);
-- 
GitLab