Git: Rework branch dialog

* Make adding new branches more discoverable
 * Make adding tracking branches more discoverable
 * Update UI

Task-number: QTCREATORBUG-4943
Task-number: QTCREATORBUG-4944
Change-Id: Idcbf5f8321a3bd04c925e33d094bb479788a7d9b
Reviewed-on: http://codereview.qt.nokia.com/588
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Tobias Hunger <tobias.hunger@nokia.com>
This commit is contained in:
Tobias Hunger
2011-05-30 12:14:49 +00:00
parent 9197596000
commit 5f6a91e009
9 changed files with 908 additions and 585 deletions

View File

@@ -0,0 +1,47 @@
#include "branchadddialog.h"
#include "ui_branchadddialog.h"
namespace Git {
namespace Internal {
BranchAddDialog::BranchAddDialog(QWidget *parent) :
QDialog(parent),
m_ui(new Ui::BranchAddDialog)
{
m_ui->setupUi(this);
}
BranchAddDialog::~BranchAddDialog()
{
delete m_ui;
}
void BranchAddDialog::setBranchName(const QString &n)
{
m_ui->branchNameEdit->setText(n);
m_ui->branchNameEdit->selectAll();
}
QString BranchAddDialog::branchName() const
{
return m_ui->branchNameEdit->text();
}
void BranchAddDialog::setTrackedBranchName(const QString &name, bool remote)
{
m_ui->trackingCheckBox->setVisible(true);
if (!name.isEmpty())
m_ui->trackingCheckBox->setText(remote ? tr("Track remote branch \'%1\'").arg(name) :
tr("Track local branch \'%1\'").arg(name));
else
m_ui->trackingCheckBox->setVisible(false);
m_ui->trackingCheckBox->setChecked(remote);
}
bool BranchAddDialog::track()
{
return m_ui->trackingCheckBox->isVisible() && m_ui->trackingCheckBox->isChecked();
}
} // namespace Internal
} // namespace Git

View File

