From e922cd234b4452906bf711938b6e6fd67d80b069 Mon Sep 17 00:00:00 2001
From: Hugues Delorme <delorme.hugues@fougsys.fr>
Date: Fri, 6 Dec 2013 14:56:24 +0100
Subject: [PATCH] Bzr: add support for "uncommit" command

All "bzr uncommit" options are supported, even --dry-run (allowing
user to check the green light)

Change-Id: Ib97ef1333709ad18be53c658c23c97356e4e4ce0
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@digia.com>
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
---
 src/plugins/bazaar/bazaar.pro         |   9 ++-
 src/plugins/bazaar/bazaarclient.cpp   |  19 +++++
 src/plugins/bazaar/bazaarclient.h     |   3 +
 src/plugins/bazaar/bazaarplugin.cpp   |  18 +++++
 src/plugins/bazaar/bazaarplugin.h     |   1 +
 src/plugins/bazaar/constants.h        |   1 +
 src/plugins/bazaar/uncommitdialog.cpp |  83 ++++++++++++++++++++
 src/plugins/bazaar/uncommitdialog.h   |  62 +++++++++++++++
 src/plugins/bazaar/uncommitdialog.ui  | 104 ++++++++++++++++++++++++++
 9 files changed, 297 insertions(+), 3 deletions(-)
 create mode 100644 src/plugins/bazaar/uncommitdialog.cpp
 create mode 100644 src/plugins/bazaar/uncommitdialog.h
 create mode 100644 src/plugins/bazaar/uncommitdialog.ui

diff --git a/src/plugins/bazaar/bazaar.pro b/src/plugins/bazaar/bazaar.pro
index 06259346df0..f3a266221b4 100644
--- a/src/plugins/bazaar/bazaar.pro
+++ b/src/plugins/bazaar/bazaar.pro
@@ -13,7 +13,8 @@ SOURCES += \
     branchinfo.cpp \
     clonewizardpage.cpp \
     clonewizard.cpp \
-    cloneoptionspanel.cpp
+    cloneoptionspanel.cpp \
+    uncommitdialog.cpp
 HEADERS += \
     bazaarclient.h \
     constants.h \
@@ -29,11 +30,13 @@ HEADERS += \
     branchinfo.h \
     clonewizard.h \
     clonewizardpage.h \
-    cloneoptionspanel.h
+    cloneoptionspanel.h \
+    uncommitdialog.h
 FORMS += \
     optionspage.ui \
     revertdialog.ui \
     bazaarcommitpanel.ui \
     pullorpushdialog.ui \
-    cloneoptionspanel.ui
+    cloneoptionspanel.ui \
+    uncommitdialog.ui
 RESOURCES += bazaar.qrc
diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp
index 5df1804457b..ffc210be864 100644
--- a/src/plugins/bazaar/bazaarclient.cpp
+++ b/src/plugins/bazaar/bazaarclient.cpp
@@ -30,6 +30,7 @@
 #include "constants.h"
 
 #include <vcsbase/vcsbaseplugin.h>
+#include <vcsbase/vcsbaseoutputwindow.h>
 #include <vcsbase/vcsbaseeditorparameterwidget.h>
 #include <utils/synchronousprocess.h>
 
@@ -102,6 +103,24 @@ BranchInfo BazaarClient::synchronousBranchQuery(const QString &repositoryRoot) c
     return BranchInfo(repositoryRoot, false);
 }
 
