Commit 99adb22d authored by Waqar Ahmed's avatar Waqar Ahmed
Browse files

Refactor projectplugin quick-dialogs

parent a36dfd2f
......@@ -64,6 +64,7 @@ target_sources(
gitstatusmodel.cpp
gitcommitdialog.cpp
stashdialog.cpp
quickdialog.cpp
tools/kateprojectcodeanalysistoolcppcheck.cpp
tools/kateprojectcodeanalysistoolflake8.cpp
......
......@@ -152,56 +152,22 @@ private:
QString m_filterString;
};
BranchesDialog::BranchesDialog(QWidget *parent, KTextEditor::MainWindow *mainWindow, KateProjectPluginView *pluginView, QString projectPath)
: QMenu(parent)
, m_mainWindow(mainWindow)
BranchesDialog::BranchesDialog(QWidget *window, KateProjectPluginView *pluginView, QString projectPath)
: QuickDialog(window)
, m_pluginView(pluginView)
, m_projectPath(projectPath)
{
QVBoxLayout *layout = new QVBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(4, 4, 4, 4);
setLayout(layout);
m_lineEdit = new QLineEdit(this);
setFocusProxy(m_lineEdit);
layout->addWidget(m_lineEdit);
m_treeView = new QTreeView();
layout->addWidget(m_treeView, 1);
m_treeView->setTextElideMode(Qt::ElideLeft);
m_treeView->setUniformRowHeights(true);
m_model = new BranchesDialogModel(this);
StyleDelegate *delegate = new StyleDelegate(this);
m_treeView->setItemDelegateForColumn(0, delegate);
m_proxyModel = new BranchFilterModel(this);
m_proxyModel->setFilterRole(Qt::DisplayRole);
m_proxyModel->setSortRole(Qt::UserRole + 1);
connect(m_lineEdit, &QLineEdit::returnPressed, this, &BranchesDialog::slotReturnPressed);
connect(m_lineEdit, &QLineEdit::textChanged, m_proxyModel, &BranchFilterModel::setFilterString);
connect(m_lineEdit, &QLineEdit::textChanged, delegate, &StyleDelegate::setFilterString);
connect(m_lineEdit, &QLineEdit::textChanged, this, [this]() {
m_treeView->viewport()->update();
reselectFirst();
});
connect(m_treeView, &QTreeView::clicked, this, &BranchesDialog::slotReturnPressed);
m_proxyModel->setSourceModel(m_model);
m_treeView->setSortingEnabled(true);
m_treeView->setModel(m_proxyModel);
m_treeView.setModel(m_proxyModel);
m_treeView->installEventFilter(this);
m_lineEdit->installEventFilter(this);
auto delegate = new StyleDelegate(this);
m_treeView->setHeaderHidden(true);
m_treeView->setRootIsDecorated(false);
m_treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_treeView->setSelectionMode(QTreeView::SingleSelection);
connect(&m_lineEdit, &QLineEdit::textChanged, this, [this, delegate](const QString &s) {
m_proxyModel->setFilterString(s);
delegate->setFilterString(s);
});
connect(&m_checkoutWatcher, &QFutureWatcher<GitUtils::CheckoutResult>::finished, this, &BranchesDialog::onCheckoutDone);
}
......@@ -210,7 +176,7 @@ void BranchesDialog::resetValues()
{
m_checkoutBranchName.clear();
m_checkingOutFromBranch = false;
m_lineEdit->setPlaceholderText(i18n("Select branch to checkout. Press 'Esc' to cancel."));
m_lineEdit.setPlaceholderText(i18n("Select branch to checkout. Press 'Esc' to cancel."));
}
void BranchesDialog::openDialog()
......@@ -230,45 +196,6 @@ void BranchesDialog::openDialog()
exec();
}
bool BranchesDialog::eventFilter(QObject *obj, QEvent *event)
{
// catch key presses + shortcut overrides to allow to have ESC as application wide shortcut, too, see bug 409856
if (event->type() == QEvent::KeyPress || event->type() == QEvent::ShortcutOverride) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (obj == m_lineEdit) {
const bool forward2list = (keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down) || (keyEvent->key() == Qt::Key_PageUp)
|| (keyEvent->key() == Qt::Key_PageDown);
if (forward2list) {
QCoreApplication::sendEvent(m_treeView, event);
return true;
}
if (keyEvent->key() == Qt::Key_Escape) {
m_lineEdit->clear();
keyEvent->accept();
hide();
return true;
}
} else {
const bool forward2input = (keyEvent->key() != Qt::Key_Up) && (keyEvent->key() != Qt::Key_Down) && (keyEvent->key() != Qt::Key_PageUp)
&& (keyEvent->key() != Qt::Key_PageDown) && (keyEvent->key() != Qt::Key_Tab) && (keyEvent->key() != Qt::Key_Backtab);
if (forward2input) {
QCoreApplication::sendEvent(m_lineEdit, event);
return true;
}
}
}
// hide on focus out, if neither input field nor list have focus!
else if (event->type() == QEvent::FocusOut && !(m_lineEdit->hasFocus() || m_treeView->hasFocus())) {
m_lineEdit->clear();
hide();
return true;
}
return QWidget::eventFilter(obj, event);
}
void BranchesDialog::onCheckoutDone()
{
const GitUtils::CheckoutResult res = m_checkoutWatcher.result();
......@@ -278,7 +205,7 @@ void BranchesDialog::onCheckoutDone()
msgType = KTextEditor::Message::Warning;
msgStr = i18n("Failed to checkout branch: %1", res.branch);
} else {
Q_EMIT branchChanged(res.branch);
msgStr = i18n("Checked out to branch: %1", res.branch);
}
sendMessage(msgStr, msgType == KTextEditor::Message::Warning);
......@@ -288,47 +215,47 @@ void BranchesDialog::slotReturnPressed()
{
// we cleared the model to checkout new branch
if (m_model->rowCount() == 0) {
createNewBranch(m_lineEdit->text(), m_checkoutBranchName);
createNewBranch(m_lineEdit.text(), m_checkoutBranchName);
return;
}
// branch is selected, do actual checkout
if (m_checkingOutFromBranch) {
m_checkingOutFromBranch = false;
const auto fromBranch = m_proxyModel->data(m_treeView->currentIndex(), BranchesDialogModel::CheckoutName).toString();
const auto fromBranch = m_proxyModel->data(m_treeView.currentIndex(), BranchesDialogModel::CheckoutName).toString();
m_checkoutBranchName = fromBranch;
m_model->clear();
m_lineEdit->clear();
m_lineEdit->setPlaceholderText(i18n("Enter new branch name. Press 'Esc' to cancel."));
clearLineEdit();
m_lineEdit.setPlaceholderText(i18n("Enter new branch name. Press 'Esc' to cancel."));
return;
}
const auto branch = m_proxyModel->data(m_treeView->currentIndex(), BranchesDialogModel::CheckoutName).toString();
const auto itemType = (BranchesDialogModel::ItemType)m_proxyModel->data(m_treeView->currentIndex(), BranchesDialogModel::ItemTypeRole).toInt();
const auto branch = m_proxyModel->data(m_treeView.currentIndex(), BranchesDialogModel::CheckoutName).toString();
const auto itemType = (BranchesDialogModel::ItemType)m_proxyModel->data(m_treeView.currentIndex(), BranchesDialogModel::ItemTypeRole).toInt();
if (itemType == BranchesDialogModel::BranchItem) {
QFuture<GitUtils::CheckoutResult> future = QtConcurrent::run(&GitUtils::checkoutBranch, m_projectPath, branch);
m_checkoutWatcher.setFuture(future);
} else if (itemType == BranchesDialogModel::CreateBranch) {
m_model->clear();
m_lineEdit->setPlaceholderText(i18n("Enter new branch name. Press 'Esc' to cancel."));
m_lineEdit.setPlaceholderText(i18n("Enter new branch name. Press 'Esc' to cancel."));
return;
} else if (itemType == BranchesDialogModel::CreateBranchFrom) {
m_model->clearBranchCreationItems();
m_lineEdit->clear();
m_lineEdit->setPlaceholderText(i18n("Select branch to checkout from. Press 'Esc' to cancel."));
clearLineEdit();
m_lineEdit.setPlaceholderText(i18n("Select branch to checkout from. Press 'Esc' to cancel."));
m_checkingOutFromBranch = true;
return;
}
m_lineEdit->clear();
clearLineEdit();
hide();
}
void BranchesDialog::reselectFirst()
{
QModelIndex index = m_proxyModel->index(0, 0);
m_treeView->setCurrentIndex(index);
m_treeView.setCurrentIndex(index);
}
void BranchesDialog::sendMessage(const QString &plainText, bool warn)
......@@ -345,7 +272,7 @@ void BranchesDialog::sendMessage(const QString &plainText, bool warn)
void BranchesDialog::createNewBranch(const QString &branch, const QString &fromBranch)
{
if (branch.isEmpty()) {
m_lineEdit->clear();
clearLineEdit();
hide();
return;
}
......@@ -359,26 +286,6 @@ void BranchesDialog::createNewBranch(const QString &branch, const QString &fromB
sendMessage(i18n("Failed to create new branch. Error \"%1\"", r.error), warn);
}
m_lineEdit->clear();
clearLineEdit();
hide();
}
void BranchesDialog::updateViewGeometry()
{
m_treeView->resizeColumnToContents(0);
m_treeView->resizeColumnToContents(1);
QWidget *window = m_mainWindow->window();
const QSize centralSize = window->size();
// width: 2.4 of editor, height: 1/2 of editor
const QSize viewMaxSize(centralSize.width() / 2.4, centralSize.height() / 2);
// Position should be central over window
const int xPos = std::max(0, (centralSize.width() - viewMaxSize.width()) / 2);
const int yPos = std::max(0, (centralSize.height() - viewMaxSize.height()) * 1 / 4);
const QPoint p(xPos, yPos);
move(p + window->pos());
this->setFixedSize(viewMaxSize);
}
......@@ -7,6 +7,7 @@
#include <QMenu>
#include "git/gitutils.h"
#include "quickdialog.h"
class QTreeView;
class QLineEdit;
......@@ -21,24 +22,17 @@ namespace KTextEditor
class MainWindow;
}
class BranchesDialog : public QMenu
class BranchesDialog : public QuickDialog
{
Q_OBJECT
public:
BranchesDialog(QWidget *parent, KTextEditor::MainWindow *mainWindow, KateProjectPluginView *pluginView, QString projectPath);
BranchesDialog(QWidget *window, KateProjectPluginView *pluginView, QString projectPath);
void openDialog();
void updateViewGeometry();
Q_SIGNAL void branchChanged(const QString &branch);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
// removed, otherwise we can trigger multiple project reloads on branch change
// Q_SIGNAL void branchChanged(const QString &branch);
private Q_SLOTS:
void slotReturnPressed();
void slotReturnPressed() override;
void reselectFirst();
void onCheckoutDone();
......@@ -48,11 +42,8 @@ private:
void createNewBranch(const QString &branch, const QString &fromBranch = QString());
private:
QTreeView *m_treeView;
QLineEdit *m_lineEdit;
BranchesDialogModel *m_model;
BranchFilterModel *m_proxyModel;
KTextEditor::MainWindow *m_mainWindow;
KateProjectPluginView *m_pluginView;
QString m_projectPath;
QFutureWatcher<GitUtils::CheckoutResult> m_checkoutWatcher;
......
......@@ -522,7 +522,7 @@ void GitWidget::buildMenu()
}
});
m_gitMenu->addAction(i18n("Checkout Branch"), this, [this] {
BranchesDialog bd(this, m_mainWin, m_pluginView, m_project->baseDir());
BranchesDialog bd(m_mainWin->window(), m_pluginView, m_project->baseDir());
bd.openDialog();
});
......@@ -543,39 +543,39 @@ QMenu *GitWidget::stashMenu()
auto showStashAct = menu->addAction(i18n("Show Stash Content"));
connect(stashAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::Stash);
});
connect(stashUAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::StashUntrackIncluded);
});
connect(stashKeepStagedAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::StashKeepIndex);
});
connect(popAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::StashPop);
});
connect(applyStashAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::StashApply);
});
connect(dropAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::StashDrop);
});
connect(popLastAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::StashPopLast);
});
connect(applyLastAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::StashApplyLast);
});
connect(showStashAct, &QAction::triggered, this, [this] {
StashDialog stashDialog(this, m_mainWin);
StashDialog stashDialog(this, m_mainWin->window());
stashDialog.openDialog(StashDialog::ShowStashContent);
});
......
......@@ -68,14 +68,11 @@ KateProjectView::KateProjectView(KateProjectPluginView *pluginView, KateProject
* Setup git checkout stuff
*/
m_branchBtn->setHidden(true);
m_branchesDialog = new BranchesDialog(this, mainWindow, m_pluginView, m_project->baseDir());
connect(m_branchBtn, &QPushButton::clicked, this, [this] {
m_branchesDialog->openDialog();
});
connect(m_branchesDialog, &BranchesDialog::branchChanged, this, [this](const QString &branch) {
m_branchBtn->setText(branch);
m_project->reload(true);
connect(m_branchBtn, &QPushButton::clicked, this, [this, mainWindow] {
BranchesDialog bd(mainWindow->window(), m_pluginView, m_project->baseDir());
bd.openDialog();
});
connect(m_project, &KateProject::modelChanged, this, [this] {
if (GitUtils::isGitRepo(m_project->baseDir())) {
m_branchBtn->setHidden(false);
......
......@@ -92,11 +92,6 @@ private:
*/
QToolButton *m_branchBtn;
/**
* The dialog which displays git branches
*/
BranchesDialog *m_branchesDialog;
/**
* watches for changes to .git/HEAD
*/
......
#include "quickdialog.h"
#include <QCoreApplication>
#include <QKeyEvent>
#include <QLineEdit>
#include <QSortFilterProxyModel>
#include <QTreeView>
#include <QVBoxLayout>
#include <QDebug>
QuickDialog::QuickDialog(QWidget *mainWindow)
: QMenu()
, m_mainWindow(mainWindow)
{
QVBoxLayout *layout = new QVBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(4, 4, 4, 4);
setLayout(layout);
setFocusProxy(&m_lineEdit);
layout->addWidget(&m_lineEdit);
layout->addWidget(&m_treeView, 1);
m_treeView.setTextElideMode(Qt::ElideLeft);
m_treeView.setUniformRowHeights(true);
connect(&m_lineEdit, &QLineEdit::returnPressed, this, &QuickDialog::slotReturnPressed);
// user can add this as necessary
// connect(m_lineEdit, &QLineEdit::textChanged, delegate, &StyleDelegate::setFilterString);
connect(&m_lineEdit, &QLineEdit::textChanged, this, [this]() {
m_treeView.viewport()->update();
});
connect(&m_treeView, &QTreeView::clicked, this, &QuickDialog::slotReturnPressed);
m_treeView.setSortingEnabled(true);
m_treeView.installEventFilter(this);
m_lineEdit.installEventFilter(this);
m_treeView.setHeaderHidden(true);
m_treeView.setRootIsDecorated(false);
m_treeView.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_treeView.setSelectionMode(QTreeView::SingleSelection);
}
bool QuickDialog::eventFilter(QObject *obj, QEvent *event)
{
// catch key presses + shortcut overrides to allow to have ESC as application wide shortcut, too, see bug 409856
if (event->type() == QEvent::KeyPress || event->type() == QEvent::ShortcutOverride) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (obj == &m_lineEdit) {
const bool forward2list = (keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down) || (keyEvent->key() == Qt::Key_PageUp)
|| (keyEvent->key() == Qt::Key_PageDown);
if (forward2list) {
QCoreApplication::sendEvent(&m_treeView, event);
return true;
}
if (keyEvent->key() == Qt::Key_Escape) {
clearLineEdit();
keyEvent->accept();
hide();
return true;
}
} else {
const bool forward2input = (keyEvent->key() != Qt::Key_Up) && (keyEvent->key() != Qt::Key_Down) && (keyEvent->key() != Qt::Key_PageUp)
&& (keyEvent->key() != Qt::Key_PageDown) && (keyEvent->key() != Qt::Key_Tab) && (keyEvent->key() != Qt::Key_Backtab);
if (forward2input) {
QCoreApplication::sendEvent(&m_lineEdit, event);
return true;
}
}
}
// hide on focus out, if neither input field nor list have focus!
else if (event->type() == QEvent::FocusOut && !(m_lineEdit.hasFocus() || m_treeView.hasFocus())) {
clearLineEdit();
hide();
return true;
}
return QWidget::eventFilter(obj, event);
}
void QuickDialog::updateViewGeometry()
{
if (!m_mainWindow)
return;
m_treeView.resizeColumnToContents(0);
m_treeView.resizeColumnToContents(1);
const QSize centralSize = m_mainWindow->size();
// width: 2.4 of editor, height: 1/2 of editor
const QSize viewMaxSize(centralSize.width() / 2.4, centralSize.height() / 2);
// Position should be central over window
const int xPos = std::max(0, (centralSize.width() - viewMaxSize.width()) / 2);
const int yPos = std::max(0, (centralSize.height() - viewMaxSize.height()) * 1 / 4);
const QPoint p(xPos, yPos);
move(p + m_mainWindow->pos());
this->setFixedSize(viewMaxSize);
}
void QuickDialog::clearLineEdit()
{
const QSignalBlocker block(m_lineEdit);
m_lineEdit.clear();
}
#ifndef QUICKDIALOG_H
#define QUICKDIALOG_H
#include <QLineEdit>
#include <QMenu>
#include <QPointer>
#include <QSortFilterProxyModel>
#include <QTreeView>
class QAbstractItemModel;
class QTreeView;
class QLineEdit;
namespace KTextEditor
{
class MainWindow;
}
class QuickDialog : public QMenu
{
Q_OBJECT
public:
QuickDialog(QWidget *mainWindow /* QAbstractItemModel *model*/ /*, QuickDialogProxyModel *proxyModel*/);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
void updateViewGeometry();
void clearLineEdit();
protected Q_SLOTS:
virtual void slotReturnPressed() = 0;
protected:
QTreeView m_treeView;
QLineEdit m_lineEdit;
private:
QPointer<QWidget> m_mainWindow;
};
#endif // QUICKDIALOG_H
......@@ -34,7 +34,7 @@
constexpr int StashIndexRole = Qt::UserRole + 2;
class StashFilterModel : public QSortFilterProxyModel
class StashFilterModel final : public QSortFilterProxyModel
{
public:
StashFilterModel(QObject *parent = nullptr)
......@@ -68,10 +68,9 @@ protected:
sourceModel()->setData(idx, score, FuzzyScore);
return res;
}
private:
QString m_pattern;
static constexpr int FuzzyScore = Qt::UserRole + 1;
QString m_pattern;
};
class StyleDelegate : public QStyledItemDelegate
......@@ -133,54 +132,24 @@ private:
QString m_filterString;
};
StashDialog::StashDialog(QWidget *parent, KTextEditor::MainWindow *mainWindow)
: QMenu(parent)
, m_mainWindow(mainWindow)
, m_gitwidget(qobject_cast<GitWidget *>(parent))
StashDialog::StashDialog(GitWidget *gitwidget, QWidget *window)
: QuickDialog(window)
, m_gitwidget(gitwidget)
{
QVBoxLayout *layout = new QVBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(4, 4, 4, 4);
setLayout(layout);
m_lineEdit = new QLineEdit(this);
setFocusProxy(m_lineEdit);
layout->addWidget(m_lineEdit);
m_treeView = new QTreeView();
layout->addWidget(m_treeView, 1);
m_treeView->setTextElideMode(Qt::ElideLeft);
m_treeView->setUniformRowHeights(true);
m_model = new QStandardItemModel(this);
StyleDelegate *delegate = new StyleDelegate(this);
m_treeView->setItemDelegateForColumn(0, delegate);
m_proxyModel = new StashFilterModel(this);
m_proxyModel->setFilterRole(Qt::DisplayRole);
connect(m_lineEdit, &QLineEdit::returnPressed, this, &StashDialog::slotReturnPressed);
connect(m_lineEdit, &QLineEdit::textChanged, m_proxyModel, &StashFilterModel::setFilterString);
connect(m_lineEdit, &QLineEdit::textChanged, delegate, &StyleDelegate::setFilterString);
connect(m_lineEdit, &QLineEdit::textChanged, this, [this]() {
m_treeView->viewport()->update();
reselectFirst();
});
connect(m_treeView, &QTreeView::clicked, this, &StashDialog::slotReturnPressed);
m_proxyModel->setSourceModel(m_model);
m_treeView->setSortingEnabled(true);
m_treeView->setModel(m_proxyModel);
m_treeView.setModel(m_proxyModel);
m_treeView->installEventFilter(this);
m_lineEdit->installEventFilter(this);
m_treeView->setHeaderHidden(true);