@@ -0,0 +1,36 @@
#ifndef BRANCHADDDIALOG_H
#define BRANCHADDDIALOG_H
#include <QDialog>
namespace Git {
namespace Internal {
namespace Ui {
class BranchAddDialog;
}
class BranchAddDialog : public QDialog
{
Q_OBJECT
public:
explicit BranchAddDialog(QWidget *parent = 0);
~BranchAddDialog();
void setBranchName(const QString &);
QString branchName() const;
void setTrackedBranchName(const QString &name, bool remote);
bool track();
private:
Ui::BranchAddDialog *m_ui;
};
} // namespace Internal
} // namespace Git
#endif // BRANCHADDDIALOG_H

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Git::Internal::BranchAddDialog</class>
<widget class="QDialog" name="Git::Internal::BranchAddDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>134</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="branchNameLabel">
<property name="text">
<string>Branch Name:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="branchNameEdit"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="trackingCheckBox">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Git::Internal::BranchAddDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Git::Internal::BranchAddDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -31,12 +31,14 @@
**************************************************************************/
#include "branchdialog.h"
#include "branchadddialog.h"
#include "branchmodel.h"
#include "gitclient.h"
#include "gitplugin.h"
#include "ui_branchdialog.h"
#include "stashdialog.h" // Label helpers
#include <utils/checkablemessagebox.h>
#include <vcsbase/vcsbaseoutputwindow.h>
#include <QtGui/QItemSelectionModel>
@@ -45,42 +47,13 @@
#include <QtCore/QDebug>
enum { debug = 0 };
// Single selection helper
static inline int selectedRow(const QAbstractItemView *listView)
{
const QModelIndexList indexList = listView->selectionModel()->selectedIndexes();
if (indexList.size() == 1)
return indexList.front().row();
return -1;
}
// Helper to select a row. No sooner said then done
static inline void selectListRow(QAbstractItemView *iv, int row)
{
const QModelIndex index = iv->model()->index(row, 0);
iv->selectionModel()->select(index, QItemSelectionModel::Select);
}
namespace Git {
namespace Internal {
static inline GitClient *gitClient()
{
return GitPlugin::instance()->gitClient();
}
namespace Internal {
BranchDialog::BranchDialog(QWidget *parent) :
QDialog(parent),
m_ui(new Ui::BranchDialog),
m_checkoutButton(0),
m_diffButton(0),
m_logButton(0),
m_refreshButton(0),
m_deleteButton(0),
m_localModel(new LocalBranchModel(gitClient(), this)),
m_remoteModel(new RemoteBranchModel(gitClient(), this))
m_model(new BranchModel(GitPlugin::instance()->gitClient(), this))
{
setModal(false);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -88,273 +61,135 @@ BranchDialog::BranchDialog(QWidget *parent) :
m_ui->setupUi(this);
m_checkoutButton = m_ui->buttonBox->addButton(tr("Checkout"), QDialogButtonBox::ActionRole);
connect(m_checkoutButton, SIGNAL(clicked()), this, SLOT(slotCheckoutSelectedBranch()));
connect(m_ui->refreshButton, SIGNAL(clicked()), this, SLOT(refresh()));
connect(m_ui->addButton, SIGNAL(clicked()), this, SLOT(add()));
connect(m_ui->checkoutButton, SIGNAL(clicked()), this, SLOT(checkout()));
connect(m_ui->removeButton, SIGNAL(clicked()), this, SLOT(remove()));
connect(m_ui->diffButton, SIGNAL(clicked()), this, SLOT(diff()));
connect(m_ui->logButton, SIGNAL(clicked()), this, SLOT(log()));
m_diffButton = m_ui->buttonBox->addButton(tr("Diff"), QDialogButtonBox::ActionRole);
connect(m_diffButton, SIGNAL(clicked()), this, SLOT(slotDiffSelected()));
m_ui->branchView->setModel(m_model);
m_logButton = m_ui->buttonBox->addButton(tr("Log"), QDialogButtonBox::ActionRole);
connect(m_logButton, SIGNAL(clicked()), this, SLOT(slotLog()));
connect(m_ui->branchView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(enableButtons()));
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(QItemSelection)));
connect(m_ui->remoteBranchListView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(slotEnableButtons(QItemSelection)));
slotEnableButtons();
enableButtons();
}
BranchDialog::~BranchDialog()
{
delete m_ui;
delete m_model;
m_model = 0;
}
void BranchDialog::refresh(const QString &repository, bool force)
{
if (m_repository == repository && !force)
return;
// Refresh
return;
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();
QString errorMessage;
if (!m_model->refresh(m_repository, &errorMessage))
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
m_ui->branchView->expandAll();
}
int BranchDialog::selectedLocalBranchIndex() const
void BranchDialog::enableButtons()
{
return selectedRow(m_ui->localBranchListView);
QModelIndex idx = selectedIndex();
const bool hasSelection = idx.isValid();
const bool currentSelected = hasSelection && idx == m_model->currentBranch();
const bool isLocal = m_model->isLocal(idx);
const bool isLeaf = m_model->isLeaf(idx);
m_ui->removeButton->setEnabled(hasSelection && !currentSelected && isLocal && isLeaf);
m_ui->logButton->setEnabled(hasSelection && isLeaf);
m_ui->diffButton->setEnabled(hasSelection && isLeaf);
m_ui->checkoutButton->setEnabled(hasSelection && !currentSelected && isLocal && isLeaf);
}
int BranchDialog::selectedRemoteBranchIndex() const
{
return selectedRow(m_ui->remoteBranchListView);
}
void BranchDialog::slotEnableButtons(const QItemSelection &selected)
{
if (!selected.indexes().isEmpty()) {
if (selected.indexes().at(0).model() == m_localModel)
m_ui->remoteBranchListView->clearSelection();
else
m_ui->localBranchListView->clearSelection();
}
// We can switch to or delete branches that are not current.
const int selectedLocalRow = selectedLocalBranchIndex();
const bool hasRepository = !m_repository.isEmpty();
const bool hasLocalSelection = selectedLocalRow != -1 && !m_localModel->isNewBranchRow(selectedLocalRow);
const bool otherLocalSelected = hasLocalSelection && selectedLocalRow != m_localModel->currentBranch();
const bool branchSelected = hasLocalSelection || selectedRemoteBranchIndex() != -1;
m_checkoutButton->setEnabled(otherLocalSelected);
m_diffButton->setEnabled(branchSelected);
m_logButton->setEnabled(branchSelected);
m_deleteButton->setEnabled(otherLocalSelected);
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()
void BranchDialog::refresh()
{
refresh(m_repository, true);
}
void BranchDialog::selectLocalBranch(const QString &b)
void BranchDialog::add()
{
// Select the newly created branch
const int row = m_localModel->findBranchByName(b);
if (row != -1)
selectListRow(m_ui->localBranchListView, row);
QString trackedBranch = m_model->branchName(selectedIndex());
bool isLocal = m_model->isLocal(selectedIndex());
if (trackedBranch.isEmpty()) {
trackedBranch = m_model->branchName(m_model->currentBranch());
isLocal = true;
}
QStringList localNames = m_model->localBranchNames();
QString suggestedNameBase = trackedBranch.mid(trackedBranch.lastIndexOf(QLatin1Char('/')) + 1);
QString suggestedName = suggestedNameBase;
int i = 2;
while (localNames.contains(suggestedName)) {
suggestedName = suggestedNameBase + QString::number(i);
++i;
}
BranchAddDialog branchAddDialog;
branchAddDialog.setBranchName(suggestedName);
branchAddDialog.setTrackedBranchName(trackedBranch, !isLocal);
if (branchAddDialog.exec() == QDialog::Accepted && m_model) {
QModelIndex idx = m_model->addBranch(branchAddDialog.branchName(), branchAddDialog.track(), trackedBranch);
m_ui->branchView->selectionModel()->select(idx, QItemSelectionModel::Clear
| QItemSelectionModel::Select
| QItemSelectionModel::Current);
m_ui->branchView->scrollTo(idx);
}
}
bool BranchDialog::ask(const QString &title, const QString &what, bool defaultButton)
void BranchDialog::checkout()
{
return QMessageBox::question(this, title, what, QMessageBox::Yes|QMessageBox::No,
defaultButton ? QMessageBox::Yes : QMessageBox::No) == QMessageBox::Yes;
QModelIndex idx = selectedIndex();
Q_ASSERT(m_model->isLocal(idx));
m_model->checkoutBranch(idx);
}
/* Prompt to delete a local branch and do so. */
void BranchDialog::slotDeleteSelectedBranch()
void BranchDialog::remove()
{
const int idx = selectedLocalBranchIndex();
if (idx == -1)
QModelIndex selected = selectedIndex();
Q_ASSERT(selected != m_model->currentBranch()); // otherwise the button would not be enabled!
QString branchName = m_model->branchName(selected);
if (branchName.isEmpty())
return;
const QString name = m_localModel->branchName(idx);
if (!ask(tr("Delete Branch"), tr("Would you like to delete the branch '%1'?").arg(name), true))
return;
QString errorMessage;
bool ok = false;
do {
QString output;
QStringList args(QLatin1String("-D"));
args << name;
if (!gitClient()->synchronousBranchCmd(m_repository, args, &output, &errorMessage))
break;
if (!m_localModel->refresh(m_repository, &errorMessage))
break;
ok = true;
} while (false);
slotEnableButtons();
if (!ok)
QMessageBox::warning(this, tr("Failed to delete branch"), errorMessage);
QString message = tr("Would you like to delete the branch '%1'?").arg(branchName);
bool wasMerged = m_model->branchIsMerged(selected);
if (!wasMerged)
message = tr("Would you like to delete the <b>unmerged</b> branch '%1'?").arg(branchName);
if (QMessageBox::question(this, tr("Delete Branch"), message, QMessageBox::Yes|QMessageBox::No,
wasMerged ? QMessageBox::Yes : QMessageBox::No) == QMessageBox::Yes)
m_model->removeBranch(selected);
}
void BranchDialog::slotCreateLocalBranch(const QString &branchName)
void BranchDialog::diff()
{
// Create
QString output;
QString errorMessage;
bool ok = false;
do {
if (!gitClient()->synchronousBranchCmd(m_repository, QStringList(branchName), &output, &errorMessage))
break;
if (!m_localModel->refresh(m_repository, &errorMessage))
break;
ok = true;
} while (false);
if (!ok) {
QMessageBox::warning(this, tr("Failed to create branch"), errorMessage);
QString branchName = m_model->branchName(selectedIndex());
if (branchName.isEmpty())
return;
}
selectLocalBranch(branchName);
GitPlugin::instance()->gitClient()->diffBranch(m_repository, QStringList(), branchName);
}
void BranchDialog::slotLocalBranchActivated()
void BranchDialog::log()
{
if (m_checkoutButton->isEnabled())
m_checkoutButton->animateClick();
}
void BranchDialog::slotDiffSelected()
{
int idx = selectedLocalBranchIndex();
if (idx != -1) {
gitClient()->diffBranch(m_repository, QStringList(), m_localModel->branchName(idx));
QString branchName = m_model->branchName(selectedIndex());
if (branchName.isEmpty())
return;
}
idx = selectedRemoteBranchIndex();
if (idx != -1)
gitClient()->diffBranch(m_repository, QStringList(), m_remoteModel->branchName(idx));
}
void BranchDialog::slotLog()
{
int idx = selectedLocalBranchIndex();
if (idx != -1) {
gitClient()->graphLog(m_repository, m_localModel->branchName(idx));
return;
}
idx = selectedRemoteBranchIndex();
if (idx != -1)
gitClient()->graphLog(m_repository, m_remoteModel->branchName(idx));
}
/* Ask to stash away changes and then close dialog and do an asynchronous
* checkout. */
void BranchDialog::slotCheckoutSelectedBranch()
{
const int idx = selectedLocalBranchIndex();
if (idx == -1)
return;
const QString name = m_localModel->branchName(idx);
QString errorMessage;
switch (gitClient()->ensureStash(m_repository, &errorMessage)) {
case GitClient::StashUnchanged:
case GitClient::Stashed:
case GitClient::NotStashed:
break;
case GitClient::StashCanceled:
return;
case GitClient::StashFailed:
QMessageBox::warning(this, tr("Failed to stash"), errorMessage);
return;
}
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)
{
// Double click on a remote branch (origin/foo): Switch to matching
// local (foo) one or offer to create a tracking branch.
const QString remoteName = m_remoteModel->branchName(i.row());
// build the name of the corresponding local branch
// and look for it in the local model.
const int slashPos = remoteName.indexOf(QLatin1Char('/'));
if (slashPos == -1)
return;
const QString localBranch = remoteName.mid(slashPos + 1);
if (localBranch == QLatin1String("HEAD") || localBranch == QLatin1String("master"))
return;
const int localIndex = m_localModel->findBranchByName(localBranch);
if (debug)
qDebug() << Q_FUNC_INFO << remoteName << localBranch << localIndex;
// There is a matching a local one!
if (localIndex != -1) {
// Is it the current one? Just close.
if (m_localModel->currentBranch() == localIndex) {
accept();
return;
}
// Nope, select and trigger checkout
selectListRow(m_ui->localBranchListView, localIndex);
slotLocalBranchActivated();
return;
}
// Does not exist yet. Ask to create.
const QString msg = tr("Would you like to create a local branch '%1' tracking the remote branch '%2'?").arg(localBranch, remoteName);
if (!ask(tr("Create branch"), msg, true))
return;
QStringList args(QLatin1String("--track"));
args << localBranch << remoteName;
QString errorMessage;
bool ok = false;
do {
QString output;
if (!gitClient()->synchronousBranchCmd(m_repository, args, &output, &errorMessage))
break;
if (!m_localModel->refresh(m_repository, &errorMessage))
break;
ok = true;
} while (false);
if (!ok) {
QMessageBox::warning(this, tr("Failed to create a tracking branch"), errorMessage);
return;
}
// Select it
selectLocalBranch(localBranch);
GitPlugin::instance()->gitClient()->graphLog(m_repository, branchName);
}
void BranchDialog::changeEvent(QEvent *e)
@@ -369,5 +204,13 @@ void BranchDialog::changeEvent(QEvent *e)
}
}
QModelIndex BranchDialog::selectedIndex()
{
QModelIndexList selected = m_ui->branchView->selectionModel()->selectedIndexes();
if (selected.isEmpty())
return QModelIndex();
return selected.at(0);
}
} // namespace Internal
} // namespace Git

View File

@@ -48,9 +48,8 @@ namespace Ui {
class BranchDialog;
}
class GitClient;
class LocalBranchModel;
class RemoteBranchModel;
class BranchAddDialog;
class BranchModel;
/**
* Branch dialog. Displays a list of local branches at the top and remote
@@ -59,44 +58,33 @@ class RemoteBranchModel;
*/
class BranchDialog : public QDialog {
Q_OBJECT
Q_DISABLE_COPY(BranchDialog)
public:
explicit BranchDialog(QWidget *parent = 0);
virtual ~BranchDialog();
~BranchDialog();
public slots:
void refresh(const QString &repository, bool force);
private slots:
void slotEnableButtons(const QItemSelection &selected = QItemSelection());
void slotCheckoutSelectedBranch();
void slotDeleteSelectedBranch();
void slotDiffSelected();
void slotLog();
void slotRefresh();
void slotLocalBranchActivated();
void slotRemoteBranchActivated(const QModelIndex &);
void slotCreateLocalBranch(const QString &branchName);
void enableButtons();
void refresh();
void add();
void checkout();
void remove();
void diff();
void log();
protected:
virtual void changeEvent(QEvent *e);
void changeEvent(QEvent *e);
private:
bool ask(const QString &title, const QString &what, bool defaultButton);
void selectLocalBranch(const QString &b);
int selectedLocalBranchIndex() const;
int selectedRemoteBranchIndex() const;
QModelIndex selectedIndex();
Ui::BranchDialog *m_ui;
QPushButton *m_checkoutButton;
QPushButton *m_diffButton;
QPushButton *m_logButton;
QPushButton *m_refreshButton;
QPushButton *m_deleteButton;
LocalBranchModel *m_localModel;
RemoteBranchModel *m_remoteModel;
BranchModel *m_model;
QString m_repository;
};

