forked from qt-creator/qt-creator
Fixes: Use a model for the submit file list (to resolve the git diff mess)
This commit is contained in:
@@ -32,8 +32,12 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "commitdata.h"
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QRegExp>
|
||||
|
||||
const char *const kBranchIndicatorC = "# On branch";
|
||||
|
||||
namespace Git {
|
||||
namespace Internal {
|
||||
@@ -85,6 +89,130 @@ void CommitData::clear()
|
||||
untrackedFiles.clear();
|
||||
}
|
||||
|
||||
// Split a state/file spec from git status output
|
||||
// '#<tab>modified:<blanks>git .pro'
|
||||
// into state and file ('modified', 'git .pro').
|
||||
CommitData::StateFilePair splitStateFileSpecification(const QString &line)
|
||||
{
|
||||
QPair<QString, QString> rc;
|
||||
const int statePos = 2;
|
||||
const int colonIndex = line.indexOf(QLatin1Char(':'), statePos);
|
||||
if (colonIndex == -1)
|
||||
return rc;
|
||||
rc.first = line.mid(statePos, colonIndex - statePos);
|
||||
int filePos = colonIndex + 1;
|
||||
const QChar blank = QLatin1Char(' ');
|
||||
while (line.at(filePos) == blank)
|
||||
filePos++;
|
||||
if (filePos < line.size())
|
||||
rc.second = line.mid(filePos, line.size() - filePos);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Convenience to add a state/file spec to a list
|
||||
static inline bool addStateFileSpecification(const QString &line, QList<CommitData::StateFilePair> *list)
|
||||
{
|
||||
const CommitData::StateFilePair sf = splitStateFileSpecification(line);
|
||||
if (sf.first.isEmpty() || sf.second.isEmpty())
|
||||
return false;
|
||||
list->push_back(sf);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Parse a git status file list:
|
||||
* \code
|
||||
# Changes to be committed:
|
||||
#<tab>modified:<blanks>git.pro
|
||||
# Changed but not updated:
|
||||
#<tab>modified:<blanks>git.pro
|
||||
# Untracked files:
|
||||
#<tab>git.pro
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bool CommitData::parseFilesFromStatus(const QString &output)
|
||||
{
|
||||
enum State { None, CommitFiles, NotUpdatedFiles, UntrackedFiles };
|
||||
|
||||
const QStringList lines = output.split(QLatin1Char('\n'));
|
||||
const QString branchIndicator = QLatin1String(kBranchIndicatorC);
|
||||
const QString commitIndicator = QLatin1String("# Changes to be committed:");
|
||||
const QString notUpdatedIndicator = QLatin1String("# Changed but not updated:");
|
||||
const QString untrackedIndicator = QLatin1String("# Untracked files:");
|
||||
|
||||
State s = None;
|
||||
// Match added/changed-not-updated files: "#<tab>modified: foo.cpp"
|
||||
QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+.+"));
|
||||
QTC_ASSERT(filesPattern.isValid(), return false);
|
||||
|
||||
const QStringList::const_iterator cend = lines.constEnd();
|
||||
for (QStringList::const_iterator it = lines.constBegin(); it != cend; ++it) {
|
||||
const QString line = *it;
|
||||
if (line.startsWith(branchIndicator)) {
|
||||
panelInfo.branch = line.mid(branchIndicator.size() + 1);
|
||||
} else {
|
||||
if (line.startsWith(commitIndicator)) {
|
||||
s = CommitFiles;
|
||||
} else {
|
||||
if (line.startsWith(notUpdatedIndicator)) {
|
||||
s = NotUpdatedFiles;
|
||||
} else {
|
||||
if (line.startsWith(untrackedIndicator)) {
|
||||
// Now match untracked: "#<tab>foo.cpp"
|
||||
s = UntrackedFiles;
|
||||
filesPattern = QRegExp(QLatin1String("#\\t.+"));
|
||||
QTC_ASSERT(filesPattern.isValid(), return false);
|
||||
} else {
|
||||
if (filesPattern.exactMatch(line)) {
|
||||
switch (s) {
|
||||
case CommitFiles:
|
||||
addStateFileSpecification(line, &stagedFiles);
|
||||
break;
|
||||
case NotUpdatedFiles:
|
||||
addStateFileSpecification(line, &unstagedFiles);
|
||||
break;
|
||||
case UntrackedFiles:
|
||||
untrackedFiles.push_back(line.mid(2).trimmed());
|
||||
break;
|
||||
case None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !stagedFiles.empty() || !unstagedFiles.empty() || !untrackedFiles.empty();
|
||||
}
|
||||
|
||||
// Convert a spec pair list to a list of file names, optionally
|
||||
// filter for a state
|
||||
static QStringList specToFileNames(const QList<CommitData::StateFilePair> &files,
|
||||
const QString &stateFilter)
|
||||
{
|
||||
typedef QList<CommitData::StateFilePair>::const_iterator ConstIterator;
|
||||
if (files.empty())
|
||||
return QStringList();
|
||||
const bool emptyFilter = stateFilter.isEmpty();
|
||||
QStringList rc;
|
||||
const ConstIterator cend = files.constEnd();
|
||||
for (ConstIterator it = files.constBegin(); it != cend; ++it)
|
||||
if (emptyFilter || stateFilter == it->first)
|
||||
rc.push_back(it->second);
|
||||
return rc;
|
||||
}
|
||||
|
||||
QStringList CommitData::stagedFileNames(const QString &stateFilter) const
|
||||
{
|
||||
return specToFileNames(stagedFiles, stateFilter);
|
||||
}
|
||||
|
||||
QStringList CommitData::unstagedFileNames(const QString &stateFilter) const
|
||||
{
|
||||
return specToFileNames(unstagedFiles, stateFilter);
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug d, const CommitData &data)
|
||||
{
|
||||
d << data.panelInfo << data.panelData;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#define COMMITDATA_H
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QPair>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDebug;
|
||||
@@ -68,11 +69,24 @@ QDebug operator<<(QDebug d, const GitSubmitEditorPanelData &);
|
||||
|
||||
struct CommitData
|
||||
{
|
||||
// A pair of state string/file name ('modified', 'file.cpp').
|
||||
typedef QPair<QString, QString> StateFilePair;
|
||||
|
||||
void clear();
|
||||
// Parse the files and the branch of panelInfo
|
||||
// from a git status output
|
||||
bool parseFilesFromStatus(const QString &output);
|
||||
|
||||
// Convenience to retrieve the file names from
|
||||
// the specification list. Optionally filter for a certain state
|
||||
QStringList stagedFileNames(const QString &stateFilter = QString()) const;
|
||||
QStringList unstagedFileNames(const QString &stateFilter = QString()) const;
|
||||
|
||||
GitSubmitEditorPanelInfo panelInfo;
|
||||
GitSubmitEditorPanelData panelData;
|
||||
QStringList stagedFiles;
|
||||
QStringList unstagedFiles;
|
||||
|
||||
QList<StateFilePair> stagedFiles;
|
||||
QList<StateFilePair> unstagedFiles;
|
||||
QStringList untrackedFiles;
|
||||
};
|
||||
|
||||
|
||||
@@ -622,73 +622,6 @@ GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory,
|
||||
return StatusChanged;
|
||||
}
|
||||
|
||||
/* Parse a git status file list:
|
||||
* \code
|
||||
# Changes to be committed:
|
||||
#<tab>modified:<blanks>git.pro
|
||||
# Changed but not updated:
|
||||
#<tab>modified:<blanks>git.pro
|
||||
# Untracked files:
|
||||
#<tab>git.pro
|
||||
\endcode
|
||||
*/
|
||||
static bool parseFiles(const QString &output, CommitData *d)
|
||||
{
|
||||
enum State { None, CommitFiles, NotUpdatedFiles, UntrackedFiles };
|
||||
|
||||
const QStringList lines = output.split(QLatin1Char('\n'));
|
||||
const QString branchIndicator = QLatin1String(kBranchIndicatorC);
|
||||
const QString commitIndicator = QLatin1String("# Changes to be committed:");
|
||||
const QString notUpdatedIndicator = QLatin1String("# Changed but not updated:");
|
||||
const QString untrackedIndicator = QLatin1String("# Untracked files:");
|
||||
|
||||
State s = None;
|
||||
// Match added/changed-not-updated files: "#<tab>modified: foo.cpp"
|
||||
QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+.+"));
|
||||
QTC_ASSERT(filesPattern.isValid(), return false);
|
||||
|
||||
const QStringList::const_iterator cend = lines.constEnd();
|
||||
for (QStringList::const_iterator it = lines.constBegin(); it != cend; ++it) {
|
||||
const QString line = *it;
|
||||
if (line.startsWith(branchIndicator)) {
|
||||
d->panelInfo.branch = line.mid(branchIndicator.size() + 1);
|
||||
} else {
|
||||
if (line.startsWith(commitIndicator)) {
|
||||
s = CommitFiles;
|
||||
} else {
|
||||
if (line.startsWith(notUpdatedIndicator)) {
|
||||
s = NotUpdatedFiles;
|
||||
} else {
|
||||
if (line.startsWith(untrackedIndicator)) {
|
||||
// Now match untracked: "#<tab>foo.cpp"
|
||||
s = UntrackedFiles;
|
||||
filesPattern = QRegExp(QLatin1String("#\\t.+"));
|
||||
QTC_ASSERT(filesPattern.isValid(), return false);
|
||||
} else {
|
||||
if (filesPattern.exactMatch(line)) {
|
||||
const QString fileSpec = line.mid(2).trimmed();
|
||||
switch (s) {
|
||||
case CommitFiles:
|
||||
d->stagedFiles.push_back(trimFileSpecification(fileSpec));
|
||||
break;
|
||||
case NotUpdatedFiles:
|
||||
d->unstagedFiles.push_back(trimFileSpecification(fileSpec));
|
||||
break;
|
||||
case UntrackedFiles:
|
||||
d->untrackedFiles.push_back(fileSpec);
|
||||
break;
|
||||
case None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !d->stagedFiles.empty() || !d->unstagedFiles.empty() || !d->untrackedFiles.empty();
|
||||
}
|
||||
|
||||
// Filter out untracked files that are not part of the project
|
||||
static void filterUntrackedFilesOfProject(const QString &repoDir, QStringList *l)
|
||||
{
|
||||
@@ -771,20 +704,12 @@ bool GitClient::getCommitData(const QString &workingDirectory,
|
||||
// #
|
||||
// # list of files...
|
||||
|
||||
if (!parseFiles(output, d)) {
|
||||
if (!d->parseFilesFromStatus(output)) {
|
||||
*errorMessage = msgParseFilesFailed();
|
||||
return false;
|
||||
}
|
||||
// Filter out untracked files that are not part of the project and,
|
||||
// for symmetry, insert the prefix "untracked:" (as "added:" or ":modified"
|
||||
// for staged files).
|
||||
// Filter out untracked files that are not part of the project
|
||||
filterUntrackedFilesOfProject(repoDirectory, &d->untrackedFiles);
|
||||
if (!d->untrackedFiles.empty()) {
|
||||
const QString untrackedPrefix = QLatin1String("untracked: ");
|
||||
const QStringList::iterator pend = d->untrackedFiles.end();
|
||||
for (QStringList::iterator it = d->untrackedFiles.begin(); it != pend; ++it)
|
||||
it->insert(0, untrackedPrefix);
|
||||
}
|
||||
|
||||
d->panelData.author = readConfigValue(workingDirectory, QLatin1String("user.name"));
|
||||
d->panelData.email = readConfigValue(workingDirectory, QLatin1String("user.email"));
|
||||
@@ -881,7 +806,7 @@ GitClient::RevertResult GitClient::revertI(QStringList files, bool *ptrToIsDirec
|
||||
return RevertFailed;
|
||||
}
|
||||
CommitData data;
|
||||
if (!parseFiles(output, &data)) {
|
||||
if (!data.parseFilesFromStatus(output)) {
|
||||
*errorMessage = msgParseFilesFailed();
|
||||
return RevertFailed;
|
||||
}
|
||||
@@ -896,9 +821,9 @@ GitClient::RevertResult GitClient::revertI(QStringList files, bool *ptrToIsDirec
|
||||
}
|
||||
|
||||
// From the status output, determine all modified [un]staged files.
|
||||
const QString modifiedPattern = QLatin1String("modified: ");
|
||||
const QStringList allStagedFiles = GitSubmitEditor::statusListToFileList(data.stagedFiles.filter(modifiedPattern));
|
||||
const QStringList allUnstagedFiles = GitSubmitEditor::statusListToFileList(data.unstagedFiles.filter(modifiedPattern));
|
||||
const QString modifiedState = QLatin1String("modified");
|
||||
const QStringList allStagedFiles = data.stagedFileNames(modifiedState);
|
||||
const QStringList allUnstagedFiles = data.unstagedFileNames(modifiedState);
|
||||
// Unless a directory was passed, filter all modified files for the
|
||||
// argument file list.
|
||||
QStringList stagedFiles = allStagedFiles;
|
||||
|
||||
@@ -602,7 +602,7 @@ void GitPlugin::startCommit()
|
||||
// Store repository for diff and the original list of
|
||||
// files to be able to unstage files the user unchecks
|
||||
m_submitRepository = data.panelInfo.repository;
|
||||
m_submitOrigCommitFiles = GitSubmitEditor::statusListToFileList(data.stagedFiles);
|
||||
m_submitOrigCommitFiles = data.stagedFileNames();
|
||||
|
||||
if (Git::Constants::debug)
|
||||
qDebug() << Q_FUNC_INFO << data << commitTemplate;
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include "gitconstants.h"
|
||||
#include "commitdata.h"
|
||||
|
||||
#include <vcsbase/submitfilemodel.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
namespace Git {
|
||||
@@ -52,14 +54,14 @@ GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget()
|
||||
return static_cast<GitSubmitEditorWidget *>(widget());
|
||||
}
|
||||
|
||||
QStringList GitSubmitEditor::statusListToFileList(const QStringList &rawList)
|
||||
static void addStateFileListToModel(const QList<CommitData::StateFilePair> &l,
|
||||
VCSBase::SubmitFileModel *model,
|
||||
bool checked)
|
||||
{
|
||||
if (rawList.empty())
|
||||
return rawList;
|
||||
QStringList rc;
|
||||
foreach (const QString &rf, rawList)
|
||||
rc.push_back(fileFromStatusLine(rf));
|
||||
return rc;
|
||||
typedef QList<CommitData::StateFilePair>::const_iterator ConstIterator;
|
||||
const ConstIterator cend = l.constEnd();
|
||||
for (ConstIterator it = l.constBegin(); it != cend; ++it)
|
||||
model->addFile(it->second, it->first, checked);
|
||||
}
|
||||
|
||||
void GitSubmitEditor::setCommitData(const CommitData &d)
|
||||
@@ -67,10 +69,16 @@ void GitSubmitEditor::setCommitData(const CommitData &d)
|
||||
submitEditorWidget()->setPanelData(d.panelData);
|
||||
submitEditorWidget()->setPanelInfo(d.panelInfo);
|
||||
|
||||
addFiles(d.stagedFiles, true, true);
|
||||
// Not Updated: Initially unchecked
|
||||
addFiles(d.unstagedFiles, false, true);
|
||||
addFiles(d.untrackedFiles, false, true);
|
||||
VCSBase::SubmitFileModel *model = new VCSBase::SubmitFileModel(this);
|
||||
addStateFileListToModel(d.stagedFiles, model, true);
|
||||
addStateFileListToModel(d.unstagedFiles, model, false);
|
||||
if (!d.untrackedFiles.empty()) {
|
||||
const QString untrackedSpec = QLatin1String("untracked");
|
||||
const QStringList::const_iterator cend = d.untrackedFiles.constEnd();
|
||||
for (QStringList::const_iterator it = d.untrackedFiles.constBegin(); it != cend; ++it)
|
||||
model->addFile(*it, untrackedSpec, false);
|
||||
}
|
||||
setFileModel(model);
|
||||
}
|
||||
|
||||
GitSubmitEditorPanelData GitSubmitEditor::panelData() const
|
||||
@@ -78,18 +86,5 @@ GitSubmitEditorPanelData GitSubmitEditor::panelData() const
|
||||
return const_cast<GitSubmitEditor*>(this)->submitEditorWidget()->panelData();
|
||||
}
|
||||
|
||||
QString GitSubmitEditor::fileFromStatusLine(const QString &line)
|
||||
{
|
||||
QString rc = line;
|
||||
// "modified: mainwindow.cpp"
|
||||
const int index = rc.indexOf(QLatin1Char(':'));
|
||||
if (index != -1)
|
||||
rc.remove(0, index + 1);
|
||||
const QChar blank(' ');
|
||||
while (rc.startsWith(blank))
|
||||
rc.remove(0, 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Git
|
||||
|
||||
@@ -54,13 +54,6 @@ public:
|
||||
void setCommitData(const CommitData &);
|
||||
GitSubmitEditorPanelData panelData() const;
|
||||
|
||||
static QString fileFromStatusLine(const QString &line);
|
||||
static QStringList statusListToFileList(const QStringList &);
|
||||
|
||||
protected:
|
||||
virtual QStringList vcsFileListToFileList(const QStringList &l) const
|
||||
{ return statusListToFileList(l); }
|
||||
|
||||
private:
|
||||
inline GitSubmitEditorWidget *submitEditorWidget();
|
||||
};
|
||||
|
||||
@@ -494,19 +494,19 @@ void PerforcePlugin::submit()
|
||||
QTC_ASSERT(m_coreInstance, return);
|
||||
|
||||
if (!checkP4Command()) {
|
||||
showOutput(tr("No p4 executable specified!"));
|
||||
showOutput(tr("No p4 executable specified!"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_changeTmpFile) {
|
||||
showOutput(tr("Another submit is currently executed."));
|
||||
showOutput(tr("Another submit is currently executed."), true);
|
||||
m_perforceOutputWindow->popup(false);
|
||||
return;
|
||||
}
|
||||
|
||||
m_changeTmpFile = new QTemporaryFile(this);
|
||||
if (!m_changeTmpFile->open()) {
|
||||
showOutput(tr("Cannot create temporary file."));
|
||||
showOutput(tr("Cannot create temporary file."), true);
|
||||
delete m_changeTmpFile;
|
||||
m_changeTmpFile = 0;
|
||||
return;
|
||||
@@ -970,7 +970,7 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
|
||||
QByteArray change = m_changeTmpFile->readAll();
|
||||
m_changeTmpFile->close();
|
||||
if (!checkP4Command()) {
|
||||
showOutput(tr("No p4 executable specified!"));
|
||||
showOutput(tr("No p4 executable specified!"), true);
|
||||
delete m_changeTmpFile;
|
||||
m_changeTmpFile = 0;
|
||||
return false;
|
||||
@@ -981,8 +981,8 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
|
||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
proc.start(m_settings.p4Command,
|
||||
basicP4Args() << QLatin1String("submit") << QLatin1String("-i"));
|
||||
if (!proc.waitForStarted(3000)) {
|
||||
showOutput(tr("Cannot execute p4 submit."));
|
||||
if (!proc.waitForStarted(p4Timeout)) {
|
||||
showOutput(tr("Cannot execute p4 submit."), true);
|
||||
QApplication::restoreOverrideCursor();
|
||||
delete m_changeTmpFile;
|
||||
m_changeTmpFile = 0;
|
||||
@@ -992,7 +992,7 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
|
||||
proc.closeWriteChannel();
|
||||
|
||||
if (!proc.waitForFinished()) {
|
||||
showOutput(tr("Cannot execute p4 submit."));
|
||||
showOutput(tr("Cannot execute p4 submit."), true);
|
||||
QApplication::restoreOverrideCursor();
|
||||
delete m_changeTmpFile;
|
||||
m_changeTmpFile = 0;
|
||||
@@ -1000,7 +1000,7 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
|
||||
}
|
||||
QString output = QString::fromUtf8(proc.readAll());
|
||||
showOutput(output);
|
||||
if (output.contains("Out of date files must be resolved or reverted")) {
|
||||
if (output.contains("Out of date files must be resolved or reverted"), true) {
|
||||
QMessageBox::warning(editor->widget(), "Pending change", "Could not submit the change, because your workspace was out of date. Created a pending submit instead.");
|
||||
}
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "perforceplugin.h"
|
||||
#include "perforceconstants.h"
|
||||
|
||||
#include <vcsbase/submitfilemodel.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
@@ -43,10 +44,14 @@
|
||||
namespace Perforce {
|
||||
namespace Internal {
|
||||
|
||||
enum { FileSpecRole = Qt::UserRole + 1 };
|
||||
|
||||
PerforceSubmitEditor::PerforceSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *parameters, QWidget *parent) :
|
||||
VCSBaseSubmitEditor(parameters, new PerforceSubmitEditorWidget(parent))
|
||||
VCSBaseSubmitEditor(parameters, new PerforceSubmitEditorWidget(parent)),
|
||||
m_fileModel(new VCSBase::SubmitFileModel(this))
|
||||
{
|
||||
setDisplayName(tr("Perforce Submit"));
|
||||
setFileModel(m_fileModel);
|
||||
}
|
||||
|
||||
PerforceSubmitEditorWidget *PerforceSubmitEditor::submitEditorWidget()
|
||||
@@ -54,14 +59,6 @@ PerforceSubmitEditorWidget *PerforceSubmitEditor::submitEditorWidget()
|
||||
return static_cast<PerforceSubmitEditorWidget *>(widget());
|
||||
}
|
||||
|
||||
QStringList PerforceSubmitEditor::vcsFileListToFileList(const QStringList &rawList) const
|
||||
{
|
||||
QStringList rc;
|
||||
foreach (const QString &rf, rawList)
|
||||
rc.push_back(fileFromChangeLine(rf));
|
||||
return rc;
|
||||
}
|
||||
|
||||
QString PerforceSubmitEditor::fileContents() const
|
||||
{
|
||||
const_cast<PerforceSubmitEditor*>(this)->updateEntries();
|
||||
@@ -121,25 +118,7 @@ bool PerforceSubmitEditor::parseText(QString text)
|
||||
|
||||
void PerforceSubmitEditor::restrictToProjectFiles(const QStringList &knownProjectFiles)
|
||||
{
|
||||
QStringList allFiles = submitEditorWidget()->fileList();
|
||||
const int oldSize = allFiles.size();
|
||||
for (int i = oldSize - 1; i >= 0; i--)
|
||||
if (!knownProjectFiles.contains(fileFromChangeLine(allFiles.at(i))))
|
||||
allFiles.removeAt(i);
|
||||
if (allFiles.size() != oldSize)
|
||||
submitEditorWidget()->setFileList(allFiles);
|
||||
if (Perforce::Constants::debug)
|
||||
qDebug() << Q_FUNC_INFO << oldSize << "->" << allFiles.size();
|
||||
}
|
||||
|
||||
QString PerforceSubmitEditor::fileFromChangeLine(const QString &line)
|
||||
{
|
||||
QString rc = line;
|
||||
// " foo.cpp#add"
|
||||
const int index = rc.lastIndexOf(QLatin1Char('#'));
|
||||
if (index != -1)
|
||||
rc.truncate(index);
|
||||
return rc.trimmed();
|
||||
m_fileModel->filter(knownProjectFiles, fileNameColumn());
|
||||
}
|
||||
|
||||
void PerforceSubmitEditor::updateFields()
|
||||
@@ -161,12 +140,15 @@ void PerforceSubmitEditor::updateFields()
|
||||
widget->setDescriptionText(lines.join(newLine));
|
||||
|
||||
lines = m_entries.value(QLatin1String("Files")).split(newLine);
|
||||
lines.replaceInStrings(leadingTabPattern, QString());
|
||||
QStringList fileList;
|
||||
foreach (const QString &line, lines)
|
||||
if (!line.isEmpty())
|
||||
fileList.push_back(line);
|
||||
widget->setFileList(fileList);
|
||||
// split up "file#add" and store complete spec line as user data
|
||||
foreach (const QString &specLine, lines) {
|
||||
const QStringList list = specLine.split(QLatin1Char('#'));
|
||||
if (list.size() == 2) {
|
||||
const QString file = list.at(0).trimmed();
|
||||
const QString state = list.at(1).trimmed();
|
||||
m_fileModel->addFile(file, state).at(0)->setData(specLine, FileSpecRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerforceSubmitEditor::updateEntries()
|
||||
@@ -181,13 +163,14 @@ void PerforceSubmitEditor::updateEntries()
|
||||
lines.replaceInStrings(QRegExp(QLatin1String("^")), tab);
|
||||
m_entries.insert(QLatin1String("Description"), newLine + lines.join(newLine) + QLatin1String("\n\n"));
|
||||
QString files = newLine;
|
||||
// Files
|
||||
const QStringList fileList = submitEditorWidget()->fileList();
|
||||
const int count = fileList.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
files += tab;
|
||||
files += fileList.at(i);
|
||||
files += newLine;
|
||||
// Re-build the file spec '<tab>file#add' from the user data
|
||||
const int count = m_fileModel->rowCount();
|
||||
for (int r = 0; r < count; r++) {
|
||||
const QStandardItem *item = m_fileModel->item(r, 0);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
files += item->data(FileSpecRole).toString();
|
||||
files += newLine;
|
||||
}
|
||||
}
|
||||
files += newLine;
|
||||
m_entries.insert(QLatin1String("Files"), files);
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
namespace VCSBase {
|
||||
class SubmitFileModel;
|
||||
}
|
||||
|
||||
namespace Perforce {
|
||||
namespace Internal {
|
||||
|
||||
@@ -66,7 +70,6 @@ public:
|
||||
static QString fileFromChangeLine(const QString &line);
|
||||
|
||||
protected:
|
||||
virtual QStringList vcsFileListToFileList(const QStringList &) const;
|
||||
virtual QString fileContents() const;
|
||||
virtual bool setFileContents(const QString &contents);
|
||||
|
||||
@@ -77,6 +80,7 @@ private:
|
||||
void updateEntries();
|
||||
|
||||
QMap<QString, QString> m_entries;
|
||||
VCSBase::SubmitFileModel *m_fileModel;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -139,6 +139,29 @@ inline Core::IEditor* locateEditor(const Core::ICore *core, const char *property
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse "svn status" output for added/modified/deleted files
|
||||
// "M<7blanks>file"
|
||||
typedef QList<SubversionSubmitEditor::StatusFilePair> StatusList;
|
||||
|
||||
StatusList parseStatusOutput(const QString &output)
|
||||
{
|
||||
StatusList changeSet;
|
||||
const QString newLine = QString(QLatin1Char('\n'));
|
||||
const QStringList list = output.split(newLine, QString::SkipEmptyParts);
|
||||
foreach (const QString &l, list) {
|
||||
const QString line =l.trimmed();
|
||||
if (line.size() > 8) {
|
||||
const QChar state = line.at(0);
|
||||
if (state == QLatin1Char('A') || state == QLatin1Char('D') || state == QLatin1Char('M')) {
|
||||
const QString fileName = line.mid(7);
|
||||
changeSet.push_back(SubversionSubmitEditor::StatusFilePair(QString(state), fileName));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return changeSet;
|
||||
}
|
||||
|
||||
// ------------- SubversionPlugin
|
||||
Core::ICore *SubversionPlugin::m_coreInstance = 0;
|
||||
SubversionPlugin *SubversionPlugin::m_subversionPluginInstance = 0;
|
||||
@@ -694,7 +717,7 @@ void SubversionPlugin::startCommit(const QStringList &files)
|
||||
if (response.error)
|
||||
return;
|
||||
// Get list of added/modified/deleted files
|
||||
const QStringList statusOutput = parseStatusOutput(response.stdOut);
|
||||
const StatusList statusOutput = parseStatusOutput(response.stdOut);
|
||||
if (statusOutput.empty()) {
|
||||
showOutput(tr("There are no modified files."), true);
|
||||
return;
|
||||
@@ -717,22 +740,7 @@ void SubversionPlugin::startCommit(const QStringList &files)
|
||||
m_changeTmpFile->seek(0);
|
||||
// Create a submit editor and set file list
|
||||
SubversionSubmitEditor *editor = openSubversionSubmitEditor(m_changeTmpFile->fileName());
|
||||
editor->setFileList(statusOutput);
|
||||
}
|
||||
|
||||
// Parse "status" output for added/modified/deleted files
|
||||
QStringList SubversionPlugin::parseStatusOutput(const QString &output) const
|
||||
{
|
||||
QStringList changeSet;
|
||||
const QString newLine = QString(QLatin1Char('\n'));
|
||||
const QStringList list = output.split(newLine, QString::SkipEmptyParts);
|
||||
foreach (const QString &l, list) {
|
||||
QString line(l.trimmed());
|
||||
if (line.startsWith(QLatin1Char('A')) || line.startsWith(QLatin1Char('D'))
|
||||
|| line.startsWith(QLatin1Char('M')))
|
||||
changeSet.append(line);
|
||||
}
|
||||
return changeSet;
|
||||
editor->setStatusList(statusOutput);
|
||||
}
|
||||
|
||||
bool SubversionPlugin::commit(const QString &messageFile,
|
||||
|
||||
@@ -133,7 +133,6 @@ private:
|
||||
SubversionResponse runSvn(const QStringList &arguments, int timeOut,
|
||||
bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0);
|
||||
void showOutput(const QString &output, bool bringToForeground = true);
|
||||
QStringList parseStatusOutput(const QString &output) const;
|
||||
void annotate(const QString &file);
|
||||
void filelog(const QString &file);
|
||||
bool managesDirectory(const QDir &directory) const;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "subversionsubmiteditor.h"
|
||||
|
||||
#include <utils/submiteditorwidget.h>
|
||||
#include <vcsbase/submitfilemodel.h>
|
||||
|
||||
using namespace Subversion::Internal;
|
||||
|
||||
@@ -45,6 +46,19 @@ SubversionSubmitEditor::SubversionSubmitEditor(const VCSBase::VCSBaseSubmitEdito
|
||||
setDisplayName(tr("Subversion Submit"));
|
||||
}
|
||||
|
||||
void SubversionSubmitEditor::setStatusList(const QList<StatusFilePair> &statusOutput)
|
||||
{
|
||||
typedef QList<StatusFilePair>::const_iterator ConstIterator;
|
||||
VCSBase::SubmitFileModel *model = new VCSBase::SubmitFileModel(this);
|
||||
|
||||
const ConstIterator cend = statusOutput.constEnd();
|
||||
for (ConstIterator it = statusOutput.constBegin(); it != cend; ++it)
|
||||
model->addFile(it->second, it->first, true);
|
||||
setFileModel(model);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
QStringList SubversionSubmitEditor::vcsFileListToFileList(const QStringList &rl) const
|
||||
{
|
||||
QStringList files;
|
||||
@@ -59,3 +73,5 @@ QString SubversionSubmitEditor::fileFromStatusLine(const QString &statusLine)
|
||||
enum { filePos = 7 };
|
||||
return statusLine.mid(filePos, statusLine.size() - filePos);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
#ifndef SUBVERSIONSUBMITEDITOR_H
|
||||
#define SUBVERSIONSUBMITEDITOR_H
|
||||
|
||||
#include <QtCore/QPair>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include <vcsbase/vcsbasesubmiteditor.h>
|
||||
|
||||
namespace Subversion {
|
||||
@@ -48,8 +51,10 @@ public:
|
||||
|
||||
static QString fileFromStatusLine(const QString &statusLine);
|
||||
|
||||
private:
|
||||
virtual QStringList vcsFileListToFileList(const QStringList &) const;
|
||||
// A list of ( 'A','M','D') status indicators and file names.
|
||||
typedef QPair<QString, QString> StatusFilePair;
|
||||
|
||||
void setStatusList(const QList<StatusFilePair> &statusOutput);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
78
src/plugins/vcsbase/submitfilemodel.cpp
Normal file
78
src/plugins/vcsbase/submitfilemodel.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/***************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Qt Software Information (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** Non-Open Source Usage
|
||||
**
|
||||
** Licensees may use this file in accordance with the Qt Beta Version
|
||||
** License Agreement, Agreement version 2.2 provided with the Software or,
|
||||
** alternatively, in accordance with the terms contained in a written
|
||||
** agreement between you and Nokia.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License versions 2.0 or 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the packaging
|
||||
** of this file. Please review the following information to ensure GNU
|
||||
** General Public Licensing requirements will be met:
|
||||
**
|
||||
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt GPL Exception
|
||||
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
***************************************************************************/
|
||||
|
||||
#include "submitfilemodel.h"
|
||||
#include "vcsbaseconstants.h"
|
||||
|
||||
#include <QtGui/QStandardItem>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
namespace VCSBase {
|
||||
|
||||
SubmitFileModel::SubmitFileModel(QObject *parent) :
|
||||
QStandardItemModel(0, 2, parent)
|
||||
{
|
||||
// setColumnCount(2);
|
||||
QStringList headerLabels;
|
||||
headerLabels << tr("State") << tr("File");
|
||||
setHorizontalHeaderLabels(headerLabels);
|
||||
}
|
||||
|
||||
QList<QStandardItem *> SubmitFileModel::addFile(const QString &fileName, const QString &status, bool checked)
|
||||
{
|
||||
if (VCSBase::Constants::Internal::debug)
|
||||
qDebug() << Q_FUNC_INFO << fileName << status << checked;
|
||||
QStandardItem *statusItem = new QStandardItem(status);
|
||||
statusItem->setCheckable(true);
|
||||
statusItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
|
||||
QStandardItem *fileItem = new QStandardItem(fileName);
|
||||
QList<QStandardItem *> row;
|
||||
row << statusItem << fileItem;
|
||||
appendRow(row);
|
||||
return row;
|
||||
}
|
||||
|
||||
unsigned SubmitFileModel::filter(const QStringList &filter, int column)
|
||||
{
|
||||
unsigned rc = 0;
|
||||
for (int r = rowCount() - 1; r >= 0; r--)
|
||||
if (const QStandardItem *i = item(r, column))
|
||||
if (!filter.contains(i->text())) {
|
||||
qDeleteAll(takeRow(r));
|
||||
rc++;
|
||||
}
|
||||
if (VCSBase::Constants::Internal::debug)
|
||||
qDebug() << Q_FUNC_INFO << " deleted " << rc << " items using " << filter << " , remaining " << rowCount();
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
62
src/plugins/vcsbase/submitfilemodel.h
Normal file
62
src/plugins/vcsbase/submitfilemodel.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Qt Software Information (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** Non-Open Source Usage
|
||||
**
|
||||
** Licensees may use this file in accordance with the Qt Beta Version
|
||||
** License Agreement, Agreement version 2.2 provided with the Software or,
|
||||
** alternatively, in accordance with the terms contained in a written
|
||||
** agreement between you and Nokia.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License versions 2.0 or 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the packaging
|
||||
** of this file. Please review the following information to ensure GNU
|
||||
** General Public Licensing requirements will be met:
|
||||
**
|
||||
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt GPL Exception
|
||||
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SUBMITMODEL_H
|
||||
#define SUBMITMODEL_H
|
||||
|
||||
#include "vcsbase_global.h"
|
||||
|
||||
#include <QtGui/QStandardItemModel>
|
||||
|
||||
namespace VCSBase {
|
||||
|
||||
/* A 2-column (checkable, state, file name) model to be used to list the files-
|
||||
* in the submit editor. Provides header items and a convience to add files. */
|
||||
|
||||
class VCSBASE_EXPORT SubmitFileModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SubmitFileModel(QObject *parent = 0);
|
||||
|
||||
// Convenience to add a file plus status text.
|
||||
QList<QStandardItem *> addFile(const QString &fileName, const QString &status = QString(), bool checked = true);
|
||||
|
||||
// Filter for entries contained in the filter list. Returns the
|
||||
// number of deleted entries.
|
||||
unsigned filter(const QStringList &filter, int column);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SUBMITMODEL_H
|
||||
@@ -1,31 +1,28 @@
|
||||
TEMPLATE = lib
|
||||
TARGET = VCSBase
|
||||
|
||||
DEFINES += VCSBASE_LIBRARY
|
||||
|
||||
include(../../qworkbenchplugin.pri)
|
||||
include(vcsbase_dependencies.pri)
|
||||
|
||||
HEADERS += vcsbase_global.h \
|
||||
vcsbaseconstants.h \
|
||||
vcsbaseplugin.h \
|
||||
baseannotationhighlighter.h \
|
||||
diffhighlighter.h \
|
||||
vcsbasetextdocument.h \
|
||||
vcsbaseeditor.h \
|
||||
vcsbasesubmiteditor.h \
|
||||
basevcseditorfactory.h \
|
||||
submiteditorfile.h \
|
||||
basevcssubmiteditorfactory.h
|
||||
|
||||
vcsbaseconstants.h \
|
||||
vcsbaseplugin.h \
|
||||
baseannotationhighlighter.h \
|
||||
diffhighlighter.h \
|
||||
vcsbasetextdocument.h \
|
||||
vcsbaseeditor.h \
|
||||
vcsbasesubmiteditor.h \
|
||||
basevcseditorfactory.h \
|
||||
submiteditorfile.h \
|
||||
basevcssubmiteditorfactory.h \
|
||||
submitfilemodel.h
|
||||
SOURCES += vcsbaseplugin.cpp \
|
||||
baseannotationhighlighter.cpp \
|
||||
diffhighlighter.cpp \
|
||||
vcsbasetextdocument.cpp \
|
||||
vcsbaseeditor.cpp \
|
||||
vcsbasesubmiteditor.cpp \
|
||||
basevcseditorfactory.cpp \
|
||||
submiteditorfile.cpp \
|
||||
basevcssubmiteditorfactory.cpp
|
||||
|
||||
RESOURCES=vcsbase.qrc
|
||||
baseannotationhighlighter.cpp \
|
||||
diffhighlighter.cpp \
|
||||
vcsbasetextdocument.cpp \
|
||||
vcsbaseeditor.cpp \
|
||||
vcsbasesubmiteditor.cpp \
|
||||
basevcseditorfactory.cpp \
|
||||
submiteditorfile.cpp \
|
||||
basevcssubmiteditorfactory.cpp \
|
||||
submitfilemodel.cpp
|
||||
RESOURCES = vcsbase.qrc
|
||||
|
||||
@@ -129,6 +129,16 @@ VCSBaseSubmitEditor::~VCSBaseSubmitEditor()
|
||||
delete m_d;
|
||||
}
|
||||
|
||||
int VCSBaseSubmitEditor::fileNameColumn() const
|
||||
{
|
||||
return m_d->m_widget->fileNameColumn();
|
||||
}
|
||||
|
||||
void VCSBaseSubmitEditor::setFileNameColumn(int c)
|
||||
{
|
||||
m_d->m_widget->setFileNameColumn(c);
|
||||
}
|
||||
|
||||
void VCSBaseSubmitEditor::slotDescriptionChanged()
|
||||
{
|
||||
}
|
||||
@@ -246,22 +256,22 @@ bool VCSBaseSubmitEditor::restoreState(const QByteArray &/*state*/)
|
||||
|
||||
QStringList VCSBaseSubmitEditor::checkedFiles() const
|
||||
{
|
||||
return vcsFileListToFileList(m_d->m_widget->checkedFiles());
|
||||
return m_d->m_widget->checkedFiles();
|
||||
}
|
||||
|
||||
void VCSBaseSubmitEditor::setFileList(const QStringList &l)
|
||||
void VCSBaseSubmitEditor::setFileModel(QAbstractItemModel *m)
|
||||
{
|
||||
m_d->m_widget->setFileList(l);
|
||||
m_d->m_widget->setFileModel(m);
|
||||
}
|
||||
|
||||
void VCSBaseSubmitEditor::addFiles(const QStringList& list, bool checked, bool userCheckable)
|
||||
QAbstractItemModel *VCSBaseSubmitEditor::fileModel() const
|
||||
{
|
||||
m_d->m_widget->addFiles(list, checked, userCheckable);
|
||||
return m_d->m_widget->fileModel();
|
||||
}
|
||||
|
||||
void VCSBaseSubmitEditor::slotDiffSelectedVCSFiles(const QStringList &rawList)
|
||||
{
|
||||
emit diffSelectedFiles(vcsFileListToFileList(rawList));
|
||||
emit diffSelectedFiles(rawList);
|
||||
}
|
||||
|
||||
bool VCSBaseSubmitEditor::save(const QString &fileName)
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QIcon;
|
||||
class QAbstractItemModel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Core {
|
||||
@@ -90,6 +91,7 @@ struct VCSBASE_EXPORT VCSBaseSubmitEditorParameters {
|
||||
class VCSBASE_EXPORT VCSBaseSubmitEditor : public Core::IEditor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int fileNameColumn READ fileNameColumn WRITE setFileNameColumn DESIGNABLE false)
|
||||
public:
|
||||
typedef QList<int> Context;
|
||||
|
||||
@@ -100,6 +102,9 @@ protected:
|
||||
public:
|
||||
virtual ~VCSBaseSubmitEditor();
|
||||
|
||||
int fileNameColumn() const;
|
||||
void setFileNameColumn(int c);
|
||||
|
||||
// Core::IEditor
|
||||
virtual bool createNew(const QString &contents);
|
||||
virtual bool open(const QString &fileName);
|
||||
@@ -119,8 +124,8 @@ public:
|
||||
|
||||
QStringList checkedFiles() const;
|
||||
|
||||
void setFileList(const QStringList&);
|
||||
void addFiles(const QStringList&, bool checked = true, bool userCheckable = true);
|
||||
void setFileModel(QAbstractItemModel *m);
|
||||
QAbstractItemModel *fileModel() const;
|
||||
|
||||
// Utilities returning some predefined icons for actions
|
||||
static QIcon diffIcon();
|
||||
@@ -139,11 +144,6 @@ private slots:
|
||||
void slotDescriptionChanged();
|
||||
|
||||
protected:
|
||||
/* Implemented this to extract the real file list from the status
|
||||
* output of the versioning system as displayed in the file list
|
||||
* for example "M foo.cpp" -> "foo.cpp". */
|
||||
virtual QStringList vcsFileListToFileList(const QStringList &) const = 0;
|
||||
|
||||
/* These hooks allow for modifying the contents that goes to
|
||||
* the file. The default implementation uses the text
|
||||
* of the description editor. */
|
||||
|
||||
Reference in New Issue
Block a user