VCS[git]: Make Branchdialog non-modal as is StashDialog.

Give dialogs a consistent look, set
WA_DeleteOnClose on them and improve updating.
Add a Refresh/Diff buttons to branch dialog.
This commit is contained in:
Friedemann Kleint
2010-01-27 12:47:14 +01:00
parent 8ecc80ec4c
commit 18ab532e56
11 changed files with 179 additions and 91 deletions

View File

@@ -30,7 +30,11 @@
#include "branchdialog.h"
#include "branchmodel.h"
#include "gitclient.h"
#include "gitplugin.h"
#include "ui_branchdialog.h"
#include "stashdialog.h" // Label helpers
#include <vcsbase/vcsbaseoutputwindow.h>
#include <QtGui/QItemSelectionModel>
#include <QtGui/QPushButton>
@@ -59,29 +63,56 @@ static inline void selectListRow(QAbstractItemView *iv, int row)
namespace Git {
namespace Internal {
static inline GitClient *gitClient()
{
return GitPlugin::instance()->gitClient();
}
BranchDialog::BranchDialog(QWidget *parent) :
QDialog(parent),
m_client(0),
m_ui(new Ui::BranchDialog),
m_checkoutButton(0),
m_diffButton(0),
m_refreshButton(0),
m_deleteButton(0),
m_localModel(0),
m_remoteModel(0)
m_localModel(new LocalBranchModel(gitClient(), this)),
m_remoteModel(new RemoteBranchModel(gitClient(), this))
{
setModal(true);
setModal(false);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setAttribute(Qt::WA_DeleteOnClose, true); // Do not update unnecessarily
m_ui->setupUi(this);
m_checkoutButton = m_ui->buttonBox->addButton(tr("Checkout"), QDialogButtonBox::AcceptRole);
m_checkoutButton = m_ui->buttonBox->addButton(tr("Checkout"), QDialogButtonBox::ActionRole);
connect(m_checkoutButton, SIGNAL(clicked()), this, SLOT(slotCheckoutSelectedBranch()));
m_deleteButton = m_ui->buttonBox->addButton(tr("Delete"), QDialogButtonBox::ActionRole);
m_diffButton = m_ui->buttonBox->addButton(tr("Diff"), QDialogButtonBox::ActionRole);
connect(m_diffButton, SIGNAL(clicked()), this, SLOT(slotDiffSelected()));
m_refreshButton = m_ui->buttonBox->addButton(tr("Refresh"), QDialogButtonBox::ActionRole);
connect(m_refreshButton, SIGNAL(clicked()), this, SLOT(slotRefresh()));
m_deleteButton = m_ui->buttonBox->addButton(tr("Delete..."), QDialogButtonBox::ActionRole);
connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteSelectedBranch()));
connect(m_ui->localBranchListView, SIGNAL(doubleClicked(QModelIndex)), this,
SLOT(slotLocalBranchActivated()));
connect(m_ui->remoteBranchListView, SIGNAL(doubleClicked(QModelIndex)), this,
SLOT(slotRemoteBranchActivated(QModelIndex)));
connect(m_localModel, SIGNAL(newBranchEntered(QString)), this, SLOT(slotCreateLocalBranch(QString)));
m_ui->localBranchListView->setModel(m_localModel);
m_ui->remoteBranchListView->setModel(m_remoteModel);
connect(m_ui->localBranchListView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(slotEnableButtons()));
connect(m_ui->remoteBranchListView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(slotEnableButtons()));
slotEnableButtons();
}
BranchDialog::~BranchDialog()
@@ -89,35 +120,24 @@ BranchDialog::~BranchDialog()
delete m_ui;
}
bool BranchDialog::init(GitClient *client, const QString &workingDirectory, QString *errorMessage)
void BranchDialog::refresh(const QString &repository, bool force)
{
// Find repository and populate models.
m_client = client;
m_repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory);
if (m_repoDirectory.isEmpty()) {
*errorMessage = tr("Unable to find the repository directory for '%1'.").arg(workingDirectory);
return false;
if (m_repository == repository && !force)
return;
// Refresh
m_repository = repository;
m_ui->repositoryLabel->setText(StashDialog::msgRepositoryLabel(m_repository));
if (m_repository.isEmpty()) {
m_localModel->clear();
m_remoteModel->clear();
} else {
QString errorMessage;
const bool success = m_localModel->refresh(m_repository, &errorMessage)
&& m_remoteModel->refresh(m_repository, &errorMessage);
if (!success)
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
}
m_ui->repositoryFieldLabel->setText(m_repoDirectory);
m_localModel = new LocalBranchModel(client, this);
connect(m_localModel, SIGNAL(newBranchEntered(QString)), this, SLOT(slotCreateLocalBranch(QString)));
m_remoteModel = new RemoteBranchModel(client, this);
if (!m_localModel->refresh(workingDirectory, errorMessage)
|| !m_remoteModel->refresh(workingDirectory, errorMessage))
return false;
m_ui->localBranchListView->setModel(m_localModel);
m_ui->remoteBranchListView->setModel(m_remoteModel);
// Selection model comes into existence only now
connect(m_ui->localBranchListView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(slotEnableButtons()));
connect(m_ui->remoteBranchListView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(slotEnableButtons()));
slotEnableButtons();
return true;
}
int BranchDialog::selectedLocalBranchIndex() const
@@ -133,6 +153,7 @@ int BranchDialog::selectedRemoteBranchIndex() const
void BranchDialog::slotEnableButtons()
{
// We can switch to or delete branches that are not current.
const bool hasRepository = !m_repository.isEmpty();
const int selectedLocalRow = selectedLocalBranchIndex();
const int currentLocalBranch = m_localModel->currentBranch();
@@ -140,7 +161,17 @@ void BranchDialog::slotEnableButtons()
const bool currentIsNotSelected = hasSelection && selectedLocalRow != currentLocalBranch;
m_checkoutButton->setEnabled(currentIsNotSelected);
m_diffButton->setEnabled(currentIsNotSelected);
m_deleteButton->setEnabled(currentIsNotSelected);
m_refreshButton->setEnabled(hasRepository);
// Also disable <New Branch> entry of list view
m_ui->localBranchListView->setEnabled(hasRepository);
m_ui->remoteBranchListView->setEnabled(hasRepository);
}
void BranchDialog::slotRefresh()
{
refresh(m_repository, true);
}
void BranchDialog::selectLocalBranch(const QString &b)
@@ -172,9 +203,9 @@ void BranchDialog::slotDeleteSelectedBranch()
QString output;
QStringList args(QLatin1String("-D"));
args << name;
if (!m_client->synchronousBranchCmd(m_repoDirectory, args, &output, &errorMessage))
if (!gitClient()->synchronousBranchCmd(m_repository, args, &output, &errorMessage))
break;
if (!m_localModel->refresh(m_repoDirectory, &errorMessage))
if (!m_localModel->refresh(m_repository, &errorMessage))
break;
ok = true;
} while (false);
@@ -190,9 +221,9 @@ void BranchDialog::slotCreateLocalBranch(const QString &branchName)
QString errorMessage;
bool ok = false;
do {
if (!m_client->synchronousBranchCmd(m_repoDirectory, QStringList(branchName), &output, &errorMessage))
if (!gitClient()->synchronousBranchCmd(m_repository, QStringList(branchName), &output, &errorMessage))
break;
if (!m_localModel->refresh(m_repoDirectory, &errorMessage))
if (!m_localModel->refresh(m_repository, &errorMessage))
break;
ok = true;
} while (false);
@@ -209,6 +240,14 @@ void BranchDialog::slotLocalBranchActivated()
m_checkoutButton->animateClick();
}
void BranchDialog::slotDiffSelected()
{
const int idx = selectedLocalBranchIndex();
if (idx == -1)
return;
gitClient()->diffBranch(m_repository, QStringList(), m_localModel->branchName(idx));
}
/* Ask to stash away changes and then close dialog and do an asynchronous
* checkout. */
void BranchDialog::slotCheckoutSelectedBranch()
@@ -218,7 +257,7 @@ void BranchDialog::slotCheckoutSelectedBranch()
return;
const QString name = m_localModel->branchName(idx);
QString errorMessage;
switch (m_client->ensureStash(m_repoDirectory, &errorMessage)) {
switch (gitClient()->ensureStash(m_repository, &errorMessage)) {
case GitClient::StashUnchanged:
case GitClient::Stashed:
case GitClient::NotStashed:
@@ -229,8 +268,11 @@ void BranchDialog::slotCheckoutSelectedBranch()
QMessageBox::warning(this, tr("Failed to stash"), errorMessage);
return;
}
accept();
m_client->checkoutBranch(m_repoDirectory, name);
if (gitClient()->synchronousCheckoutBranch(m_repository, name, &errorMessage)) {
refresh(m_repository, true);
} else {
QMessageBox::warning(this, tr("Checkout failed"), errorMessage);
}
}
void BranchDialog::slotRemoteBranchActivated(const QModelIndex &i)
@@ -271,9 +313,9 @@ void BranchDialog::slotRemoteBranchActivated(const QModelIndex &i)
bool ok = false;
do {
QString output;
if (!m_client->synchronousBranchCmd(m_repoDirectory, args, &output, &errorMessage))
if (!gitClient()->synchronousBranchCmd(m_repository, args, &output, &errorMessage))
break;
if (!m_localModel->refresh(m_repoDirectory, &errorMessage))
if (!m_localModel->refresh(m_repository, &errorMessage))
break;
ok = true;
} while (false);

