Newer
Older
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
**
**************************************************************************/
#include "branchmodel.h"
#include "gitclient.h"
#include <QtCore/QDebug>
#include <QtCore/QRegExp>
#include <QtCore/QTimer>
enum { debug = 0 };
namespace Git {
namespace Internal {
// Parse a branch line: " *name sha description". Return true if it is
// the current one
bool RemoteBranchModel::Branch::parse(const QString &lineIn, bool *isCurrent)
{
if (debug)
qDebug() << Q_FUNC_INFO << lineIn;
*isCurrent = lineIn.startsWith(QLatin1String("* "));
if (lineIn.size() < 3)
return false;
const QStringList tokens =lineIn.mid(2).split(QLatin1Char(' '), QString::SkipEmptyParts);
if (tokens.size() < 2)
return false;
name = tokens.at(0);
currentSHA= tokens.at(1);
toolTip.clear();
return true;
}
// ------ RemoteBranchModel
RemoteBranchModel::RemoteBranchModel(GitClient *client, QObject *parent) :
QAbstractListModel(parent),
m_flags(Qt::ItemIsSelectable|Qt::ItemIsEnabled),
m_client(client)
bool RemoteBranchModel::refresh(const QString &workingDirectory, QString *errorMessage)
int currentBranch;
return refreshBranches(workingDirectory, true, ¤tBranch, errorMessage);
QString RemoteBranchModel::branchName(int row) const
return m_branches.at(row).name;
QString RemoteBranchModel::workingDirectory() const
return m_workingDirectory;
int RemoteBranchModel::branchCount() const
{
return m_branches.size();
}
int RemoteBranchModel::rowCount(const QModelIndex & /* parent */) 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;
}
return QVariant();
}
Qt::ItemFlags RemoteBranchModel::flags(const QModelIndex & /* index */) const
QString RemoteBranchModel::toolTip(const QString &sha) const
{
// Show the sha description excluding diff as toolTip
QString output;
QString errorMessage;
if (!m_client->synchronousShow(m_workingDirectory, sha, &output, &errorMessage))
return errorMessage;
// Remove 'diff' output
const int diffPos = output.indexOf(QLatin1String("\ndiff --"));
if (diffPos != -1)
output.remove(diffPos, output.size() - diffPos);
return output;
}
bool RemoteBranchModel::runGitBranchCommand(const QString &workingDirectory, const QStringList &additionalArgs, QString *output, QString *errorMessage)
{
return m_client->synchronousBranchCmd(workingDirectory, additionalArgs, output, errorMessage);
}
bool RemoteBranchModel::refreshBranches(const QString &workingDirectory, bool remoteBranches,
int *currentBranch, QString *errorMessage)
{
// Run branch command with verbose.

Friedemann Kleint
committed
QStringList branchArgs;
branchArgs << QLatin1String(GitClient::noColorOption) << QLatin1String("-v");
*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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
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;
case Qt::CheckStateRole:
return QVariant(false);
}
return QVariant();
}
if (role == Qt::CheckStateRole)
return index.row() == m_currentBranch ? Qt::Checked : Qt::Unchecked;
return RemoteBranchModel::data(index, role);
}
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 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);