From 9654df9f1f92ab2c1548c10ca614a6ab82783ac4 Mon Sep 17 00:00:00 2001
From: Andre Hartmann <aha_1980@gmx.de>
Date: Thu, 25 Apr 2013 13:04:45 +0200
Subject: [PATCH] Git: Allow direct push after commit

Git commit dialog: Added a drop-down menu to the commit button to
execute "git push" or open the "Push to Gerrit" dialog directly after
a commit or amend.

Task-number: QTCREATORBUG-8854
Change-Id: I00ff8f816d1768e0cdaf6929126b55826788e578
Reviewed-by: Petar Perisin <petar.perisin@gmail.com>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
---
 src/plugins/git/commitdata.cpp             |  5 ++-
 src/plugins/git/commitdata.h               |  8 +++++
 src/plugins/git/gerrit/gerritplugin.cpp    |  9 +++--
 src/plugins/git/gerrit/gerritplugin.h      |  1 +
 src/plugins/git/gitclient.cpp              |  2 ++
 src/plugins/git/gitplugin.cpp              | 13 ++++++++
 src/plugins/git/gitplugin.h                |  1 +
 src/plugins/git/gitsubmiteditorwidget.cpp  | 39 ++++++++++++++++++++++
 src/plugins/git/gitsubmiteditorwidget.h    |  6 ++++
 src/plugins/vcsbase/submiteditorwidget.cpp | 21 +++++++++---
 src/plugins/vcsbase/submiteditorwidget.h   |  1 +
 11 files changed, 97 insertions(+), 9 deletions(-)

diff --git a/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp
index d17cf89d1c8..129e256d9f7 100644
--- a/src/plugins/git/commitdata.cpp
+++ b/src/plugins/git/commitdata.cpp
@@ -53,6 +53,8 @@ void GitSubmitEditorPanelData::clear()
     author.clear();
     email.clear();
     bypassHooks = false;
+    pushAction = CommitOnly;
+    hasRemotes = false;
 }
 
 QString GitSubmitEditorPanelData::authorString() const
@@ -72,7 +74,8 @@ QString GitSubmitEditorPanelData::authorString() const
 QDebug operator<<(QDebug d, const GitSubmitEditorPanelData &data)
 {
     d.nospace() << " author:" << data.author << " email: " << data.email
-                << " bypass hooks: " << data.bypassHooks;
+                << " bypass hooks: " << data.bypassHooks
+                << " action after commit " << data.pushAction;
     return d;
 }
 
diff --git a/src/plugins/git/commitdata.h b/src/plugins/git/commitdata.h
index 6688843dd5d..824f9dfe5d6 100644
--- a/src/plugins/git/commitdata.h
+++ b/src/plugins/git/commitdata.h
@@ -52,6 +52,12 @@ struct GitSubmitEditorPanelInfo
 
 QDebug operator<<(QDebug d, const GitSubmitEditorPanelInfo &);
 
+enum PushAction {
+    CommitOnly,
+    CommitAndPush,
+    CommitAndPushToGerrit
+};
+
 struct GitSubmitEditorPanelData
 {
     void clear();
@@ -61,6 +67,8 @@ struct GitSubmitEditorPanelData
     QString author;
     QString email;
     bool bypassHooks;
+    PushAction pushAction;
+    bool hasRemotes;
 };
 
 QDebug operator<<(QDebug d, const GitSubmitEditorPanelData &);
diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp
index df424fb3683..75eefd32b1f 100644
--- a/src/plugins/git/gerrit/gerritplugin.cpp
+++ b/src/plugins/git/gerrit/gerritplugin.cpp
@@ -308,10 +308,8 @@ void GerritPlugin::addToLocator(Locator::CommandLocator *locator)
     locator->appendCommand(m_pushToGerritPair.second);
 }
 