View File

@@ -16,14 +16,33 @@
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="infoGroupBox">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<item>
<widget class="QLabel" name="repositoryLabel">
<property name="text">
<string notr="true">Repository: Dummy</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="refreshButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Re&amp;fresh</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -32,21 +51,63 @@
<property name="title">
<string>Branches</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListView" name="localBranchListView"/>
<layout class="QGridLayout" name="gridLayout">
<property name="topMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="verticalSpacing">
<number>9</number>
</property>
<item row="0" column="0" colspan="3">
<widget class="QTreeView" name="branchView">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="remoteBranchGroupBox">
<property name="title">
<string>Remote Branches</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QListView" name="remoteBranchListView"/>
<item row="1" column="0">
<widget class="QPushButton" name="addButton">
<property name="text">
<string>&amp;Add...</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="removeButton">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="diffButton">
<property name="text">
<string>&amp;Diff</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="logButton">
<property name="text">
<string>&amp;Log</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="checkoutButton">
<property name="text">
<string>&amp;Checkout</string>
</property>
</widget>
</item>
</layout>
</widget>
@@ -63,6 +124,16 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>branchView</tabstop>
<tabstop>addButton</tabstop>
<tabstop>checkoutButton</tabstop>
<tabstop>removeButton</tabstop>
<tabstop>diffButton</tabstop>
<tabstop>logButton</tabstop>
<tabstop>buttonBox</tabstop>
<tabstop>refreshButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>

View File

@@ -33,97 +33,540 @@
#include "branchmodel.h"
#include "gitclient.h"
#include <vcsbase/vcsbaseoutputwindow.h>
#include <QtGui/QFont>
#include <QtCore/QDebug>
#include <QtCore/QRegExp>
#include <QtCore/QTimer>
enum { debug = 0 };
namespace Git {
namespace Internal {
namespace Internal {
// Parse a branch line: " *name sha description".
bool RemoteBranchModel::Branch::parse(const QString &lineIn, bool *isCurrent)
// --------------------------------------------------------------------------
// BranchNode:
// --------------------------------------------------------------------------
class BranchNode
{
if (debug)
qDebug() << Q_FUNC_INFO << lineIn;
public:
BranchNode() :
parent(0), current(false)
{ }
*isCurrent = lineIn.startsWith(QLatin1String("* "));
if (lineIn.size() < 3)
BranchNode(const QString &n, const QString &s = QString(), bool c = false) :
parent(0), current(c), name(n), sha(s)
{ }
~BranchNode()
{
qDeleteAll(children);
}
BranchNode *rootNode()
{
return parent ? parent->rootNode() : this;
}
int count()
{
return children.count();
}
bool isLeaf()
{
return children.isEmpty();
}
bool childOf(BranchNode *node)
{
if (this == node)
return true;
return parent ? parent->childOf(node) : false;
}
bool isLocal()
{
BranchNode *rn = rootNode();
if (rn->isLeaf())
return false;
return childOf(rn->children.at(0));
}
BranchNode *childOfName(const QString &name)
{
for (int i = 0; i < children.count(); ++i) {
if (children.at(i)->name == name)
return children.at(i);
}
return 0;
}
QStringList fullName()
{
Q_ASSERT(isLeaf());
QStringList fn;
QList<BranchNode *> nodes;
BranchNode *current = this;
while (current->parent) {
nodes.prepend(current);
current = current->parent;
}
if (current->children.at(0) == nodes.at(0))
nodes.removeFirst(); // remove local branch designation
foreach (BranchNode *n, nodes)
fn.append(n->name);
return fn;
}
void insert(const QStringList path, BranchNode *n)
{
BranchNode *current = this;
for (int i = 0; i < path.count(); ++i) {
BranchNode *c = current->childOfName(path.at(i));
if (c)
current = c;
else
current = current->append(new BranchNode(path.at(i)));
}
current->append(n);
}
BranchNode *append(BranchNode *n)
{
n->parent = this;
children.append(n);
return n;
}
QStringList childrenNames()
{
if (children.count() > 0) {
QStringList names;
foreach (BranchNode *n, children) {
names.append(n->childrenNames());
}
return names;
}
return QStringList(fullName().join(QString('/')));
}
BranchNode *parent;
QList<BranchNode *> children;
bool current;
QString name;
QString sha;
mutable QString toolTip;
};
// --------------------------------------------------------------------------
// BranchModel:
// --------------------------------------------------------------------------
BranchModel::BranchModel(GitClient *client, QObject *parent) :
QAbstractItemModel(parent),
m_client(client),
m_rootNode(new BranchNode)
{
Q_ASSERT(m_client);
m_rootNode->append(new BranchNode(tr("Local Branches")));
}
BranchModel::~BranchModel()
{
delete m_rootNode;
}
QModelIndex BranchModel::index(int row, int column, const QModelIndex &parent) const
{
BranchNode *node = m_rootNode;
if (parent.isValid())
node = static_cast<BranchNode *>(parent.internalPointer());
if (row >= node->count())
return QModelIndex();
return createIndex(row, column, static_cast<void *>(node->children.at(row)));
}
QModelIndex BranchModel::parent(const QModelIndex &index) const
{
BranchNode *node = static_cast<BranchNode *>(index.internalPointer());
if (node->parent == m_rootNode)
return QModelIndex();
int row = node->parent->children.indexOf(node);
return createIndex(row, 0, static_cast<void *>(node->parent));
}
int BranchModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid())
return m_rootNode->count();
if (parent.column() != 0)
return 0;
return static_cast<BranchNode *>(parent.internalPointer())->count();
}
int BranchModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 1;
}
QVariant BranchModel::data(const QModelIndex &index, int role) const
{
BranchNode *node = static_cast<BranchNode *>(index.internalPointer());
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole:
return node->name;
case Qt::ToolTipRole:
if (!node->isLeaf())
return QVariant();
if (node->toolTip.isEmpty())
node->toolTip = toolTip(node->sha);
return node->toolTip;
case Qt::FontRole:
{
QFont font;
if (!node->isLeaf()) {
font.setBold(true);
} else if (node->current) {
font.setBold(true);
font.setUnderline(true);
}
return font;
}
default:
return QVariant();
}
}
bool BranchModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Qt::EditRole)
return false;
BranchNode *node = static_cast<BranchNode *>(index.internalPointer());
const QString newName = value.toString();
if (newName.isEmpty())
return false;
const QString branchInfo = lineIn.mid(2);
QStringList tokens;
if (*isCurrent && branchInfo.startsWith(QLatin1String("(no branch)")))
if (node->name == newName)
return true;
QStringList oldFullName = node->fullName();
node->name = newName;
QStringList newFullName = node->fullName();
QString output;
QString errorMessage;
if (!m_client->synchronousBranchCmd(m_workingDirectory,
QStringList() << QLatin1String("-m")
<< oldFullName.last()
<< newFullName.last(),
&output, &errorMessage)) {
node->name = oldFullName.last();
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
return false;
else
tokens = branchInfo.split(QLatin1Char(' '), QString::SkipEmptyParts);
if (tokens.size() < 2)
return false;
name = tokens.at(0);
currentSHA= tokens.at(1);
toolTip.clear();
}
emit dataChanged(index, index);
return true;
}
// ------ RemoteBranchModel
RemoteBranchModel::RemoteBranchModel(GitClient *client, QObject *parent) :
QAbstractListModel(parent),
m_flags(Qt::ItemIsSelectable|Qt::ItemIsEnabled),
m_client(client)
Qt::ItemFlags BranchModel::flags(const QModelIndex &index) const
{
BranchNode *node = static_cast<BranchNode *>(index.internalPointer());
if (node->isLeaf() && node->isLocal())
return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
else
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
bool RemoteBranchModel::refresh(const QString &workingDirectory, QString *errorMessage)
void BranchModel::clear()
{
int currentBranch;
return refreshBranches(workingDirectory, true, &currentBranch, errorMessage);
while (m_rootNode->count() > 1) {
BranchNode *n = m_rootNode->children.takeLast();
delete n;
}
BranchNode *locals = m_rootNode->children.at(0);
while (locals->count()) {
BranchNode *n = locals->children.takeLast();
delete n;
}
}
QString RemoteBranchModel::branchName(int row) const
bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage)
{
return m_branches.at(row).name;
if (workingDirectory.isEmpty())
return false;
QStringList branchArgs;
branchArgs << QLatin1String(GitClient::noColorOption)
<< QLatin1String("-v") << QLatin1String("-a");
QString output;
if (!m_client->synchronousBranchCmd(workingDirectory, branchArgs, &output, errorMessage)) {
VCSBase::VCSBaseOutputWindow::instance()->appendError(*errorMessage);
return false;
}
beginResetModel();
clear();
m_workingDirectory = workingDirectory;
const QStringList lines = output.split(QLatin1Char('\n'));
foreach (const QString &l, lines)
parseOutputLine(l);
endResetModel();
return true;
}
QString RemoteBranchModel::workingDirectory() const
void BranchModel::renameBranch(const QString &oldName, const QString &newName)
{
QString errorMessage;
QString output;
if (!m_client->synchronousBranchCmd(m_workingDirectory,
QStringList() << QLatin1String("-m") << oldName << newName,
&output, &errorMessage))
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
else
refresh(m_workingDirectory, &errorMessage);
}
QString BranchModel::workingDirectory() const
{
return m_workingDirectory;
}
int RemoteBranchModel::branchCount() const
GitClient *BranchModel::client() const
{
return m_branches.size();
return m_client;
}
int RemoteBranchModel::rowCount(const QModelIndex & /* parent */) const
QModelIndex BranchModel::currentBranch() const
{
return branchCount();
}
QVariant RemoteBranchModel::data(const QModelIndex &index, int role) const
{
const int row = index.row();
switch (role) {
case Qt::DisplayRole:
return branchName(row);
case Qt::ToolTipRole:
if (m_branches.at(row).toolTip.isEmpty())
m_branches.at(row).toolTip = toolTip(m_branches.at(row).currentSHA);
return m_branches.at(row).toolTip;
break;
default:
break;
if (!m_rootNode || !m_rootNode->count())
return QModelIndex();
BranchNode *localBranches = m_rootNode->children.at(0);
QModelIndex localIdx = index(0, 0, QModelIndex());
for (int i = 0; i < localBranches->count(); ++i) {
if (localBranches->children.at(i)->current)
return index(i, 0, localIdx);
}
return QVariant();
return QModelIndex();
}
Qt::ItemFlags RemoteBranchModel::flags(const QModelIndex & /* index */) const
QString BranchModel::branchName(const QModelIndex &idx) const
{
return m_flags;
if (!idx.isValid())
return QString();
BranchNode *node = static_cast<BranchNode *>(idx.internalPointer());
if (!node->isLeaf())
return QString();
QStringList path = node->fullName();
return path.join(QString('/'));
}
QString RemoteBranchModel::toolTip(const QString &sha) const
QStringList BranchModel::localBranchNames() const
{
if (!m_rootNode || m_rootNode->children.isEmpty())
return QStringList();
return m_rootNode->children.at(0)->childrenNames();
}
QString BranchModel::sha(const QModelIndex &idx) const
{
if (!idx.isValid())
return QString();
BranchNode *node = static_cast<BranchNode *>(idx.internalPointer());
return node->sha;
}
bool BranchModel::isLocal(const QModelIndex &idx) const
{
if (!idx.isValid())
return false;
BranchNode *node = static_cast<BranchNode *>(idx.internalPointer());
return node->isLocal();
}
bool BranchModel::isLeaf(const QModelIndex &idx) const
{
if (!idx.isValid())
return false;
BranchNode *node = static_cast<BranchNode *>(idx.internalPointer());
return node->isLeaf();
}
void BranchModel::removeBranch(const QModelIndex &idx)
{
QString branch = branchName(idx);
if (branch.isEmpty())
return;
QString errorMessage;
QString output;
QStringList args;
args << QLatin1String("-D") << branch;
if (!m_client->synchronousBranchCmd(m_workingDirectory, args, &output, &errorMessage)) {
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
return;
}
QModelIndex parentIdx = parent(idx);
beginRemoveRows(parentIdx, idx.row(), idx.row());
static_cast<BranchNode *>(parentIdx.internalPointer())->children.removeAt(parentIdx.row());
delete static_cast<BranchNode *>(idx.internalPointer());
endRemoveRows();
}
void BranchModel::checkoutBranch(const QModelIndex &idx)
{
QString branch = branchName(idx);
if (branch.isEmpty())
return;
QString errorMessage;
switch (m_client->ensureStash(m_workingDirectory, &errorMessage)) {
case GitClient::StashUnchanged:
case GitClient::Stashed:
case GitClient::NotStashed:
break;
case GitClient::StashCanceled:
return;
case GitClient::StashFailed:
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
return;
}
if (m_client->synchronousCheckoutBranch(m_workingDirectory, branch, &errorMessage)) {
if (errorMessage.isEmpty()) {
static_cast<BranchNode *>(currentBranch().internalPointer())->current = false;
emit dataChanged(currentBranch(), currentBranch());
static_cast<BranchNode *>(idx.internalPointer())->current = true;
emit dataChanged(idx, idx);
} else {
refresh(m_workingDirectory, &errorMessage); // not sure all went well... better refresh!
}
}
if (!errorMessage.isEmpty())
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
}
bool BranchModel::branchIsMerged(const QModelIndex &idx)
{
QString branch = branchName(idx);
if (branch.isEmpty())
return false;
QString errorMessage;
QString output;
QStringList args;
args << QLatin1String("--contains") << sha(idx);
if (!m_client->synchronousBranchCmd(m_workingDirectory, args, &output, &errorMessage)) {
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
return false;
}
QStringList lines = output.split(QLatin1Char('/'), QString::SkipEmptyParts);
foreach (const QString &l, lines) {
if (l.startsWith(QLatin1String(" ")) && l.count() >= 3)
return true;
}
return false;
}
QModelIndex BranchModel::addBranch(const QString &branchName, bool track, const QString &startPoint)
{
if (!m_rootNode || !m_rootNode->count())
return QModelIndex();
QString output;
QString errorMessage;
QStringList args;
args << (track ? QLatin1String("--track") : QLatin1String("--no-track"));
args << branchName << startPoint;
if (!m_client->synchronousBranchCmd(m_workingDirectory, args, &output, &errorMessage)) {
VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
return QModelIndex();
}
BranchNode *local = m_rootNode->children.at(0);
int pos = 0;
for (pos = 0; pos < local->count(); ++pos) {
if (local->children.at(pos)->name > branchName)
break;
}
BranchNode *newNode = new BranchNode(branchName);
// find the sha of the new branch:
output = toolTip(branchName); // abuse toolTip to get the data;-)
QStringList lines = output.split(QLatin1Char('\n'));
foreach (const QString &l, lines) {
if (l.startsWith("commit ")) {
newNode->sha = l.mid(7, 8);
break;
}
}
beginInsertRows(index(0, 0), pos, pos);
newNode->parent = local;
local->children.insert(pos, newNode);
endInsertRows();
return index(pos, 0, index(0, 0));
}
void BranchModel::parseOutputLine(const QString &line)
{
if (line.size() < 3)
return;
bool current = line.startsWith(QLatin1String("* "));
const QString branchInfo = line.mid(2);
if (current && branchInfo.startsWith(QLatin1String("(no branch)")))
return;
QStringList tokens = branchInfo.split(QLatin1Char(' '), QString::SkipEmptyParts);
if (tokens.size() < 2)
return;
QString sha = tokens.at(1);
// insert node into tree:
QStringList nameParts = tokens.at(0).split(QLatin1Char('/'));
if (nameParts.count() < 1)
return;
QString name = nameParts.last();
nameParts.removeLast();
if (nameParts.isEmpty() || nameParts.at(0) != QLatin1String("remotes")) {
// local branch:
while (nameParts.count() > 2)
nameParts[1] = nameParts.at(1) + QLatin1Char('/') + nameParts.at(2);
m_rootNode->children.at(0)->insert(nameParts, new BranchNode(name, sha, current));
} else {
// remote branch:
nameParts.removeFirst(); // remove "remotes"
while (nameParts.count() > 2)
nameParts[1] = nameParts.at(1) + QLatin1Char('/') + nameParts.at(2);
m_rootNode->insert(nameParts, new BranchNode(name, sha, current));
}
}
QString BranchModel::toolTip(const QString &sha) const
{
// Show the sha description excluding diff as toolTip
QString output;
@@ -137,156 +580,6 @@ QString RemoteBranchModel::toolTip(const QString &sha) const
return output;
}
bool RemoteBranchModel::runGitBranchCommand(const QString &workingDirectory, const QStringList &additionalArgs, QString *output, QString *errorMessage)
{
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)
{
// Run branch command with verbose.
QStringList branchArgs;
branchArgs << QLatin1String(GitClient::noColorOption) << QLatin1String("-v");
QString output;
*currentBranch = -1;
if (remoteBranches)
branchArgs.push_back(QLatin1String("-r"));
if (!runGitBranchCommand(workingDirectory, branchArgs, &output, errorMessage))
return false;
if (debug)
qDebug() << Q_FUNC_INFO << workingDirectory << output;
// Parse output
m_workingDirectory = workingDirectory;
m_branches.clear();
const QStringList branches = output.split(QLatin1Char('\n'));
const int branchCount = branches.size();
bool isCurrent;
for (int b = 0; b < branchCount; b++) {
Branch newBranch;
if (newBranch.parse(branches.at(b), &isCurrent)) {
m_branches.push_back(newBranch);
if (isCurrent)
*currentBranch = b;
}
}
reset();
return true;
}
int RemoteBranchModel::findBranchByName(const QString &name) const
{
const int count = branchCount();
for (int i = 0; i < count; i++)
if (branchName(i) == name)
return i;
return -1;
}
// --- LocalBranchModel
LocalBranchModel::LocalBranchModel(GitClient *client, QObject *parent) :
RemoteBranchModel(client, parent),
m_typeHere(tr("<New branch>")),
m_typeHereToolTip(tr("Type to create a new branch")),
m_currentBranch(-1)
{
}
int LocalBranchModel::currentBranch() const
{
return m_currentBranch;
}
bool LocalBranchModel::isNewBranchRow(int row) const
{
return row >= branchCount();
}
Qt::ItemFlags LocalBranchModel::flags(const QModelIndex & index) const
{
if (isNewBranchRow(index))
return Qt::ItemIsEditable|Qt::ItemIsSelectable|Qt::ItemIsEnabled| Qt::ItemIsUserCheckable;
return RemoteBranchModel::flags(index) | Qt::ItemIsUserCheckable;
}
int LocalBranchModel::rowCount(const QModelIndex & /* parent */) const
{
return branchCount() + 1;
}
QVariant LocalBranchModel::data(const QModelIndex &index, int role) const
{
if (isNewBranchRow(index)) {
switch (role) {
case Qt::DisplayRole:
return m_typeHere;
case Qt::ToolTipRole:
return m_typeHereToolTip;
}
return QVariant();
}
if (role == Qt::FontRole && index.row() == m_currentBranch) {
QFont font = RemoteBranchModel::data(index, role).value<QFont>();
font.setBold(true);
font.setUnderline(true);
return font;
}
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);
}
bool LocalBranchModel::checkNewBranchName(const QString &name) const
{
// Syntax
const QRegExp pattern(QLatin1String("[a-zA-Z0-9-_]+"));
if (!pattern.exactMatch(name))
return false;
// existing
if (findBranchByName(name) != -1)
return false;
return true;
}
bool LocalBranchModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
// Verify
if (role != Qt::EditRole || index.row() < branchCount())
return false;
const QString branchName = value.toString();
// Delay the signal as we don't want ourselves to be reset while
// in setData().
if (checkNewBranchName(branchName)) {
m_newBranch = branchName;
QTimer::singleShot(0, this, SLOT(slotNewBranchDelayedRefresh()));
}
return true;
}
void LocalBranchModel::slotNewBranchDelayedRefresh()
{
emit newBranchEntered(m_newBranch);
}
}
}
} // namespace Internal
} // namespace Git

