Commit 402cf0e3 authored by Waqar Ahmed's avatar Waqar Ahmed Committed by Christoph Cullmann
Browse files

Allow cancelling git operations

- Only git push / pull for now
- Make sure we kill a running push / pull on destruction properly
parent 93232787
......@@ -127,6 +127,18 @@ public:
}
};
static QToolButton *toolButton(const QString &icon, const QString &tooltip, const QString &text = QString(), Qt::ToolButtonStyle t = Qt::ToolButtonIconOnly)
{
auto tb = new QToolButton;
tb->setIcon(QIcon::fromTheme(icon));
tb->setToolTip(tooltip);
tb->setText(text);
tb->setAutoRaise(true);
tb->setToolButtonStyle(t);
tb->setSizePolicy(QSizePolicy::Minimum, tb->sizePolicy().verticalPolicy());
return tb;
}
GitWidget::GitWidget(KateProject *project, KTextEditor::MainWindow *mainWindow, KateProjectPluginView *pluginView)
: m_project(project)
, m_mainWin(mainWindow)
......@@ -137,9 +149,7 @@ GitWidget::GitWidget(KateProject *project, KTextEditor::MainWindow *mainWindow,
m_treeView = new GitWidgetTreeView(this);
buildMenu();
m_menuBtn = new QToolButton;
m_menuBtn->setIcon(QIcon::fromTheme(QStringLiteral("application-menu")));
m_menuBtn->setAutoRaise(true);
m_menuBtn = toolButton(QStringLiteral("application-menu"), QString());
m_menuBtn->setMenu(m_gitMenu);
m_menuBtn->setArrowType(Qt::NoArrow);
m_menuBtn->setStyleSheet(QStringLiteral("QToolButton::menu-indicator{ image: none; }"));
......@@ -147,35 +157,34 @@ GitWidget::GitWidget(KateProject *project, KTextEditor::MainWindow *mainWindow,
m_menuBtn->showMenu();
});
m_commitBtn = new QToolButton;
m_commitBtn->setText(i18n("Commit"));
m_commitBtn->setIcon(QIcon::fromTheme(QStringLiteral("svn-commit"))); // ":/kxmlgui5/kateproject/git-commit-dark.svg"
m_commitBtn->setAutoRaise(true);
m_commitBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
m_commitBtn->setSizePolicy(QSizePolicy::Minimum, m_commitBtn->sizePolicy().verticalPolicy());
m_pushBtn = new QToolButton;
m_pushBtn->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up")));
m_pushBtn->setToolTip(i18n("Git push"));
m_pushBtn->setAutoRaise(true);
m_pushBtn->setSizePolicy(QSizePolicy::Minimum, m_commitBtn->sizePolicy().verticalPolicy());
m_commitBtn = toolButton(QStringLiteral("svn-commit"), QString(), i18n("Commit"), Qt::ToolButtonTextBesideIcon);
m_pushBtn = toolButton(QStringLiteral("arrow-up"), i18n("Git push"));
connect(m_pushBtn, &QToolButton::clicked, this, [this]() {
PushPullDialog ppd(m_mainWin->window(), m_gitPath);
connect(&ppd, &PushPullDialog::runGitCommand, this, &GitWidget::runPushPullCmd);
ppd.openDialog(PushPullDialog::Push);
});
m_pullBtn = new QToolButton;
m_pullBtn->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
m_pullBtn->setToolTip(i18n("Git pull"));
m_pullBtn->setAutoRaise(true);
m_pullBtn->setSizePolicy(QSizePolicy::Minimum, m_commitBtn->sizePolicy().verticalPolicy());
m_pullBtn = toolButton(QStringLiteral("arrow-down"), i18n("Git pull"));
connect(m_pullBtn, &QToolButton::clicked, this, [this]() {
PushPullDialog ppd(m_mainWin->window(), m_gitPath);
connect(&ppd, &PushPullDialog::runGitCommand, this, &GitWidget::runPushPullCmd);
ppd.openDialog(PushPullDialog::Pull);
});
m_cancelBtn = toolButton(QStringLiteral("dialog-cancel"), i18n("Cancel Operation"));
m_cancelBtn->setHidden(true);
connect(m_cancelBtn, &QToolButton::clicked, this, [this] {
if (m_cancelHandle.proc) {
// we don't want error occurred, this is intentional
disconnect(m_cancelHandle.proc, &QProcess::errorOccurred, nullptr, nullptr);
m_cancelHandle.proc->kill();
sendMessage(m_cancelHandle.cmd + i18n(" canceled."), false);
hideCancel();
}
});
QVBoxLayout *layout = new QVBoxLayout;
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
......@@ -183,10 +192,9 @@ GitWidget::GitWidget(KateProject *project, KTextEditor::MainWindow *mainWindow,
QHBoxLayout *btnsLayout = new QHBoxLayout;
btnsLayout->setContentsMargins(0, 0, 0, 0);
btnsLayout->addWidget(m_commitBtn);
btnsLayout->addWidget(m_pushBtn);
btnsLayout->addWidget(m_pullBtn);
btnsLayout->addWidget(m_menuBtn);
for (auto *btn : {m_commitBtn, m_cancelBtn, m_pushBtn, m_pullBtn, m_menuBtn}) {
btnsLayout->addWidget(btn);
}
btnsLayout->setStretch(0, 1);
layout->addLayout(btnsLayout);
......@@ -221,6 +229,13 @@ GitWidget::GitWidget(KateProject *project, KTextEditor::MainWindow *mainWindow,
connect(m_treeView, &QTreeView::doubleClicked, this, &GitWidget::treeViewDoubleClicked);
}
GitWidget::~GitWidget()
{
if (m_cancelHandle.proc) {
m_cancelHandle.proc->kill();
}
}
void GitWidget::setDotGitPath()
{
/* This call is intentionally blocking because we need git path for everything else */
......@@ -273,6 +288,10 @@ QProcess *GitWidget::gitp()
auto git = new QProcess(this);
git->setProgram(QStringLiteral("git"));
git->setWorkingDirectory(m_gitPath);
connect(git, &QProcess::errorOccurred, this, [this, git](QProcess::ProcessError) {
sendMessage(git->errorString(), true);
git->deleteLater();
});
return git;
}
......@@ -321,29 +340,34 @@ void GitWidget::runGitCmd(const QStringList &args, const QString &i18error)
void GitWidget::runPushPullCmd(const QStringList &args)
{
auto git = gitp();
git->setProcessChannelMode(QProcess::MergedChannels);
connect(git, &QProcess::finished, this, [this, args, git](int exitCode, QProcess::ExitStatus es) {
if (es != QProcess::NormalExit || exitCode != 0) {
sendMessage(i18n("git push error: %1", QString::fromUtf8(git->readAllStandardError())), true);
sendMessage(QStringLiteral("git ") + args.first() + i18n(" error: %1", QString::fromUtf8(git->readAll())), true);
} else {
auto gargs = args;
gargs.push_front(QStringLiteral("git"));
QString cmd = gargs.join(QStringLiteral(" "));
QString out = QString::fromUtf8(git->readAllStandardError() + git->readAllStandardOutput());
QString out = QString::fromUtf8(git->readAll());
sendMessage(i18n("\"%1\" executed successfully: %2", cmd, out), false);
getStatus();
}
hideCancel();
git->deleteLater();
});
enableCancel(git, args);
git->setArguments(args);
git->start(QProcess::ReadOnly);
// kill after 40 seconds
QTimer::singleShot(40000, this, [git, this] {
if (git->state() == QProcess::Running) {
sendMessage(i18n("Git operation failed. Killing..."), true);
sendMessage(i18n("Git operation timed-out. Killing..."), true);
git->kill();
git->deleteLater();
hideCancel();
}
});
}
......@@ -381,7 +405,6 @@ void GitWidget::discard(const QStringList &files)
// discard=>git checkout -q -- xx.cpp
auto args = QStringList{QStringLiteral("checkout"), QStringLiteral("-q"), QStringLiteral("--")};
args.append(files);
runGitCmd(args, i18n("Failed to discard changes. Error:"));
}
......@@ -393,7 +416,6 @@ void GitWidget::clean(const QStringList &files)
// discard=>git clean -q -f -- xx.cpp
auto args = QStringList{QStringLiteral("clean"), QStringLiteral("-q"), QStringLiteral("-f"), QStringLiteral("--")};
args.append(files);
runGitCmd(args, i18n("Failed to remove. Error:"));
}
......@@ -753,6 +775,19 @@ void GitWidget::createStashDialog(StashMode m, const QString &gitPath)
stashDialog->openDialog(m);
}
void GitWidget::enableCancel(QProcess *git, const QStringList &args)
{
m_cancelHandle = {git, QStringLiteral("git ") + args.join(QLatin1Char(' '))};
m_pushBtn->hide();
m_cancelBtn->show();
}
void GitWidget::hideCancel()
{
m_cancelBtn->hide();
m_pushBtn->show();
}
QMenu *GitWidget::stashMenu()
{
QMenu *menu = new QMenu(this);
......
......@@ -7,6 +7,7 @@
#define GITWIDGET_H
#include <QFutureWatcher>
#include <QPointer>
#include <QProcess>
#include <QWidget>
......@@ -40,6 +41,7 @@ class GitWidget : public QWidget
Q_OBJECT
public:
explicit GitWidget(KateProject *project, KTextEditor::MainWindow *mainWindow = nullptr, KateProjectPluginView *pluginView = nullptr);
~GitWidget();
bool eventFilter(QObject *o, QEvent *e) override;
void getStatus(bool untracked = true, bool submodules = false);
......@@ -57,6 +59,7 @@ private:
QToolButton *m_commitBtn;
QToolButton *m_pushBtn;
QToolButton *m_pullBtn;
QToolButton *m_cancelBtn;
GitWidgetTreeView *m_treeView;
GitStatusModel *m_model;
KateProject *m_project;
......@@ -69,6 +72,12 @@ private:
std::vector<TempFileViewPair> m_tempFiles;
KateProjectPluginView *m_pluginView;
struct CancelHandle {
QPointer<QProcess> proc;
QString cmd;
};
CancelHandle m_cancelHandle;
QProcess *gitp();
void buildMenu();
......@@ -94,6 +103,9 @@ private:
QString getDiff(KTextEditor::View *view, bool hunk, bool alreadyStaged);
void createStashDialog(StashMode m, const QString &gitPath);
void enableCancel(QProcess *git, const QStringList &args);
void hideCancel();
public Q_SLOTS:
void clearTempFile(KTextEditor::Document *document);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment