diff --git a/src/libs/utils/submiteditorwidget.cpp b/src/libs/utils/submiteditorwidget.cpp index ae8eb41593d5cb5778003fe89c27991a21db181c..3513c27715d4eea1caef363dfc32d09bc70486eb 100644 --- a/src/libs/utils/submiteditorwidget.cpp +++ b/src/libs/utils/submiteditorwidget.cpp @@ -36,6 +36,7 @@ #include <QtCore/QDebug> #include <QtCore/QPointer> +#include <QtCore/QTimer> #include <QtGui/QPushButton> @@ -70,6 +71,42 @@ void QActionPushButton::actionChanged() setEnabled(a->isEnabled()); } +// Helpers to retrieve model data +static inline bool listModelChecked(const QAbstractItemModel *model, int row, int column = 0) +{ + const QModelIndex checkableIndex = model->index(row, column, QModelIndex()); + return model->data(checkableIndex, Qt::CheckStateRole).toInt() == Qt::Checked; +} + +static inline QString listModelText(const QAbstractItemModel *model, int row, int column) +{ + const QModelIndex index = model->index(row, column, QModelIndex()); + return model->data(index, Qt::DisplayRole).toString(); +} + +// Find a check item in a model +static bool listModelContainsCheckedItem(const QAbstractItemModel *model) +{ + const int count = model->rowCount(); + for (int i = 0; i < count; i++) + if (listModelChecked(model, i, 0)) + return true; + return false; +} + +// Convenience to extract a list of selected indexes +QList<int> selectedRows(const QAbstractItemView *view) +{ + const QModelIndexList indexList = view->selectionModel()->selectedRows(0); + if (indexList.empty()) + return QList<int>(); + QList<int> rc; + const QModelIndexList::const_iterator cend = indexList.constEnd(); + for (QModelIndexList::const_iterator it = indexList.constBegin(); it != cend; ++it) + rc.push_back(it->row()); + return rc; +} + // ----------- SubmitEditorWidgetPrivate struct SubmitEditorWidgetPrivate { @@ -78,11 +115,15 @@ struct SubmitEditorWidgetPrivate Ui::SubmitEditorWidget m_ui; bool m_filesSelected; bool m_filesChecked; + int m_fileNameColumn; + int m_activatedRow; }; SubmitEditorWidgetPrivate::SubmitEditorWidgetPrivate() : m_filesSelected(false), - m_filesChecked(false) + m_filesChecked(false), + m_fileNameColumn(1), + m_activatedRow(-1) { } @@ -92,10 +133,10 @@ SubmitEditorWidget::SubmitEditorWidget(QWidget *parent) : { m_d->m_ui.setupUi(this); // File List - m_d->m_ui.fileList->setSelectionMode(QAbstractItemView::ExtendedSelection); - connect(m_d->m_ui.fileList, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(triggerDiffSelected())); - connect(m_d->m_ui.fileList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(fileItemChanged(QListWidgetItem*))); - connect(m_d->m_ui.fileList, SIGNAL(itemSelectionChanged()), this, SLOT(fileSelectionChanged())); + m_d->m_ui.fileView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_d->m_ui.fileView->setRootIsDecorated(false); + connect(m_d->m_ui.fileView, SIGNAL(doubleClicked(QModelIndex)), + this, SLOT(diffActivated(QModelIndex))); // Text m_d->m_ui.description->setFont(QFont(QLatin1String("Courier"))); @@ -124,8 +165,12 @@ void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *ed } if (submitAction) { - if (debug) - qDebug() << submitAction << m_d->m_ui.fileList->count() << "items" << m_d->m_filesChecked; + if (debug) { + int count = 0; + if (const QAbstractItemModel *model = m_d->m_ui.fileView->model()) + count = model->rowCount(); + qDebug() << submitAction << count << "items" << m_d->m_filesChecked; + } submitAction->setEnabled(m_d->m_filesChecked); connect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool))); m_d->m_ui.buttonLayout->addWidget(new QActionPushButton(submitAction)); @@ -161,7 +206,6 @@ void SubmitEditorWidget::unregisterActions(QAction *editorUndoAction, QAction * } } - QString SubmitEditorWidget::trimmedDescriptionText() const { // Make sure we have one terminating NL @@ -180,91 +224,70 @@ void SubmitEditorWidget::setDescriptionText(const QString &text) m_d->m_ui.description->setPlainText(text); } -QStringList SubmitEditorWidget::fileList() const +int SubmitEditorWidget::fileNameColumn() const { - QStringList rc; - const int count = m_d->m_ui.fileList->count(); - for (int i = 0; i < count; i++) - rc.push_back(m_d->m_ui.fileList->item(i)->text()); - return rc; + return m_d->m_fileNameColumn; } -void SubmitEditorWidget::addFilesUnblocked(const QStringList &list, bool checked, bool userCheckable) +void SubmitEditorWidget::setFileNameColumn(int c) { - if (debug) - qDebug() << Q_FUNC_INFO << list << checked << userCheckable; - foreach (const QString &f, list) { - QListWidgetItem *item = new QListWidgetItem(f); - item->setCheckState(checked ? Qt::Checked : Qt::Unchecked); - if (!userCheckable) - item->setFlags(item->flags() & ~Qt::ItemIsUserCheckable); - m_d->m_ui.fileList->addItem(item); - } + m_d->m_fileNameColumn = c; } -void SubmitEditorWidget::addFiles(const QStringList &list, bool checked, bool userCheckable) +void SubmitEditorWidget::setFileModel(QAbstractItemModel *model) { - if (list.empty()) - return; - - const bool blocked = m_d->m_ui.fileList->blockSignals(true); - addFilesUnblocked(list, checked, userCheckable); - m_d->m_ui.fileList->blockSignals(blocked); - // Did we gain any checked files..update action accordingly - if (!m_d->m_filesChecked && checked) { - m_d->m_filesChecked = true; - emit fileCheckStateChanged(m_d->m_filesChecked); - } -} + m_d->m_ui.fileView->clearSelection(); // trigger the change signals -void SubmitEditorWidget::setFileList(const QStringList &list) -{ - // Trigger enabling of menu action - m_d->m_ui.fileList->clearSelection(); + m_d->m_ui.fileView->setModel(model); - const bool blocked = m_d->m_ui.fileList->blockSignals(true); - m_d->m_ui.fileList->clear(); - if (!list.empty()) { - addFilesUnblocked(list, true, true); - // Checked files added? - if (!m_d->m_filesChecked) { - m_d->m_filesChecked = true; - emit fileCheckStateChanged(m_d->m_filesChecked); - } + if (model->rowCount()) { + const int columnCount = model->columnCount(); + for (int c = 0; c < columnCount; c++) + m_d->m_ui.fileView->resizeColumnToContents(c); } - m_d->m_ui.fileList->blockSignals(blocked); + + connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(updateSubmitAction())); + connect(model, SIGNAL(modelReset()), + this, SLOT(updateSubmitAction())); + connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(updateSubmitAction())); + connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(updateSubmitAction())); + connect(m_d->m_ui.fileView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(updateDiffAction())); + updateActions(); } -static bool containsCheckState(const QListWidget *lw, Qt::CheckState cs) +QAbstractItemModel *SubmitEditorWidget::fileModel() const { - const int count = lw->count(); - for (int i = 0; i < count; i++) - if (lw->item(i)->checkState() == cs) - return true; - return false; + return m_d->m_ui.fileView->model(); } QStringList SubmitEditorWidget::selectedFiles() const { + const QList<int> selection = selectedRows(m_d->m_ui.fileView); + if (selection.empty()) + return QStringList(); + QStringList rc; - const int count = m_d->m_ui.fileList->count(); - for (int i = 0; i < count; i++) { - const QListWidgetItem *item = m_d->m_ui.fileList->item(i); - if (item->isSelected()) - rc.push_back(item->text()); - } + const QAbstractItemModel *model = m_d->m_ui.fileView->model(); + const int count = selection.size(); + for (int i = 0; i < count; i++) + rc.push_back(listModelText(model, selection.at(i), fileNameColumn())); return rc; } QStringList SubmitEditorWidget::checkedFiles() const { QStringList rc; - const int count = m_d->m_ui.fileList->count(); - for (int i = 0; i < count; i++) { - const QListWidgetItem *item = m_d->m_ui.fileList->item(i); - if (item->checkState() == Qt::Checked) - rc.push_back(item->text()); - } + const QAbstractItemModel *model = m_d->m_ui.fileView->model(); + if (!model) + return rc; + const int count = model->rowCount(); + for (int i = 0; i < count; i++) + if (listModelChecked(model, i, 0)) + rc.push_back(listModelText(model, i, fileNameColumn())); return rc; } @@ -280,44 +303,61 @@ void SubmitEditorWidget::triggerDiffSelected() emit diffSelected(sel); } -void SubmitEditorWidget::fileItemChanged(QListWidgetItem *item) -{ - const Qt::CheckState st = item->checkState(); - if (debug) - qDebug() << Q_FUNC_INFO << st << item->text() << m_d->m_filesChecked; - // Enable the actions according to check state - switch (st) { - case Qt::Unchecked: // Item was unchecked: Any checked items left? - if (m_d->m_filesChecked && !containsCheckState(m_d->m_ui.fileList, Qt::Checked)) { - m_d->m_filesChecked = false; - emit fileCheckStateChanged(m_d->m_filesChecked); - } - break; - case Qt::Checked: - // Item was Checked. First one? - if (!m_d->m_filesChecked) { - m_d->m_filesChecked = true; - emit fileCheckStateChanged(m_d->m_filesChecked); - } - break; - case Qt::PartiallyChecked: // Errm? - break; +void SubmitEditorWidget::diffActivatedDelayed() +{ + const QStringList files = QStringList(listModelText(m_d->m_ui.fileView->model(), m_d->m_activatedRow, fileNameColumn())); + emit diffSelected(files); +} + +void SubmitEditorWidget::diffActivated(const QModelIndex &index) +{ + // We need to delay the signal, otherwise, the diff editor will not + // be in the foreground. + m_d->m_activatedRow = index.row(); + QTimer::singleShot(0, this, SLOT(diffActivatedDelayed())); +} + +void SubmitEditorWidget::updateActions() +{ + updateSubmitAction(); + updateDiffAction(); +} + +// Enable submit depending on having checked files +void SubmitEditorWidget::updateSubmitAction() +{ + const bool newFilesCheckedState = hasCheckedFiles(); + if (m_d->m_filesChecked != newFilesCheckedState) { + m_d->m_filesChecked = newFilesCheckedState; + emit fileCheckStateChanged(m_d->m_filesChecked); } } -void SubmitEditorWidget::fileSelectionChanged() +// Enable diff depending on selected files +void SubmitEditorWidget::updateDiffAction() { - const bool newFilesSelected = !m_d->m_ui.fileList->selectedItems().empty(); - if (debug) - qDebug() << Q_FUNC_INFO << newFilesSelected; - if (m_d->m_filesSelected != newFilesSelected) { - m_d->m_filesSelected = newFilesSelected; + const bool filesSelected = hasSelection(); + if (m_d->m_filesSelected != filesSelected) { + m_d->m_filesSelected = filesSelected; emit fileSelectionChanged(m_d->m_filesSelected); - if (debug) - qDebug() << Q_FUNC_INFO << m_d->m_filesSelected; } } +bool SubmitEditorWidget::hasSelection() const +{ + // Not present until model is set + if (const QItemSelectionModel *sm = m_d->m_ui.fileView->selectionModel()) + return sm->hasSelection(); + return false; +} + +bool SubmitEditorWidget::hasCheckedFiles() const +{ + if (const QAbstractItemModel *model = m_d->m_ui.fileView->model()) + return listModelContainsCheckedItem(model); + return false; +} + void SubmitEditorWidget::changeEvent(QEvent *e) { switch (e->type()) { diff --git a/src/libs/utils/submiteditorwidget.h b/src/libs/utils/submiteditorwidget.h index 921bb6d16ddbd83cbf35497f6cecfa85d0e4351d..71af07641e896e9708f25ec84bd29b67954ff072 100644 --- a/src/libs/utils/submiteditorwidget.h +++ b/src/libs/utils/submiteditorwidget.h @@ -42,6 +42,8 @@ QT_BEGIN_NAMESPACE class QPlainTextEdit; class QListWidgetItem; class QAction; +class QAbstractItemModel; +class QModelIndex; QT_END_NAMESPACE namespace Core { @@ -51,8 +53,9 @@ struct SubmitEditorWidgetPrivate; /* The submit editor presents the commit message in a text editor and an * checkable list of modified files in a list window. The user can delete - * files from the list by pressing unchecking them or diff the selection - * by doubleclicking. + * files from the list by unchecking them or diff the selection + * by doubleclicking. A list model which contains the file in a column + * specified by fileNameColumn should be set using setFileModel(). * * Additionally, standard creator actions can be registered: * Undo/redo will be set up to work with the description editor. @@ -71,7 +74,7 @@ class QWORKBENCH_UTILS_EXPORT SubmitEditorWidget : public QWidget Q_OBJECT Q_DISABLE_COPY(SubmitEditorWidget) Q_PROPERTY(QString descriptionText READ descriptionText WRITE setDescriptionText DESIGNABLE true) - Q_PROPERTY(QStringList fileList READ fileList WRITE setFileList DESIGNABLE true) + Q_PROPERTY(int fileNameColumn READ fileNameColumn WRITE setFileNameColumn DESIGNABLE false) public: explicit SubmitEditorWidget(QWidget *parent = 0); virtual ~SubmitEditorWidget(); @@ -86,10 +89,11 @@ public: // Should be used to normalize newlines. QString trimmedDescriptionText() const; - // The raw file list - QStringList fileList() const; - void addFiles(const QStringList&, bool checked = true, bool userCheckable = true); - void setFileList(const QStringList&); + int fileNameColumn() const; + void setFileNameColumn(int c); + + void setFileModel(QAbstractItemModel *model); + QAbstractItemModel *fileModel() const; // Files to be included in submit QStringList checkedFiles() const; @@ -110,11 +114,16 @@ protected: private slots: void triggerDiffSelected(); - void fileItemChanged(QListWidgetItem *); - void fileSelectionChanged(); + void diffActivated(const QModelIndex &index); + void diffActivatedDelayed(); + void fileDataChanged (const QModelIndex &topLeft, const QModelIndex &bottomRight); + void updateActions(); + void updateSubmitAction(); + void updateDiffAction(); private: - void addFilesUnblocked(const QStringList &list, bool checked, bool userCheckable); + bool hasSelection() const; + bool hasCheckedFiles() const; SubmitEditorWidgetPrivate *m_d; }; diff --git a/src/libs/utils/submiteditorwidget.ui b/src/libs/utils/submiteditorwidget.ui index 69eed91eb326d286b7ab84ee5170ba12b2f73841..2067cad4487dbafbf69f1de5651adb4242c6fec0 100644 --- a/src/libs/utils/submiteditorwidget.ui +++ b/src/libs/utils/submiteditorwidget.ui @@ -39,14 +39,7 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QListWidget" name="fileList"> - <property name="font"> - <font/> - </property> - <property name="textElideMode"> - <enum>Qt::ElideNone</enum> - </property> - </widget> + <widget class="QTreeView" name="fileView"/> </item> </layout> </widget> diff --git a/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp index 8b96fe23c973c5e8fb1dd2238adce22bce9b6f21..ada478e3743c283f1e681839a9adadd40e74c60f 100644 --- a/src/plugins/git/commitdata.cpp +++ b/src/plugins/git/commitdata.cpp @@ -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; diff --git a/src/plugins/git/commitdata.h b/src/plugins/git/commitdata.h index a1dc05ef42540be2b3ce927978efc69c41a1a720..6cb5ddb42b9ca4f46996f7f1b3788bc4360867c1 100644 --- a/src/plugins/git/commitdata.h +++ b/src/plugins/git/commitdata.h @@ -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; }; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 281a9572a215079dae27ad6176349236f7039f73..d1ebda300b4bcfbe4329fc55bc4103d19f1fead3 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -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; diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index fe2d93adbff2415f7a56cbf435c44e065d114ebf..2ef08083393531aca4164993246fa6b0356dedcd 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -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; diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index fe93a0c6ad14510f7e4a66565bc4eb7ece89d8d6..d34a78240d21301e168a6f1249fbf48ded86db1a 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -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 diff --git a/src/plugins/git/gitsubmiteditor.h b/src/plugins/git/gitsubmiteditor.h index 8199384d07f7a75ac1e483a53ae0b975512296a3..a1a80ac22cf11be556f6dfe39fb27a602c79e91f 100644 --- a/src/plugins/git/gitsubmiteditor.h +++ b/src/plugins/git/gitsubmiteditor.h @@ -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(); }; diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 0ad0224d1ca191b911ab9d2ed5fedd3a55ad8874..aa4b0a4fa4841f82e734a245067294ef6dde6d69 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -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(); diff --git a/src/plugins/perforce/perforcesubmiteditor.cpp b/src/plugins/perforce/perforcesubmiteditor.cpp index 6aa74f95fb236468ee1123f94f1d9d6f4733e14c..826f22757187f0bbb7b79423c50e5b267af4d9bd 100644 --- a/src/plugins/perforce/perforcesubmiteditor.cpp +++ b/src/plugins/perforce/perforcesubmiteditor.cpp @@ -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); diff --git a/src/plugins/perforce/perforcesubmiteditor.h b/src/plugins/perforce/perforcesubmiteditor.h index 0f44332a694f466fe22485af057f9d0ca6066201..5dba068315855806a051f05044cbadeb21ea4965 100644 --- a/src/plugins/perforce/perforcesubmiteditor.h +++ b/src/plugins/perforce/perforcesubmiteditor.h @@ -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 diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 5f5200aab34528a3ae0a20cb0a62ce5447dadc0f..36182eb94a0474badab795228e9e90c717a3c6be 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -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, diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h index 6c2c448241ea3de3323901cb9e5d624cf30cf18b..7909b3f2328ead25b6b84a8438efd3617eb57acc 100644 --- a/src/plugins/subversion/subversionplugin.h +++ b/src/plugins/subversion/subversionplugin.h @@ -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; diff --git a/src/plugins/subversion/subversionsubmiteditor.cpp b/src/plugins/subversion/subversionsubmiteditor.cpp index b1e97e676e46dcecd1948231557d9e4d8ff94df6..c65a2530dd72039a3bbbcecc2f2603e8476e7c0a 100644 --- a/src/plugins/subversion/subversionsubmiteditor.cpp +++ b/src/plugins/subversion/subversionsubmiteditor.cpp @@ -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); } + +*/ diff --git a/src/plugins/subversion/subversionsubmiteditor.h b/src/plugins/subversion/subversionsubmiteditor.h index c6bf0845ebce135ce2f67658b2e6423ef49888b1..6aae19c824e08d50ded6cd2f81f31055dd1abf76 100644 --- a/src/plugins/subversion/subversionsubmiteditor.h +++ b/src/plugins/subversion/subversionsubmiteditor.h @@ -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 diff --git a/src/plugins/vcsbase/submitfilemodel.cpp b/src/plugins/vcsbase/submitfilemodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f12eab38d14bd0291346c346dfe88a08435eed79 --- /dev/null +++ b/src/plugins/vcsbase/submitfilemodel.cpp @@ -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; +} +} diff --git a/src/plugins/vcsbase/submitfilemodel.h b/src/plugins/vcsbase/submitfilemodel.h new file mode 100644 index 0000000000000000000000000000000000000000..fef89df83bef6b4e4d1d92d14566c822cfb69550 --- /dev/null +++ b/src/plugins/vcsbase/submitfilemodel.h @@ -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 diff --git a/src/plugins/vcsbase/vcsbase.pro b/src/plugins/vcsbase/vcsbase.pro index 329e27b0686c4def2c150583c84468d00033a563..d34fe84e7c05476658180ae46779d68540842f5b 100644 --- a/src/plugins/vcsbase/vcsbase.pro +++ b/src/plugins/vcsbase/vcsbase.pro @@ -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 diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 9d668f16a767735ca789f369e0315ff050cd432f..d130c2664596505fe65e1ccb4ed37956fa4ecca7 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -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) diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.h b/src/plugins/vcsbase/vcsbasesubmiteditor.h index 72553672411b003cdd3c0012e7b5df2157edd443..91b10d488f99b0e8754a2699267cda3178c1abcc 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.h +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.h @@ -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. */