View File

@@ -38,105 +38,63 @@
#include <QtCore/QVariant>
namespace Git {
namespace Internal {
namespace Internal {
class GitClient;
/* A read-only model to list git remote branches in a simple list of branch names.
* The tooltip describes the latest commit (delayed creation).
* Provides virtuals to be able to derive a local branch model with the notion
* of a "current branch". */
class BranchNode;
class RemoteBranchModel : public QAbstractListModel {
// --------------------------------------------------------------------------
// BranchModel:
// --------------------------------------------------------------------------
class BranchModel : public QAbstractItemModel {
Q_OBJECT
public:
explicit RemoteBranchModel(GitClient *client, QObject *parent = 0);
explicit BranchModel(GitClient *client, QObject *parent = 0);
~BranchModel();
virtual void clear();
virtual bool refresh(const QString &workingDirectory, QString *errorMessage);
// QAbstractItemModel
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex &index) const;
QString branchName(int row) const;
void clear();
bool refresh(const QString &workingDirectory, QString *errorMessage);
// QAbstractListModel
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
int branchCount() const;
void renameBranch(const QString &oldName, const QString &newName);
QString workingDirectory() const;
int findBranchByName(const QString &name) const;
GitClient *client() const;
protected:
struct Branch {
bool parse(const QString &line, bool *isCurrent);
QModelIndex currentBranch() const;
QString branchName(const QModelIndex &idx) const;
QStringList localBranchNames() const;
QString sha(const QModelIndex &idx) const;
bool isLocal(const QModelIndex &idx) const;
bool isLeaf(const QModelIndex &idx) const;
QString name;
QString currentSHA;
mutable QString toolTip;
};
typedef QList<Branch> BranchList;
/* Parse git output and populate m_branches. */
bool refreshBranches(const QString &workingDirectory, bool remoteBranches,
int *currentBranch, QString *errorMessage);
bool runGitBranchCommand(const QString &workingDirectory, const QStringList &additionalArgs, QString *output, QString *errorMessage);
void removeBranch(const QModelIndex &idx);
void checkoutBranch(const QModelIndex &idx);
bool branchIsMerged(const QModelIndex &idx);
QModelIndex addBranch(const QString &branchName, bool track, const QString &trackedBranch);
private:
QString toolTip(const QString &sha) const;
void parseOutputLine(const QString &line);
const Qt::ItemFlags m_flags;
QString toolTip(const QString &sha) const;
GitClient *m_client;
QString m_workingDirectory;
BranchList m_branches;
BranchNode *m_rootNode;
};
/* LocalBranchModel: Extends RemoteBranchModel by a read-only
* checkable column indicating the current branch. Provides an
* editable "Type here" new-branch-row at the bottom to create
* a new branch. */
class LocalBranchModel : public RemoteBranchModel {
Q_OBJECT
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?
bool isNewBranchRow(int row) const;
bool isNewBranchRow(const QModelIndex & index) const { return isNewBranchRow(index.row()); }
int currentBranch() const;
// QAbstractListModel
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
signals:
void newBranchCreated(const QString &);
void newBranchEntered(const QString &);
private slots:
void slotNewBranchDelayedRefresh();
private:
bool checkNewBranchName(const QString &name) const;
const QVariant m_typeHere;
const QVariant m_typeHereToolTip;
int m_currentBranch;
QString m_newBranch;
};
}
}
} // namespace Internal
} // namespace Git
#endif // BRANCHMODEL_H

View File

@@ -27,6 +27,7 @@ HEADERS += gitplugin.h \
gitutils.h \
remotemodel.h \
remotedialog.h \
branchadddialog.h
SOURCES += gitplugin.cpp \
gitclient.cpp \
@@ -48,6 +49,7 @@ SOURCES += gitplugin.cpp \
gitutils.cpp \
remotemodel.cpp \
remotedialog.cpp \
branchadddialog.cpp
FORMS += changeselectiondialog.ui \
settingspage.ui \
@@ -56,8 +58,12 @@ FORMS += changeselectiondialog.ui \
stashdialog.ui \
remotedialog.ui \
remoteadditiondialog.ui \
branchadddialog.ui
include(gitorious/gitorious.pri)
RESOURCES += \
git.qrc