View File

@@ -52,30 +52,30 @@ class RemoteBranchModel;
* Branch dialog. Displays a list of local branches at the top and remote
* branches below. Offers to checkout/delete local branches.
*
* TODO: Add new branch (optionally tracking a remote one).
* How to find out that a local branch is a tracking one?
*/
class BranchDialog : public QDialog {
Q_OBJECT
Q_DISABLE_COPY(BranchDialog)
public:
explicit BranchDialog(QWidget *parent = 0);
bool init(GitClient *client, const QString &workingDirectory, QString *errorMessage);
virtual ~BranchDialog();
protected:
virtual void changeEvent(QEvent *e);
public slots:
void refresh(const QString &repository, bool force);
private slots:
void slotEnableButtons();
void slotCheckoutSelectedBranch();
void slotDeleteSelectedBranch();
void slotDiffSelected();
void slotRefresh();
void slotLocalBranchActivated();
void slotRemoteBranchActivated(const QModelIndex &);
void slotCreateLocalBranch(const QString &branchName);
protected:
virtual void changeEvent(QEvent *e);
private:
bool ask(const QString &title, const QString &what, bool defaultButton);
void selectLocalBranch(const QString &b);
@@ -83,14 +83,15 @@ private:
int selectedLocalBranchIndex() const;
int selectedRemoteBranchIndex() const;
GitClient *m_client;
Ui::BranchDialog *m_ui;
QPushButton *m_checkoutButton;
QPushButton *m_diffButton;
QPushButton *m_refreshButton;
QPushButton *m_deleteButton;
LocalBranchModel *m_localModel;
RemoteBranchModel *m_remoteModel;
QString m_repoDirectory;
QString m_repository;
};
} // namespace Internal

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>544</width>
<height>631</height>
<width>514</width>
<height>527</height>
</rect>
</property>
<property name="windowTitle">
@@ -16,21 +16,14 @@
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="infoGroupBox">
<property name="title">
<string>General information</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="repositoryLabel">
<property name="text">
<string>Repository:</string>
<string notr="true">Repository: Dummy</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="repositoryFieldLabel">
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -134,6 +134,14 @@ bool RemoteBranchModel::runGitBranchCommand(const QString &workingDirectory, con
return m_client->synchronousBranchCmd(workingDirectory, additionalArgs, output, errorMessage);
}
void RemoteBranchModel::clear()
{
if (!m_branches.isEmpty()) {
m_branches.clear();
reset();
}
}
bool RemoteBranchModel::refreshBranches(const QString &workingDirectory, bool remoteBranches,
int *currentBranch, QString *errorMessage)
{
@@ -225,6 +233,13 @@ QVariant LocalBranchModel::data(const QModelIndex &index, int role) const
return RemoteBranchModel::data(index, role);
}
void LocalBranchModel::clear()
{
m_currentBranch = -1;
m_newBranch.clear();
RemoteBranchModel::clear();
}
bool LocalBranchModel::refresh(const QString &workingDirectory, QString *errorMessage)
{
return refreshBranches(workingDirectory, false, &m_currentBranch, errorMessage);
@@ -248,7 +263,7 @@ bool LocalBranchModel::setData(const QModelIndex &index, const QVariant &value,
if (role != Qt::EditRole || index.row() < branchCount())
return false;
const QString branchName = value.toString();
// Delay the signal as we don't ourselves to be reset while
// Delay the signal as we don't want ourselves to be reset while
// in setData().
if (checkNewBranchName(branchName)) {
m_newBranch = branchName;

View File

@@ -49,6 +49,7 @@ class RemoteBranchModel : public QAbstractListModel {
public:
explicit RemoteBranchModel(GitClient *client, QObject *parent = 0);
virtual void clear();
virtual bool refresh(const QString &workingDirectory, QString *errorMessage);
QString branchName(int row) const;
@@ -100,6 +101,7 @@ public:
explicit LocalBranchModel(GitClient *client,
QObject *parent = 0);
virtual void clear();
virtual bool refresh(const QString &workingDirectory, QString *errorMessage);
// is this the "type here" row?

View File

@@ -260,10 +260,10 @@ void GitClient::diff(const QString &workingDirectory,
if (Git::Constants::debug)
qDebug() << "diff" << workingDirectory << fileName;
QStringList arguments;
arguments << QLatin1String("diff") << QLatin1String(noColorOption);
arguments << QLatin1String("diff") << QLatin1String(noColorOption)
<< diffArgs;
if (!fileName.isEmpty())
arguments << diffArgs << QLatin1String("--") << fileName;
arguments << QLatin1String("--") << fileName;
const QString editorId = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_ID);
const QString title = tr("Git Diff %1").arg(fileName);
const QString sourceFile = VCSBase::VCSBaseEditor::getSource(workingDirectory, fileName);
@@ -271,6 +271,24 @@ void GitClient::diff(const QString &workingDirectory,
executeGit(workingDirectory, arguments, editor);
}
void GitClient::diffBranch(const QString &workingDirectory,
const QStringList &diffArgs,
const QString &branchName)
{
if (Git::Constants::debug)
qDebug() << "diffBranch" << workingDirectory << branchName;
QStringList arguments;
arguments << QLatin1String("diff") << QLatin1String(noColorOption)
<< diffArgs << branchName;
const QString editorId = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_ID);
const QString title = tr("Git Diff Branch %1").arg(branchName);
const QString sourceFile = VCSBase::VCSBaseEditor::getSource(workingDirectory, QStringList());
VCSBase::VCSBaseEditor *editor = createVCSEditor(editorId, title, sourceFile, true,
"BranchName", branchName);
executeGit(workingDirectory, arguments, editor);
}
void GitClient::status(const QString &workingDirectory)
{
// @TODO: Use "--no-color" once it is supported

View File

@@ -81,6 +81,9 @@ public:
void diff(const QString &workingDirectory, const QStringList &diffArgs, const QString &fileName);
void diff(const QString &workingDirectory, const QStringList &diffArgs,
const QStringList &unstagedFileNames, const QStringList &stagedFileNames= QStringList());
void diffBranch(const QString &workingDirectory,
const QStringList &diffArgs,
const QString &branchName);
void status(const QString &workingDirectory);
void graphLog(const QString &workingDirectory);

View File

@@ -684,35 +684,38 @@ void GitPlugin::stashPop()
m_gitClient->stashPop(state.topLevel());
}
// Create a non-modal dialog with refresh method or raise if it exists
template <class NonModalDialog>
inline void showNonModalDialog(const QString &topLevel,
QPointer<NonModalDialog> &dialog)
{
if (dialog) {
dialog->show();
dialog->raise();
} else {
dialog = new NonModalDialog(Core::ICore::instance()->mainWindow());
dialog->refresh(topLevel, true);
dialog->show();
}
}
void GitPlugin::branchList()
{
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasTopLevel(), return)
QString errorMessage;
BranchDialog dialog(m_core->mainWindow());
if (!dialog.init(m_gitClient, state.topLevel(), &errorMessage)) {
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
return;
}
dialog.exec();
showNonModalDialog(currentState().topLevel(), m_branchDialog);
}
void GitPlugin::stashList()
{
// Raise non-modal stash dialog.
if (m_stashDialog) {
m_stashDialog->show();
m_stashDialog->raise();
} else {
m_stashDialog = new StashDialog(Core::ICore::instance()->mainWindow());
m_stashDialog->refresh(currentState().topLevel(), true);
m_stashDialog->show();
}
showNonModalDialog(currentState().topLevel(), m_stashDialog);
}
void GitPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
{
if (m_stashDialog)
m_stashDialog->refresh(currentState().topLevel(), false);
if (m_branchDialog)
m_branchDialog->refresh(currentState().topLevel(), false);
if (!enableMenuAction(as, m_menuAction))
return;
// Note: This menu is visible if there is no repository. Only
@@ -754,9 +757,6 @@ void GitPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
m_undoRepositoryAction->setEnabled(repositoryEnabled);
m_pushAction->setEnabled(repositoryEnabled);
if (m_stashDialog)
m_stashDialog->refresh(currentState().topLevel(), false);
// Prompts for repo.
m_showAction->setEnabled(true);
}

View File

@@ -66,6 +66,7 @@ class GitSubmitEditor;
struct CommitData;
struct GitSettings;
class StashDialog;
class BranchDialog;
class GitPlugin : public VCSBase::VCSBasePlugin
{
@@ -157,6 +158,7 @@ private:
GitClient *m_gitClient;
ChangeSelectionDialog *m_changeSelectionDialog;
QPointer<StashDialog> m_stashDialog;
QPointer<BranchDialog> m_branchDialog;
QString m_submitRepository;
QStringList m_submitOrigCommitFiles;
QStringList m_submitOrigDeleteFiles;

View File

@@ -112,6 +112,8 @@ StashDialog::StashDialog(QWidget *parent) :
m_refreshButton(new QPushButton(tr("Refresh")))
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setAttribute(Qt::WA_DeleteOnClose, true); // Do not update unnecessarily
ui->setupUi(this);
// Buttons
ui->buttonBox->addButton(m_showCurrentButton, QDialogButtonBox::ActionRole);
@@ -158,17 +160,23 @@ void StashDialog::changeEvent(QEvent *e)
}
}
QString StashDialog::msgRepositoryLabel(const QString &repository)
{
return repository.isEmpty() ?
tr("<No repository>") :
tr("Repository: %1").arg(repository);
}
void StashDialog::refresh(const QString &repository, bool force)
{
if (m_repository == repository && !force)
return;
// Refresh
m_repository = repository;
ui->repositoryLabel->setText(msgRepositoryLabel(repository));
if (m_repository.isEmpty()) {
ui->repositoryLabel->setText(tr("<No repository>"));
m_model->setStashes(QList<Stash>());
} else {
ui->repositoryLabel->setText(tr("Repository: %1").arg(repository));
QList<Stash> stashes;
gitClient()->synchronousStashList(m_repository, &stashes);
m_model->setStashes(stashes);
@@ -383,14 +391,16 @@ void StashDialog::forceRefresh()
void StashDialog::enableButtons()
{
const bool hasStashes = m_model->rowCount();
const bool hasCurrentRow = hasStashes && currentRow() >= 0;
const bool hasRepository = !m_repository.isEmpty();
const bool hasStashes = hasRepository && m_model->rowCount();
const bool hasCurrentRow = hasRepository && hasStashes && currentRow() >= 0;
m_deleteAllButton->setEnabled(hasStashes);
m_showCurrentButton->setEnabled(hasCurrentRow);
m_restoreCurrentButton->setEnabled(hasCurrentRow);
m_restoreCurrentInBranchButton->setEnabled(hasCurrentRow);
const bool hasSelection = !ui->stashView->selectionModel()->selectedRows().isEmpty();
m_deleteSelectionButton->setEnabled(hasSelection);
m_refreshButton->setEnabled(hasRepository);
}
void StashDialog::warning(const QString &title, const QString &what, const QString &details)

View File

@@ -57,6 +57,8 @@ public:
explicit StashDialog(QWidget *parent = 0);
~StashDialog();
static QString msgRepositoryLabel(const QString &repository);
public slots:
void refresh(const QString &repository, bool force);