+//! Removes the last committed revision(s)
+bool BazaarClient::synchronousUncommit(const QString &workingDir,
+                                       const QString &revision,
+                                       const QStringList &extraOptions)
+{
+    QStringList args;
+    args << QLatin1String("uncommit")
+         << QLatin1String("--force")   // Say yes to all questions
+         << QLatin1String("--verbose") // Will print out what is being removed
+         << revisionSpec(revision)
+         << extraOptions;
+    QByteArray stdOut;
+    const bool success = vcsFullySynchronousExec(workingDir, args, &stdOut);
+    if (!stdOut.isEmpty())
+        VcsBase::VcsBaseOutputWindow::instance()->append(QString::fromUtf8(stdOut));
+    return success;
+}
+
 void BazaarClient::commit(const QString &repositoryRoot, const QStringList &files,
                           const QString &commitMessageFile, const QStringList &extraOptions)
 {
diff --git a/src/plugins/bazaar/bazaarclient.h b/src/plugins/bazaar/bazaarclient.h
index 3dc756ef586..df42d899fa8 100644
--- a/src/plugins/bazaar/bazaarclient.h
+++ b/src/plugins/bazaar/bazaarclient.h
@@ -49,6 +49,9 @@ public:
 
     bool synchronousSetUserId();
     BranchInfo synchronousBranchQuery(const QString &repositoryRoot) const;
+    bool synchronousUncommit(const QString &workingDir,
+                             const QString& revision = QString(),
+                             const QStringList &extraOptions = QStringList());
     void commit(const QString &repositoryRoot, const QStringList &files,
                 const QString &commitMessageFile, const QStringList &extraOptions = QStringList());
     void annotate(const QString &workingDir, const QString &file,
diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp
index 47045f8eb62..1ca6863a851 100644
--- a/src/plugins/bazaar/bazaarplugin.cpp
+++ b/src/plugins/bazaar/bazaarplugin.cpp
@@ -34,6 +34,7 @@
 #include "bazaarcommitwidget.h"
 #include "bazaareditor.h"
 #include "pullorpushdialog.h"
+#include "uncommitdialog.h"
 #include "commiteditor.h"
 #include "clonewizard.h"
 
@@ -421,6 +422,13 @@ void BazaarPlugin::createRepositoryActions(const Core::Context &context)
     m_bazaarContainer->addAction(command);
     m_commandLocator->appendCommand(command);
 
+    action = new QAction(tr("Uncommit..."), this);
+    m_repositoryActionList.append(action);
+    command = Core::ActionManager::registerAction(action, Core::Id(Constants::UNCOMMIT), context);
+    connect(action, SIGNAL(triggered()), this, SLOT(uncommit()));
+    m_bazaarContainer->addAction(command);
+    m_commandLocator->appendCommand(command);
+
     QAction *createRepositoryAction = new QAction(tr("Create Repository..."), this);
     command = Core::ActionManager::registerAction(createRepositoryAction, Core::Id(Constants::CREATE_REPOSITORY), context);
     connect(createRepositoryAction, SIGNAL(triggered()), this, SLOT(createRepository()));
@@ -640,6 +648,16 @@ void BazaarPlugin::commitFromEditor()
     Core::EditorManager::closeEditor();
 }
 
+void BazaarPlugin::uncommit()
+{
+    const VcsBase::VcsBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return);
+
+    UnCommitDialog dialog;
+    if (dialog.exec() == QDialog::Accepted)
+        m_client->synchronousUncommit(state.topLevel(), dialog.revision(), dialog.extraOptions());
+}
+
 bool BazaarPlugin::submitEditorAboutToClose()
 {
     CommitEditor *commitEditor = qobject_cast<CommitEditor *>(submitEditor());
diff --git a/src/plugins/bazaar/bazaarplugin.h b/src/plugins/bazaar/bazaarplugin.h
index ed93dd221fe..7f9c85abab0 100644
--- a/src/plugins/bazaar/bazaarplugin.h
+++ b/src/plugins/bazaar/bazaarplugin.h
@@ -106,6 +106,7 @@ private slots:
     void commit();
     void showCommitWidget(const QList<VcsBase::VcsBaseClient::StatusItem> &status);
     void commitFromEditor();
+    void uncommit();
     void diffFromEditorSelected(const QStringList &files);
 #ifdef WITH_TESTS
     void testDiffFileResolving_data();
diff --git a/src/plugins/bazaar/constants.h b/src/plugins/bazaar/constants.h
index c81427eba0a..7143e1280cd 100644
--- a/src/plugins/bazaar/constants.h
+++ b/src/plugins/bazaar/constants.h
@@ -87,6 +87,7 @@ const char PULL[] = "Bazaar.Action.Pull";
 const char PUSH[] = "Bazaar.Action.Push";
 const char UPDATE[] = "Bazaar.Action.Update";
 const char COMMIT[] = "Bazaar.Action.Commit";
+const char UNCOMMIT[] = "Bazaar.Action.UnCommit";
 const char CREATE_REPOSITORY[] = "Bazaar.Action.CreateRepository";
 
 // Submit editor actions
diff --git a/src/plugins/bazaar/uncommitdialog.cpp b/src/plugins/bazaar/uncommitdialog.cpp
new file mode 100644
index 00000000000..30c7c754516
--- /dev/null
+++ b/src/plugins/bazaar/uncommitdialog.cpp
@@ -0,0 +1,83 @@
+/**************************************************************************
+**
+** Copyright (c) 2013 Hugues Delorme
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+#include "uncommitdialog.h"
+
+#include "ui_uncommitdialog.h"
+#include "bazaarclient.h"
+#include "bazaarplugin.h"
+#include <utils/qtcassert.h>
+
+#include <QPushButton>
+
+namespace Bazaar {
+namespace Internal {
+
+UnCommitDialog::UnCommitDialog(QWidget *parent)
+    : QDialog(parent),
+      m_ui(new Ui::UnCommitDialog)
+{
+    m_ui->setupUi(this);
+
+    QPushButton* dryRunBtn = new QPushButton(tr("Dry Run"));
+    dryRunBtn->setToolTip(tr("Test the outcome of removing the last committed revision, without actually removing anything."));
+    m_ui->buttonBox->addButton(dryRunBtn, QDialogButtonBox::ApplyRole);
+    connect(dryRunBtn, SIGNAL(clicked()), this, SLOT(dryRun()));
+}
+
+UnCommitDialog::~UnCommitDialog()
+{
+    delete m_ui;
+}
+
+QStringList UnCommitDialog::extraOptions() const
+{
+    QStringList opts;
+    if (m_ui->keepTagsCheckBox->isChecked())
+        opts += QLatin1String("--keep-tags");
+    if (m_ui->localCheckBox->isChecked())
+        opts += QLatin1String("--local");
+    return opts;
+}
+
+QString UnCommitDialog::revision() const
+{
+    return m_ui->revisionLineEdit->text().trimmed();
+}
+
+void UnCommitDialog::dryRun()
+{
+    BazaarPlugin* bzrPlugin = BazaarPlugin::instance();
+    QTC_ASSERT(bzrPlugin->currentState().hasTopLevel(), return);
+    bzrPlugin->client()->synchronousUncommit(bzrPlugin->currentState().topLevel(),
+                                             revision(),
+                                             extraOptions() << QLatin1String("--dry-run"));
+}
+
+} // namespace Internal
+} // namespace Bazaar
diff --git a/src/plugins/bazaar/uncommitdialog.h b/src/plugins/bazaar/uncommitdialog.h
new file mode 100644
index 00000000000..9a59db18c1e
--- /dev/null
+++ b/src/plugins/bazaar/uncommitdialog.h
@@ -0,0 +1,62 @@
+/**************************************************************************
+**
+** Copyright (c) 2013 Hugues Delorme
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+#ifndef UNCOMMITDIALOG_H
+#define UNCOMMITDIALOG_H
+
+#include <QDialog>
+
+namespace Bazaar {
+namespace Internal {
+
+namespace Ui {
+class UnCommitDialog;
+}
+
+class UnCommitDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit UnCommitDialog(QWidget *parent = 0);
+    ~UnCommitDialog();
+
+    QStringList extraOptions() const;
+    QString revision() const;
+
+private slots:
+    void dryRun();
+
+private:
+    Ui::UnCommitDialog *m_ui;
+};
+
+} // namespace Internal
+} // namespace Bazaar
+
+#endif // UNCOMMITDIALOG_H
diff --git a/src/plugins/bazaar/uncommitdialog.ui b/src/plugins/bazaar/uncommitdialog.ui
new file mode 100644
index 00000000000..f08a8c8a7a6
--- /dev/null
+++ b/src/plugins/bazaar/uncommitdialog.ui
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Bazaar::Internal::UnCommitDialog</class>
+ <widget class="QDialog" name="Bazaar::Internal::UnCommitDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>412</width>
+    <height>124</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Uncommit</string>
+  </property>
+  <layout class="QFormLayout" name="formLayout">
+   <item row="0" column="0" colspan="2">
+    <widget class="QCheckBox" name="keepTagsCheckBox">
+     <property name="toolTip">
+      <string/>
+     </property>
+     <property name="text">
+      <string>Keep tags that point to removed revisions</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="QCheckBox" name="localCheckBox">
+     <property name="text">
+      <string>Only remove the commits from the local branch when in a checkout</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QLabel" name="revisionLabel">
+     <property name="text">
+      <string>Revision:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="QLineEdit" name="revisionLineEdit">
+     <property name="toolTip">
+      <string>If a revision is specified, uncommits revisions to leave the branch at the specified revision.
+For example, &quot;Revision: 15&quot; will leave the branch at revision 15.</string>
+     </property>
+     <property name="placeholderText">
+      <string>Last committed</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+  <zorder>buttonBox</zorder>
+  <zorder>revisionLabel</zorder>
+  <zorder>revisionLineEdit</zorder>
+  <zorder>keepTagsCheckBox</zorder>
+  <zorder>localCheckBox</zorder>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>Bazaar::Internal::UnCommitDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>Bazaar::Internal::UnCommitDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
-- 
GitLab