-void GerritPlugin::push()
+void GerritPlugin::push(const QString &topLevel)
 {
-    const QString topLevel = Git::Internal::GitPlugin::instance()->currentState().topLevel();
-
     // QScopedPointer is required to delete the dialog when leaving the function
     GerritPushDialog dialog(topLevel, m_reviewers, ICore::mainWindow());
 
@@ -387,6 +385,11 @@ void GerritPlugin::openView()
     m_dialog.data()->raise();
 }
 
+void GerritPlugin::push()
+{
+    push(Git::Internal::GitPlugin::instance()->currentState().topLevel());
+}
+
 QString GerritPlugin::gitBinary()
 {
     bool ok;
diff --git a/src/plugins/git/gerrit/gerritplugin.h b/src/plugins/git/gerrit/gerritplugin.h
index 4eda51bd989..b2a6ef737ab 100644
--- a/src/plugins/git/gerrit/gerritplugin.h
+++ b/src/plugins/git/gerrit/gerritplugin.h
@@ -67,6 +67,7 @@ public:
     static QString gitBinary();
     static QString branch(const QString &repository);
     void addToLocator(Locator::CommandLocator *locator);
+    void push(const QString &topLevel);
 
 public slots:
     void fetchDisplay(const QSharedPointer<Gerrit::Internal::GerritChange> &change);
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index c952df8b1bf..124a0d63a45 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -3044,6 +3044,8 @@ bool GitClient::getCommitData(const QString &workingDirectory,
     case FixupCommit:
         break;
     }
+
+    commitData.panelData.hasRemotes = !synchronousRemotesList(repoDirectory).isEmpty();
     return true;
 }
 
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index bc730a339c9..72d9f4bb6db 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -1121,6 +1121,14 @@ bool GitPlugin::submitEditorAboutToClose()
             m_gitClient->continueCommandIfNeeded(m_submitRepository);
         }
     }
+
+    if (m_gitClient->checkCommandInProgress(m_submitRepository) == GitClient::NoCommand) {
+        if (editor->panelData().pushAction == CommitAndPush)
+            m_gitClient->push(m_submitRepository);
+        else if (editor->panelData().pushAction == CommitAndPushToGerrit)
+            connect(editor, SIGNAL(destroyed()), this, SLOT(delayedPushToGerrit()));
+    }
+
     return closeEditor;
 }
 
@@ -1445,6 +1453,11 @@ void GitPlugin::updateContinueAndAbortCommands()
     }
 }
 
