diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp index d8a9dd8b84fe2a63671fd046b5c2855b6fa317e3..3796c6337b1674bc7ae34cbd51dd50f2acbfdef0 100644 --- a/src/plugins/git/branchdialog.cpp +++ b/src/plugins/git/branchdialog.cpp @@ -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,65 +63,81 @@ 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))); -} - -BranchDialog::~BranchDialog() -{ - delete m_ui; -} - -bool BranchDialog::init(GitClient *client, const QString &workingDirectory, QString *errorMessage) -{ - // 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; - } - 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(); +} + +BranchDialog::~BranchDialog() +{ + delete m_ui; +} + +void BranchDialog::refresh(const QString &repository, bool force) +{ + 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); + } 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); diff --git a/src/plugins/git/branchdialog.h b/src/plugins/git/branchdialog.h index 4cf8ceafeab019330774e04dac9a7d25bdbfc765..2ab5161d6aa9328f6601c9c230487846a4540423 100644 --- a/src/plugins/git/branchdialog.h +++ b/src/plugins/git/branchdialog.h @@ -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 diff --git a/src/plugins/git/branchdialog.ui b/src/plugins/git/branchdialog.ui index d88914fca5f3041aea60df70fb8ee648a0799044..45e6c65c7c950e8a0a514e5b1c008d162286c3dd 100644 --- a/src/plugins/git/branchdialog.ui +++ b/src/plugins/git/branchdialog.ui @@ -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> diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 0a37bf99aa41c6ea34df6e7c15ab26de4e88411d..8719bfeb3df8b5d2a67dd7a18d969994f6f5e21f 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -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; diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h index a4979abb0a0869dd98cbb785dc0b61785fa706dd..e36af0aad6acc6e35e4364c4937337d7385268d0 100644 --- a/src/plugins/git/branchmodel.h +++ b/src/plugins/git/branchmodel.h @@ -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? diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 88b88b9c633891fba265d9b45cd42a58c9fd4c26..b98462562ab1591a3f80c59edc85adfa5330bf8a 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -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 diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 790273aa06a5c4bfc05330e39787a1af758f58d4..55f6800d404799a1a14b5d52d7035132a570f411 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -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); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index cb034ff2a53c227f1748b7206dc89128991f9fd1..4c98ff4b087f5c42bcb8a08b0146050bb44a4eee 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -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); } diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index 30992c32d2a891e8650e68c88b154320f8929a01..c7c06f06cc3e943f29634a6cdff20c3c8ec32c17 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -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; diff --git a/src/plugins/git/stashdialog.cpp b/src/plugins/git/stashdialog.cpp index a39559ad597b964fbf7882a1e5ad289492b986b2..3c5141ee27d3838bdd17eba2f6426a65432cd4a3 100644 --- a/src/plugins/git/stashdialog.cpp +++ b/src/plugins/git/stashdialog.cpp @@ -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) diff --git a/src/plugins/git/stashdialog.h b/src/plugins/git/stashdialog.h index 377fef41e88be469d59d43412359ae01fae1386d..bea5c7b43d92998505707f02376540533b97dc27 100644 --- a/src/plugins/git/stashdialog.h +++ b/src/plugins/git/stashdialog.h @@ -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);