From 834e06e7dcf2ff35ecf0e0baeef75f164bc1cea7 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Date: Fri, 3 Sep 2021 22:56:20 +0500 Subject: [PATCH] Git: Allow deleting branches Allow deleting branches from within kate. Much faster than manually git branch -D ... Support deleting local branches only. Signed-off-by: Waqar Ahmed --- addons/project/CMakeLists.txt | 1 + addons/project/branchdeletedialog.cpp | 84 +++++++++++++++++++++++++++ addons/project/branchdeletedialog.h | 18 ++++++ addons/project/git/gitutils.cpp | 16 +++++ addons/project/git/gitutils.h | 9 ++- addons/project/gitwidget.cpp | 10 ++++ 6 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 addons/project/branchdeletedialog.cpp create mode 100644 addons/project/branchdeletedialog.h diff --git a/addons/project/CMakeLists.txt b/addons/project/CMakeLists.txt index f00073bc9..7da6fe97a 100644 --- a/addons/project/CMakeLists.txt +++ b/addons/project/CMakeLists.txt @@ -72,6 +72,7 @@ target_sources( ${CMAKE_SOURCE_DIR}/shared/quickdialog.cpp pushpulldialog.cpp comparebranchesview.cpp + branchdeletedialog.cpp tools/kateprojectcodeanalysistoolcppcheck.cpp tools/kateprojectcodeanalysistoolflake8.cpp diff --git a/addons/project/branchdeletedialog.cpp b/addons/project/branchdeletedialog.cpp new file mode 100644 index 000000000..e51162685 --- /dev/null +++ b/addons/project/branchdeletedialog.cpp @@ -0,0 +1,84 @@ +#include "branchdeletedialog.h" + +#include "git/gitutils.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +BranchDeleteDialog::BranchDeleteDialog(const QString &dotGitPath, QWidget *parent) + : QDialog(parent) +{ + loadBranches(dotGitPath); + + auto l = new QVBoxLayout(this); + + l->addWidget(&m_listView); + + m_listView.setModel(&m_model); + + // setup the buttons + using Btns = QDialogButtonBox::StandardButton; + auto dlgBtns = new QDialogButtonBox(Btns::Cancel, Qt::Horizontal, this); + auto deleteBtn = new QPushButton(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete")); + dlgBtns->addButton(deleteBtn, QDialogButtonBox::DestructiveRole); + connect(dlgBtns, &QDialogButtonBox::clicked, this, [this, deleteBtn, dlgBtns](QAbstractButton *btn) { + if (btn == deleteBtn) { + auto count = branchesToDelete().count(); + QString ques = i18np("Are you sure you want to delete the selected branch?", "Are you sure you want to delete the selected branches?", count); + auto ret = KMessageBox::questionYesNo(this, ques, {}, KStandardGuiItem::yes(), KStandardGuiItem::no(), {}, KMessageBox::Dangerous); + if (ret == KMessageBox::Yes) { + accept(); + } else { + // do nothing + } + } else if (dlgBtns->button(QDialogButtonBox::Cancel) == btn) { + reject(); + } + }); + + connect(dlgBtns, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(dlgBtns, &QDialogButtonBox::rejected, this, &QDialog::reject); + + l->addWidget(dlgBtns); + + resize(500, 500); +} + +void BranchDeleteDialog::loadBranches(const QString &dotGitPath) +{ +#if KTEXTEDITOR_VERSION >= QT_VERSION_CHECK(5, 80, 0) + QFont f = KTextEditor::Editor::instance()->font(); +#else + QFont f = QFontDatabase::systemFont(QFontDatabase::FixedFont); +#endif + + static const auto branchIcon = QIcon::fromTheme(QStringLiteral("vcs-branch")); + const auto branches = GitUtils::getAllBranchesAndTags(dotGitPath, GitUtils::RefType::Head); + for (const auto &branch : branches) { + auto item = new QStandardItem(branchIcon, branch.name); + item->setFont(f); + item->setCheckable(true); + m_model.appendRow(item); + } +} + +QStringList BranchDeleteDialog::branchesToDelete() const +{ + QStringList branches; + int rowCount = m_model.rowCount(); + for (int i = 0; i < rowCount; ++i) { + auto item = m_model.item(i); + if (item->checkState() == Qt::Checked) { + branches << item->text(); + } + } + return branches; +} diff --git a/addons/project/branchdeletedialog.h b/addons/project/branchdeletedialog.h new file mode 100644 index 000000000..9c62bacc2 --- /dev/null +++ b/addons/project/branchdeletedialog.h @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +class BranchDeleteDialog : public QDialog +{ + Q_OBJECT +public: + BranchDeleteDialog(const QString &dotGitPath, QWidget *parent = nullptr); + QStringList branchesToDelete() const; + +private: + void loadBranches(const QString &dotGitPath); + void updateLabel(QStandardItem *item); + QStandardItemModel m_model; + QListView m_listView; +}; diff --git a/addons/project/git/gitutils.cpp b/addons/project/git/gitutils.cpp index 4e6d59889..ea8dd8823 100644 --- a/addons/project/git/gitutils.cpp +++ b/addons/project/git/gitutils.cpp @@ -190,3 +190,19 @@ std::pair GitUtils::getLastCommitMessage(const QString &repo) } return {}; } + +GitUtils::Result GitUtils::deleteBranches(const QStringList &branches, const QString &repo) +{ + QStringList args = {QStringLiteral("branch"), QStringLiteral("-D")}; + args << branches; + + QProcess git; + setupGitProcess(git, repo, args); + git.start(QProcess::ReadOnly); + if (git.waitForStarted() && git.waitForFinished(-1)) { + QString out = QString::fromLatin1(git.readAllStandardError()) + QString::fromLatin1(git.readAllStandardOutput()); + return {out, git.exitCode()}; + } + Q_UNREACHABLE(); + return {QString(), -1}; +} diff --git a/addons/project/git/gitutils.h b/addons/project/git/gitutils.h index a0e80c985..76e55814f 100644 --- a/addons/project/git/gitutils.h +++ b/addons/project/git/gitutils.h @@ -31,12 +31,15 @@ struct Branch { RefType type; }; -struct CheckoutResult { - QString branch; +struct Result { QString error; int returnCode; }; +struct CheckoutResult : public Result { + QString branch; +}; + struct StatusEntry { QString file; char x; @@ -85,6 +88,8 @@ QVector getAllBranches(const QString &repo); QVector getAllBranchesAndTags(const QString &repo, RefType ref = RefType::All); std::pair getLastCommitMessage(const QString &repo); + +Result deleteBranches(const QStringList &branches, const QString &repo); } Q_DECLARE_TYPEINFO(GitUtils::Branch, Q_MOVABLE_TYPE); diff --git a/addons/project/gitwidget.cpp b/addons/project/gitwidget.cpp index 12a2ae984..5a77c2b10 100644 --- a/addons/project/gitwidget.cpp +++ b/addons/project/gitwidget.cpp @@ -6,6 +6,7 @@ #include "gitwidget.h" #include "branchcheckoutdialog.h" +#include "branchdeletedialog.h" #include "branchesdialog.h" #include "comparebranchesview.h" #include "git/gitdiff.h" @@ -826,6 +827,15 @@ void GitWidget::buildMenu() }); a->setIcon(QIcon::fromTheme(QStringLiteral("vcs-branch"))); + a = m_gitMenu->addAction(i18n("Delete Branch"), this, [this] { + BranchDeleteDialog dlg(m_gitPath, this); + if (dlg.exec() == QDialog::Accepted) { + auto result = GitUtils::deleteBranches(dlg.branchesToDelete(), m_gitPath); + sendMessage(result.error, result.returnCode != 0); + } + }); + a->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); + a = m_gitMenu->addAction(i18n("Compare Branch with ..."), this, [this] { BranchesDialog bd(m_mainWin->window(), m_pluginView, m_project->baseDir()); using GitUtils::RefType; -- GitLab