+void GitPlugin::delayedPushToGerrit()
+{
+    m_gerritPlugin->push(m_submitRepository);
+}
+
 void GitPlugin::updateBranches(const QString &repository)
 {
     if (m_branchDialog && m_branchDialog->isVisible())
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
index 12b57600d9a..f451834f300 100644
--- a/src/plugins/git/gitplugin.h
+++ b/src/plugins/git/gitplugin.h
@@ -146,6 +146,7 @@ private slots:
     void startMergeTool();
     void continueOrAbortCommand();
     void updateContinueAndAbortCommands();
+    void delayedPushToGerrit();
 
 #ifdef WITH_TESTS
     void testStatusParsing_data();
diff --git a/src/plugins/git/gitsubmiteditorwidget.cpp b/src/plugins/git/gitsubmiteditorwidget.cpp
index 98dec3c9d3d..133e5583f07 100644
--- a/src/plugins/git/gitsubmiteditorwidget.cpp
+++ b/src/plugins/git/gitsubmiteditorwidget.cpp
@@ -39,6 +39,7 @@
 #include <QGroupBox>
 #include <QRegExp>
 #include <QVBoxLayout>
+#include <QMenu>
 
 namespace Git {
 namespace Internal {
@@ -46,6 +47,7 @@ namespace Internal {
 // ------------------
 GitSubmitEditorWidget::GitSubmitEditorWidget(QWidget *parent) :
     VcsBase::SubmitEditorWidget(parent),
+    m_pushAction(CommitOnly),
     m_gitSubmitPanel(new QWidget),
     m_logChangeWidget(0),
     m_hasUnmerged(false),
@@ -105,6 +107,14 @@ void GitSubmitEditorWidget::initialize(CommitType commitType,
     insertTopWidget(m_gitSubmitPanel);
     setPanelData(data);
     setPanelInfo(info);
+
+    if (data.hasRemotes && commitType != FixupCommit) {
+        QMenu *menu = new QMenu(this);
+        menu->addAction(tr("Commit only"), this, SLOT(commitOnlySlot()));
+        menu->addAction(tr("Commit and Push"), this, SLOT(commitAndPushSlot()));
+        menu->addAction(tr("Commit and Push to Gerrit"), this, SLOT(commitAndPushToGerritSlot()));
+        addSubmitButtonMenu(menu);
+    }
 }
 
 void GitSubmitEditorWidget::refreshLog(const QString &repository)
@@ -119,6 +129,7 @@ GitSubmitEditorPanelData GitSubmitEditorWidget::panelData() const
     rc.author = m_gitSubmitPanelUi.authorLineEdit->text();
     rc.email = m_gitSubmitPanelUi.emailLineEdit->text();
     rc.bypassHooks = m_gitSubmitPanelUi.bypassHooksCheckBox->isChecked();
+    rc.pushAction = m_pushAction;
     return rc;
 }
 
@@ -158,6 +169,16 @@ QString GitSubmitEditorWidget::cleanupDescription(const QString &input) const
 
 }
 
+QString GitSubmitEditorWidget::commitName() const
+{
+    if (m_pushAction == CommitAndPush)
+        return tr("Commit and Push");
+    else if (m_pushAction == CommitAndPushToGerrit)
+        return tr("Commit and Push to Gerrit");
+
+    return tr("Commit");
+}
+
 void GitSubmitEditorWidget::authorInformationChanged()
 {
     bool bothEmpty = m_gitSubmitPanelUi.authorLineEdit->text().isEmpty() &&
@@ -171,6 +192,24 @@ void GitSubmitEditorWidget::authorInformationChanged()
     updateSubmitAction();
 }
 
+void GitSubmitEditorWidget::commitOnlySlot()
+{
+    m_pushAction = CommitOnly;
+    updateSubmitAction();
+}
+
+void GitSubmitEditorWidget::commitAndPushSlot()
+{
+    m_pushAction = CommitAndPush;
+    updateSubmitAction();
+}
+
+void GitSubmitEditorWidget::commitAndPushToGerritSlot()
+{
+    m_pushAction = CommitAndPushToGerrit;
+    updateSubmitAction();
+}
+
 bool GitSubmitEditorWidget::emailIsValid() const
 {
     int pos = m_gitSubmitPanelUi.emailLineEdit->cursorPosition();
diff --git a/src/plugins/git/gitsubmiteditorwidget.h b/src/plugins/git/gitsubmiteditorwidget.h
index 61c9886444f..73043cdaf3f 100644
--- a/src/plugins/git/gitsubmiteditorwidget.h
+++ b/src/plugins/git/gitsubmiteditorwidget.h
@@ -32,6 +32,7 @@
 
 #include "ui_gitsubmitpanel.h"
 #include "gitsettings.h"
+#include "commitdata.h"
 
 #include <texteditor/syntaxhighlighter.h>
 #include <vcsbase/submiteditorwidget.h>
@@ -77,18 +78,23 @@ public:
 protected:
     bool canSubmit() const;
     QString cleanupDescription(const QString &) const;
+    QString commitName() const;
 
 signals:
     void show(const QString &commit);
 
 private slots:
     void authorInformationChanged();
+    void commitOnlySlot();
+    void commitAndPushSlot();
+    void commitAndPushToGerritSlot();
 
 private:
     bool emailIsValid() const;
     void setPanelData(const GitSubmitEditorPanelData &data);
     void setPanelInfo(const GitSubmitEditorPanelInfo &info);
 
+    PushAction m_pushAction;
     QWidget *m_gitSubmitPanel;
     LogChangeWidget *m_logChangeWidget;
     Ui::GitSubmitPanel m_gitSubmitPanelUi;
diff --git a/src/plugins/vcsbase/submiteditorwidget.cpp b/src/plugins/vcsbase/submiteditorwidget.cpp
index 192b9d5ccd7..473bb108627 100644
--- a/src/plugins/vcsbase/submiteditorwidget.cpp
+++ b/src/plugins/vcsbase/submiteditorwidget.cpp
@@ -37,7 +37,6 @@
 #include <QTimer>
 #include <QScopedPointer>
 
-#include <QPushButton>
 #include <QMenu>
 #include <QHBoxLayout>
 #include <QToolButton>
@@ -75,7 +74,7 @@ namespace VcsBase {
 
 // QActionPushButton: A push button tied to an action
 // (similar to a QToolButton)
-class QActionPushButton : public QPushButton
+class QActionPushButton : public QToolButton
 {
     Q_OBJECT
 public:
@@ -86,8 +85,11 @@ private slots:
 };
 
 QActionPushButton::QActionPushButton(QAction *a) :
-     QPushButton(a->icon(), a->text())
+     QToolButton()
 {
+    setIcon(a->icon());
+    setText(a->text());
+    setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
     connect(a, SIGNAL(changed()), this, SLOT(actionChanged()));
     connect(this, SIGNAL(clicked()), a, SLOT(trigger()));
     setEnabled(a->isEnabled());
@@ -153,6 +155,8 @@ struct SubmitEditorWidgetPrivate
     bool m_commitEnabled;
     bool m_ignoreChange;
     bool m_descriptionMandatory;
+
+    QActionPushButton *m_submitButton;
 };
 
 SubmitEditorWidgetPrivate::SubmitEditorWidgetPrivate() :
@@ -164,7 +168,8 @@ SubmitEditorWidgetPrivate::SubmitEditorWidgetPrivate() :
     m_lineWidth(defaultLineWidth),
     m_commitEnabled(false),
     m_ignoreChange(false),
-    m_descriptionMandatory(true)
+    m_descriptionMandatory(true),
+    m_submitButton(0)
 {
 }
 
@@ -229,7 +234,8 @@ void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *edi
         if (!actionSlotHelper)
             actionSlotHelper = new QActionSetTextSlotHelper(submitAction);
         connect(this, SIGNAL(submitActionTextChanged(QString)), actionSlotHelper, SLOT(setText(QString)));
-        d->m_ui.buttonLayout->addWidget(new QActionPushButton(submitAction));
+        d->m_submitButton = new QActionPushButton(submitAction);
+        d->m_ui.buttonLayout->addWidget(d->m_submitButton);
         if (!d->m_submitShortcut)
             d->m_submitShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this);
         connect(d->m_submitShortcut, SIGNAL(activated()), submitAction, SLOT(trigger()));
@@ -523,6 +529,11 @@ void SubmitEditorWidget::insertTopWidget(QWidget *w)
     d->m_ui.vboxLayout->insertWidget(0, w);
 }
 
+void SubmitEditorWidget::addSubmitButtonMenu(QMenu *menu)
+{
+    d->m_submitButton->setMenu(menu);
+}
+
 void SubmitEditorWidget::hideDescription()
 {
     d->m_ui.descriptionBox->hide();
diff --git a/src/plugins/vcsbase/submiteditorwidget.h b/src/plugins/vcsbase/submiteditorwidget.h
index 7860eb42c04..8cec7a0c5d1 100644
--- a/src/plugins/vcsbase/submiteditorwidget.h
+++ b/src/plugins/vcsbase/submiteditorwidget.h
@@ -121,6 +121,7 @@ protected:
     virtual QString cleanupDescription(const QString &) const;
     virtual QString commitName() const;
     void insertTopWidget(QWidget *w);
+    void addSubmitButtonMenu(QMenu *menu);
     void hideDescription();
 
 protected slots:
-- 
GitLab