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. */