diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp
index 9486caa5a0125536b2434c39ae95f766c36f944f..6a2b365202143d4994a966599ca096e5e1efd883 100644
--- a/src/libs/utils/synchronousprocess.cpp
+++ b/src/libs/utils/synchronousprocess.cpp
@@ -220,6 +220,16 @@ void SynchronousProcess::setEnvironment(const QStringList &e)
     m_d->m_process.setEnvironment(e);
 }
 
+void SynchronousProcess::setProcessEnvironment(const QProcessEnvironment &environment)
+{
+    m_d->m_process.setProcessEnvironment(environment);
+}
+
+QProcessEnvironment SynchronousProcess::processEnvironment() const
+{
+    return m_d->m_process.processEnvironment();
+}
+
 void SynchronousProcess::setWorkingDirectory(const QString &workingDirectory)
 {
     m_d->m_process.setWorkingDirectory(workingDirectory);
diff --git a/src/libs/utils/synchronousprocess.h b/src/libs/utils/synchronousprocess.h
index 86f45060cd0a64c663d6c57613502d02e2ac8a6d..8e7aa042f4a9d8fa94ab6b26b4b84381f1f01d8b 100644
--- a/src/libs/utils/synchronousprocess.h
+++ b/src/libs/utils/synchronousprocess.h
@@ -110,6 +110,9 @@ public:
     QStringList environment() const;
     void setEnvironment(const QStringList &);
 
+    void setProcessEnvironment(const QProcessEnvironment &environment);
+    QProcessEnvironment processEnvironment() const;
+
     void setWorkingDirectory(const QString &workingDirectory);
     QString workingDirectory() const;
 
diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp
index bbf720051b0f8ab60ae1d8a2a8552803e9170b40..653009203b78866386d24fed6c1eab8c60f6c7c2 100644
--- a/src/plugins/coreplugin/actionmanager/command.cpp
+++ b/src/plugins/coreplugin/actionmanager/command.cpp
@@ -27,12 +27,17 @@
 **
 **************************************************************************/
 
+#include "command_p.h"
+
+#include "icore.h"
+#include "uniqueidmanager.h"
+
 #include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+
 #include <QtGui/QAction>
 #include <QtGui/QShortcut>
 
-#include "command_p.h"
-
 /*!
     \class Core::Command
     \mainclass
@@ -467,6 +472,20 @@ bool OverrideableAction::setCurrentContext(const QList<int> &context)
     return false;
 }
 
+static inline QString msgActionWarning(QAction *newAction, int k, QAction *oldAction)
+{
+    QString msg;
+    QTextStream str(&msg);
+    str << "addOverrideAction " << newAction->objectName() << '/' << newAction->text()
+         << ": Action ";
+    if (oldAction)
+        str << oldAction->objectName() << '/' << oldAction->text();
+    str << " is already registered for context " << k << ' '
+        << Core::ICore::instance()->uniqueIDManager()->stringForUniqueIdentifier(k)
+        << '.';
+    return msg;
+}
+
 void OverrideableAction::addOverrideAction(QAction *action, const QList<int> &context)
 {
     if (context.isEmpty()) {
@@ -475,7 +494,7 @@ void OverrideableAction::addOverrideAction(QAction *action, const QList<int> &co
         for (int i=0; i<context.size(); ++i) {
             int k = context.at(i);
             if (m_contextActionMap.contains(k))
-                qWarning() << QString("addOverrideAction: action already registered for context when registering '%1'").arg(action->text());
+                qWarning("%s", qPrintable(msgActionWarning(action, k, m_contextActionMap.value(k, 0))));
             m_contextActionMap.insert(k, action);
         }
     }
diff --git a/src/plugins/perforce/pendingchangesdialog.ui b/src/plugins/perforce/pendingchangesdialog.ui
index bcee662a027917baab0127b7493b80bd9198dc11..0cae43326eeb8c8c7598809aa682a105608935af 100644
--- a/src/plugins/perforce/pendingchangesdialog.ui
+++ b/src/plugins/perforce/pendingchangesdialog.ui
@@ -1,41 +1,34 @@
-<ui version="4.0" >
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
  <class>Perforce::Internal::PendingChangesDialog</class>
- <widget class="QDialog" name="Perforce::Internal::PendingChangesDialog" >
-  <property name="geometry" >
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>333</width>
-    <height>126</height>
-   </rect>
-  </property>
-  <property name="windowTitle" >
+ <widget class="QDialog" name="Perforce::Internal::PendingChangesDialog">
+  <property name="windowTitle">
    <string>P4 Pending Changes</string>
   </property>
-  <layout class="QVBoxLayout" >
-   <property name="margin" >
-    <number>9</number>
-   </property>
-   <property name="spacing" >
+  <layout class="QVBoxLayout">
+   <property name="spacing">
     <number>6</number>
    </property>
+   <property name="margin">
+    <number>9</number>
+   </property>
    <item>
-    <widget class="QListWidget" name="listWidget" />
+    <widget class="QListWidget" name="listWidget"/>
    </item>
    <item>
-    <layout class="QHBoxLayout" >
-     <property name="margin" >
-      <number>0</number>
-     </property>
-     <property name="spacing" >
+    <layout class="QHBoxLayout">
+     <property name="spacing">
       <number>6</number>
      </property>
+     <property name="margin">
+      <number>0</number>
+     </property>
      <item>
       <spacer>
-       <property name="orientation" >
+       <property name="orientation">
         <enum>Qt::Horizontal</enum>
        </property>
-       <property name="sizeHint" >
+       <property name="sizeHint" stdset="0">
         <size>
          <width>131</width>
          <height>31</height>
@@ -44,15 +37,15 @@
       </spacer>
      </item>
      <item>
-      <widget class="QPushButton" name="submitButton" >
-       <property name="text" >
+      <widget class="QPushButton" name="submitButton">
+       <property name="text">
         <string>Submit</string>
        </property>
       </widget>
      </item>
      <item>
-      <widget class="QPushButton" name="cancelButton" >
-       <property name="text" >
+      <widget class="QPushButton" name="cancelButton">
+       <property name="text">
         <string>Cancel</string>
        </property>
       </widget>
@@ -69,11 +62,11 @@
    <receiver>Perforce::Internal::PendingChangesDialog</receiver>
    <slot>accept()</slot>
    <hints>
-    <hint type="sourcelabel" >
+    <hint type="sourcelabel">
      <x>278</x>
      <y>253</y>
     </hint>
-    <hint type="destinationlabel" >
+    <hint type="destinationlabel">
      <x>96</x>
      <y>254</y>
     </hint>
@@ -85,11 +78,11 @@
    <receiver>Perforce::Internal::PendingChangesDialog</receiver>
    <slot>reject()</slot>
    <hints>
-    <hint type="sourcelabel" >
+    <hint type="sourcelabel">
      <x>369</x>
      <y>253</y>
     </hint>
-    <hint type="destinationlabel" >
+    <hint type="destinationlabel">
      <x>179</x>
      <y>282</y>
     </hint>
diff --git a/src/plugins/perforce/perforce.pro b/src/plugins/perforce/perforce.pro
index e93e3378d85a680250174a225e786ce8781cafa3..27d398f0f32641ed2aba33a4a67c8c3b80207739 100644
--- a/src/plugins/perforce/perforce.pro
+++ b/src/plugins/perforce/perforce.pro
@@ -6,6 +6,7 @@ include(perforce_dependencies.pri)
 
 HEADERS += \
     perforceplugin.h \
+    perforcechecker.h \
     settingspage.h \
     perforceeditor.h \
     changenumberdialog.h \
@@ -18,6 +19,7 @@ HEADERS += \
     perforcesubmiteditorwidget.h
 
 SOURCES += perforceplugin.cpp \
+    perforcechecker.cpp \
     settingspage.cpp \
     perforceeditor.cpp \
     changenumberdialog.cpp \
diff --git a/src/plugins/perforce/perforcechecker.cpp b/src/plugins/perforce/perforcechecker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1039e954797a93e38170262c1aa1add7003b0da3
--- /dev/null
+++ b/src/plugins/perforce/perforcechecker.cpp
@@ -0,0 +1,217 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "perforcechecker.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QRegExp>
+#include <QtCore/QTimer>
+#include <QtCore/QFileInfo>
+
+#include <QtGui/QApplication>
+#include <QtGui/QCursor>
+
+namespace Perforce {
+namespace Internal {
+
+PerforceChecker::PerforceChecker(QObject *parent) :
+    QObject(parent),
+    m_timeOutMS(-1),
+    m_timedOut(false),
+    m_useOverideCursor(false),
+    m_isOverrideCursor(false)
+{
+    connect(&m_process, SIGNAL(error(QProcess::ProcessError)),
+            this, SLOT(slotError(QProcess::ProcessError)));
+    connect(&m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
+                this, SLOT(slotFinished(int,QProcess::ExitStatus)));
+}
+
+PerforceChecker::~PerforceChecker()
+{
+    resetOverrideCursor();
+}
+
+bool PerforceChecker::isRunning() const
+{
+    return m_process.state() == QProcess::Running;
+}
+
+void PerforceChecker::resetOverrideCursor()
+{
+    if (m_isOverrideCursor) {
+        QApplication::restoreOverrideCursor();
+        m_isOverrideCursor = false;
+    }
+}
+
+void PerforceChecker::start(const QString &binary,
+                            const QStringList &basicArgs,
+                            int timeoutMS)
+{
+    if (isRunning()) {
+        emitFailed(QLatin1String("Internal error: process still running"));
+        return;
+    }
+    if (binary.isEmpty()) {
+        emitFailed(tr("No executable specified"));
+        return;
+    }
+    m_binary = binary;
+    QStringList args = basicArgs;
+    args << QLatin1String("client") << QLatin1String("-o");
+    m_process.start(m_binary, args);
+    m_process.closeWriteChannel();
+    // Timeout handling
+    m_timeOutMS = timeoutMS;
+    m_timedOut = false;
+    if (timeoutMS > 0)
+        QTimer::singleShot(m_timeOutMS, this, SLOT(slotTimeOut()));
+    // Cursor
+    if (m_useOverideCursor) {
+        m_isOverrideCursor = true;
+        QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
+    }
+}
+
+bool PerforceChecker::ensureProcessStopped(QProcess &p)
+{
+    if (p.state() != QProcess::Running)
+        return true;
+    p.terminate();
+    if (p.waitForFinished(300))
+        return true;
+    p.kill();
+    return p.waitForFinished(300);
+}
+
+void PerforceChecker::slotTimeOut()
+{
+    if (!isRunning())
+        return;
+    m_timedOut = true;
+    ensureProcessStopped(m_process);
+    emitFailed(tr("\"%1\" timed out after %2ms.").arg(m_binary).arg(m_timeOutMS));
+}
+
+void PerforceChecker::slotError(QProcess::ProcessError error)
+{
+    if (m_timedOut)
+        return;
+    switch (error) {
+    case QProcess::FailedToStart:
+        emitFailed(tr("Unable to launch \"%1\": %2").arg(m_binary, m_process.errorString()));
+        break;
+    case QProcess::Crashed: // Handled elsewhere
+    case QProcess::Timedout:
+        break;
+    case QProcess::ReadError:
+    case QProcess::WriteError:
+    case QProcess::UnknownError:
+        ensureProcessStopped(m_process);
+        break;
+    }
+}
+
+void PerforceChecker::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+    if (m_timedOut)
+        return;
+    switch (exitStatus) {
+    case QProcess::CrashExit:
+        emitFailed(tr("\"%1\" crashed.").arg(m_binary));
+        break;
+    case QProcess::NormalExit:
+        if (exitCode) {
+            const QString stdErr = QString::fromLocal8Bit(m_process.readAllStandardError());
+            emitFailed(tr("\"%1\" terminated with exit code %2: %3").arg(m_binary).arg(exitCode).arg(stdErr));
+        } else {
+            parseOutput(QString::fromLocal8Bit(m_process.readAllStandardOutput()));
+        }
+        break;
+    }
+}
+
+// Parse p4 client output for the top level
+static inline QString clientRootFromOutput(const QString &in)
+{
+    QRegExp regExp(QLatin1String("(\\n|\\r\\n|\\r)Root:\\s*(.*)(\\n|\\r\\n|\\r)"));
+    QTC_ASSERT(regExp.isValid(), return QString());
+    regExp.setMinimal(true);
+    if (regExp.indexIn(in) != -1)
+        return regExp.cap(2).trimmed();
+    return QString();
+}
+
+void PerforceChecker::parseOutput(const QString &response)
+{
+    if (!response.contains(QLatin1String("View:")) && !response.contains(QLatin1String("//depot/"))) {
+        emitFailed(tr("The client does not seem to contain any mapped files."));
+        return;
+    }
+    const QString repositoryRoot = clientRootFromOutput(response);
+    if (repositoryRoot.isEmpty()) {
+        emitFailed(tr("Unable to determine the client root."));
+        return;
+    }
+    // Check existence. No precise check here, might be a symlink
+    const QFileInfo fi(repositoryRoot);
+    if (fi.exists()) {
+        emitSucceeded(repositoryRoot);
+    } else {
+        emitFailed(tr("The repository \"%1\" does not exist.").arg(repositoryRoot));
+    }
+}
+
+void PerforceChecker::emitFailed(const QString &m)
+{
+    resetOverrideCursor();
+    emit failed(m);
+}
+
+void PerforceChecker::emitSucceeded(const QString &m)
+{
+    resetOverrideCursor();
+    emit succeeded(m);
+}
+
+bool PerforceChecker::useOverideCursor() const
+{
+    return m_useOverideCursor;
+}
+
+void PerforceChecker::setUseOverideCursor(bool v)
+{
+    m_useOverideCursor = v;
+}
+
+}
+}
+
diff --git a/src/plugins/perforce/perforcechecker.h b/src/plugins/perforce/perforcechecker.h
new file mode 100644
index 0000000000000000000000000000000000000000..906ecd5c29d327b45096d45bb1b5f4963e5cf8ed
--- /dev/null
+++ b/src/plugins/perforce/perforcechecker.h
@@ -0,0 +1,88 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef PERFORCECHECKER_H
+#define PERFORCECHECKER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+
+namespace Perforce {
+namespace Internal {
+
+// Perforce checker:  Calls perforce asynchronously to do
+// a check of the configuration and emits signals with the top level or
+// an error message.
+
+class PerforceChecker : public QObject
+{
+    Q_OBJECT
+public:
+    explicit PerforceChecker(QObject *parent = 0);
+    virtual ~PerforceChecker();
+
+public slots:
+    void start(const QString &binary,
+               const QStringList &basicArgs = QStringList(),
+               int timeoutMS = -1);
+
+    bool isRunning() const;
+
+    bool useOverideCursor() const;
+    void setUseOverideCursor(bool v);
+
+    static bool ensureProcessStopped(QProcess &p);
+
+signals:
+    void succeeded(const QString &repositoryRoot);
+    void failed(const QString &errorMessage);
+
+private slots:
+    void slotError(QProcess::ProcessError error);
+    void slotFinished(int exitCode, QProcess::ExitStatus exitStatus);
+    void slotTimeOut();
+
+private:
+    void emitFailed(const QString &);
+    void emitSucceeded(const QString &);
+    void parseOutput(const QString &);
+    inline void resetOverrideCursor();
+
+    QProcess m_process;
+    QString m_binary;
+    int m_timeOutMS;
+    bool m_timedOut;
+    bool m_useOverideCursor;
+    bool m_isOverrideCursor;
+};
+
+}
+}
+
+#endif // PERFORCECHECKER_H
diff --git a/src/plugins/perforce/perforceconstants.h b/src/plugins/perforce/perforceconstants.h
index 39d4031f98500db0c5744c5da77454a61af1ec8d..3402b49dc1591f5dd51e133244a1f96d9d282056 100644
--- a/src/plugins/perforce/perforceconstants.h
+++ b/src/plugins/perforce/perforceconstants.h
@@ -33,11 +33,24 @@
 namespace Perforce {
 namespace Constants {
 
-const char * const C_PERFORCEEDITOR  = "Perforce Editor";
+const char * const PERFORCEEDITOR_CONTEXT  = "Perforce Editor";
+
+
+const char * const PERFORCE_SUBMIT_EDITOR_KIND  = "Perforce Submit Editor";
+const char * const PERFORCESUBMITEDITOR_CONTEXT = "Perforce Submit Editor";
+
+const char * const PERFORCE_COMMANDLOG_EDITOR_KIND = "Perforce Command Log Editor";
+const char * const PERFORCE_COMMANDLOG_EDITOR_CONTEXT = "Perforce Command Log Editor";
+
+const char * const PERFORCE_LOG_EDITOR_KIND = "Perforce Log Editor";
+const char * const PERFORCE_LOG_EDITOR_CONTEXT = "Perforce Log Editor";
+
+const char * const PERFORCE_DIFF_EDITOR_KIND = "Perforce Diff Editor";
+const char * const PERFORCE_DIFF_EDITOR_CONTEXT = "Perforce Diff Editor";
+
+const char * const PERFORCE_ANNOTATION_EDITOR_KIND = "Perforce Annotation Editor";
+const char * const PERFORCE_ANNOTATION_EDITOR_CONTEXT = "Perforce Annotation Editor";
 
-const char * const PERFORCEEDITOR_KIND  = "Perforce Editor";
-const char * const C_PERFORCESUBMITEDITOR  = "Perforce Submit Editor";
-const char * const PERFORCESUBMITEDITOR_KIND  = "Perforce Submit Editor";
 const char * const SUBMIT_CURRENT = "Perforce.SubmitCurrentLog";
 const char * const DIFF_SELECTED = "Perforce.DiffSelectedFilesInLog";
 const char * const SUBMIT_MIMETYPE = "application/vnd.nokia.text.p4.submit";
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 8e1e55ea73d4f44b8b492fec03ee738e9b6994b2..350c0ffb9bd75106104da838962a0f4d12bddae6 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -35,6 +35,7 @@
 #include "perforceeditor.h"
 #include "perforcesubmiteditor.h"
 #include "perforceversioncontrol.h"
+#include "perforcechecker.h"
 #include "settingspage.h"
 
 #include <coreplugin/actionmanager/actionmanager.h>
@@ -52,8 +53,6 @@
 #include <vcsbase/basevcssubmiteditorfactory.h>
 #include <vcsbase/vcsbaseeditor.h>
 #include <vcsbase/vcsbaseoutputwindow.h>
-#include <projectexplorer/project.h>
-#include <projectexplorer/session.h>
 
 #include <QtCore/QtPlugin>
 #include <QtCore/QDebug>
@@ -69,30 +68,28 @@
 #include <QtGui/QMenu>
 #include <QtGui/QMessageBox>
 
-using namespace Perforce::Internal;
-
 enum { p4Timeout = 20000 };
 
 static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
 {
     VCSBase::RegularCommandOutput,
-    "Perforce Command Log Editor",
-    Perforce::Constants::C_PERFORCEEDITOR,
+    Perforce::Constants::PERFORCE_COMMANDLOG_EDITOR_KIND,
+    Perforce::Constants::PERFORCE_COMMANDLOG_EDITOR_CONTEXT,
     "application/vnd.nokia.text.scs_commandlog",
     "scslog"},
 {   VCSBase::LogOutput,
-    "Perforce File Log Editor",
-    Perforce::Constants::C_PERFORCEEDITOR,
+    Perforce::Constants::PERFORCE_LOG_EDITOR_KIND,
+    Perforce::Constants::PERFORCE_LOG_EDITOR_CONTEXT,
     "application/vnd.nokia.text.scs_filelog",
     "scsfilelog"},
 {    VCSBase::AnnotateOutput,
-    "Perforce Annotation Editor",
-    Perforce::Constants::C_PERFORCEEDITOR,
+     Perforce::Constants::PERFORCE_ANNOTATION_EDITOR_KIND,
+     Perforce::Constants::PERFORCE_ANNOTATION_EDITOR_CONTEXT,
     "application/vnd.nokia.text.scs_annotation",
     "scsannotate"},
 {   VCSBase::DiffOutput,
-    "Perforce Diff Editor",
-    Perforce::Constants::C_PERFORCEEDITOR,
+    Perforce::Constants::PERFORCE_DIFF_EDITOR_KIND,
+    Perforce::Constants::PERFORCE_DIFF_EDITOR_CONTEXT,
     "text/x-patch","diff"}
 };
 
@@ -108,25 +105,29 @@ static inline QString debugCodec(const QTextCodec *c)
     return c ? QString::fromAscii(c->name()) : QString::fromAscii("Null codec");
 }
 
-// Return the project files relevant for VCS
-static const QStringList currentProjectFiles(QString *name)
-{
-    QStringList files = VCSBase::VCSBaseSubmitEditor::currentProjectFiles(true, name);
-    if (!files.empty()) {
-        // Filter out mkspecs/qconfig.pri
-        QString exclusion = QLatin1String("mkspecs");
-        exclusion += QDir::separator();
-        exclusion += QLatin1String("qconfig.pri");
-        for (QStringList::iterator it = files.begin(); it != files.end(); ) {
-            if (it->endsWith(exclusion)) {
-                it = files.erase(it);
-                break;
-            } else {
-                ++it;
-            }
-        }
-    }
-    return files;
+// Ensure adding "..." to relative paths which is p4's convention
+// for the current directory
+static inline QStringList perforceRelativeFileArguments(const QStringList &args)
+{
+    if (args.isEmpty())
+        return QStringList(QLatin1String("..."));
+    QTC_ASSERT(args.size() == 1, return QStringList())
+    QStringList p4Args = args;
+    p4Args.front() += QLatin1String("/...");
+    return p4Args;
+}
+
+static inline QStringList perforceRelativeProjectDirectory(const VCSBase::VCSBasePluginState &s)
+{
+    return perforceRelativeFileArguments(s.relativeCurrentProject());
+}
+
+// Clean user setting off diff-binary for 'p4 resolve' and 'p4 diff'.
+static inline QProcessEnvironment overrideDiffEnvironmentVariable()
+{
+    QProcessEnvironment rc = QProcessEnvironment::systemEnvironment();
+    rc.remove(QLatin1String("P4DIFF"));
+    return rc;
 }
 
 static const char * const CMD_ID_PERFORCE_MENU = "Perforce.Menu";
@@ -138,6 +139,8 @@ static const char * const CMD_ID_REVERT = "Perforce.Revert";
 static const char * const CMD_ID_DIFF_CURRENT = "Perforce.DiffCurrent";
 static const char * const CMD_ID_DIFF_PROJECT = "Perforce.DiffProject";
 static const char * const CMD_ID_UPDATE_PROJECT = "Perforce.UpdateProject";
+static const char * const CMD_ID_REVERT_PROJECT = "Perforce.RevertProject";
+static const char * const CMD_ID_REVERT_UNCHANGED_PROJECT = "Perforce.RevertUnchangedProject";
 static const char * const CMD_ID_DIFF_ALL = "Perforce.DiffAll";
 static const char * const CMD_ID_RESOLVE = "Perforce.Resolve";
 static const char * const CMD_ID_SUBMIT = "Perforce.Submit";
@@ -156,21 +159,31 @@ static const char * const CMD_ID_SEPARATOR3 = "Perforce.Separator3";
 // PerforcePlugin
 ////
 
+namespace Perforce {
+namespace Internal {
+
+PerforceResponse::PerforceResponse() :
+    error(true),
+    exitCode(-1)
+{
+}
+
 PerforcePlugin *PerforcePlugin::m_perforcePluginInstance = NULL;
 
 PerforcePlugin::PerforcePlugin() :
-    VCSBase::VCSBasePlugin(QLatin1String(Constants::PERFORCESUBMITEDITOR_KIND)),
+    VCSBase::VCSBasePlugin(QLatin1String(Constants::PERFORCE_SUBMIT_EDITOR_KIND)),
     m_editAction(0),
     m_addAction(0),
     m_deleteAction(0),
     m_openedAction(0),
-    m_revertAction(0),
-    m_diffCurrentAction(0),
+    m_revertFileAction(0),
+    m_diffFileAction(0),
     m_diffProjectAction(0),
     m_updateProjectAction(0),
+    m_revertProjectAction(0),
+    m_revertUnchangedAction(0),
     m_diffAllAction(0),
-    m_resolveAction(0),
-    m_submitAction(0),
+    m_submitProjectAction(0),
     m_pendingAction(0),
     m_describeAction(0),
     m_annotateCurrentAction(0),
@@ -188,8 +201,8 @@ PerforcePlugin::PerforcePlugin() :
 
 static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = {
     Perforce::Constants::SUBMIT_MIMETYPE,
-    Perforce::Constants::PERFORCESUBMITEDITOR_KIND,
-    Perforce::Constants::C_PERFORCESUBMITEDITOR
+    Perforce::Constants::PERFORCE_SUBMIT_EDITOR_KIND,
+    Perforce::Constants::PERFORCESUBMITEDITOR_CONTEXT
 };
 
 bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * errorMessage)
@@ -234,7 +247,7 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * e
 
     QList<int> perforcesubmitcontext;
     perforcesubmitcontext << Core::UniqueIDManager::instance()->
-            uniqueIdentifier(Constants::C_PERFORCESUBMITEDITOR);
+            uniqueIdentifier(Constants::PERFORCESUBMITEDITOR_CONTEXT);
 
     Core::Command *command;
     QAction *tmpaction;
@@ -262,12 +275,12 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * e
     connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(deleteCurrentFile()));
     mperforce->addAction(command);
 
-    m_revertAction = new Utils::ParameterAction(tr("Revert"), tr("Revert \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
-    command = am->registerAction(m_revertAction, CMD_ID_REVERT, globalcontext);
+    m_revertFileAction = new Utils::ParameterAction(tr("Revert"), tr("Revert \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+    command = am->registerAction(m_revertFileAction, CMD_ID_REVERT, globalcontext);
     command->setAttribute(Core::Command::CA_UpdateText);
     command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+R")));
     command->setDefaultText(tr("Revert File"));
-    connect(m_revertAction, SIGNAL(triggered()), this, SLOT(revertCurrentFile()));
+    connect(m_revertFileAction, SIGNAL(triggered()), this, SLOT(revertCurrentFile()));
     mperforce->addAction(command);
 
     tmpaction = new QAction(this);
@@ -275,11 +288,11 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * e
     command = am->registerAction(tmpaction, QLatin1String("Perforce.Sep.Edit"), globalcontext);
     mperforce->addAction(command);
 
-    m_diffCurrentAction = new Utils::ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
-    command = am->registerAction(m_diffCurrentAction, CMD_ID_DIFF_CURRENT, globalcontext);
+    m_diffFileAction = new Utils::ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+    command = am->registerAction(m_diffFileAction, CMD_ID_DIFF_CURRENT, globalcontext);
     command->setAttribute(Core::Command::CA_UpdateText);
     command->setDefaultText(tr("Diff Current File"));
-    connect(m_diffCurrentAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
+    connect(m_diffFileAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
     mperforce->addAction(command);
 
     const QString diffProjectDefaultText = tr("Diff Current Project/Session");
@@ -307,10 +320,11 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * e
     connect(m_openedAction, SIGNAL(triggered()), this, SLOT(printOpenedFileList()));
     mperforce->addAction(command);
 
-    m_submitAction = new QAction(tr("Submit Project"), this);
-    command = am->registerAction(m_submitAction, CMD_ID_SUBMIT, globalcontext);
+    m_submitProjectAction = new Utils::ParameterAction(tr("Submit Project"), tr("Submit Project \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+    command = am->registerAction(m_submitProjectAction, CMD_ID_SUBMIT, globalcontext);
+    command->setAttribute(Core::Command::CA_UpdateText);
     command->setDefaultKeySequence(QKeySequence(tr("Alt+P,Alt+S")));
-    connect(m_submitAction, SIGNAL(triggered()), this, SLOT(submit()));
+    connect(m_submitProjectAction, SIGNAL(triggered()), this, SLOT(startSubmitProject()));
     mperforce->addAction(command);
 
     m_pendingAction = new QAction(tr("Pending Changes..."), this);
@@ -318,7 +332,7 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * e
     connect(m_pendingAction, SIGNAL(triggered()), this, SLOT(printPendingChanges()));
     mperforce->addAction(command);
 
-    const QString updateProjectDefaultText = tr("Update Current Project/Session");
+    const QString updateProjectDefaultText = tr("Update Current Project");
     m_updateProjectAction = new Utils::ParameterAction(updateProjectDefaultText, tr("Update Project \"%1\""), Utils::ParameterAction::AlwaysEnabled, this);
     command = am->registerAction(m_updateProjectAction, CMD_ID_UPDATE_PROJECT, globalcontext);
     command->setDefaultText(updateProjectDefaultText);
@@ -326,6 +340,18 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * e
     connect(m_updateProjectAction, SIGNAL(triggered()), this, SLOT(updateCurrentProject()));
     mperforce->addAction(command);
 
+    m_revertProjectAction = new Utils::ParameterAction(tr("Revert Project"), tr("Revert Project \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+    command = am->registerAction(m_revertProjectAction, CMD_ID_REVERT_PROJECT, globalcontext);
+    command->setAttribute(Core::Command::CA_UpdateText);
+    connect(m_revertProjectAction, SIGNAL(triggered()), this, SLOT(revertCurrentProject()));
+    mperforce->addAction(command);
+
+    m_revertUnchangedAction = new Utils::ParameterAction(tr("Revert Unchanged"), tr("Revert Unchanged Files of Project \"%1\""), Utils::ParameterAction::EnabledWithParameter, this);
+    command = am->registerAction(m_revertUnchangedAction, CMD_ID_REVERT_UNCHANGED_PROJECT, globalcontext);
+    command->setAttribute(Core::Command::CA_UpdateText);
+    connect(m_revertUnchangedAction, SIGNAL(triggered()), this, SLOT(revertUnchangedCurrentProject()));
+    mperforce->addAction(command);
+
     tmpaction = new QAction(this);
     tmpaction->setSeparator(true);
     command = am->registerAction(tmpaction, QLatin1String("Perforce.Sep.Changes"), globalcontext);
@@ -384,138 +410,160 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * e
 
 void PerforcePlugin::extensionsInitialized()
 {
-    m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
+    getTopLevel();
 }
 
 void PerforcePlugin::openCurrentFile()
 {
-    vcsOpen(currentFileName());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    vcsOpen(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void PerforcePlugin::addCurrentFile()
 {
-    vcsAdd(currentFileName());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    vcsAdd(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void PerforcePlugin::deleteCurrentFile()
 {
-    vcsDelete(currentFileName());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    vcsDelete(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void PerforcePlugin::revertCurrentFile()
 {
-    const QString fileName = currentFileName();
-    QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(fileName);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+
+    QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(state.currentFile());
     QStringList args;
-    args << QLatin1String("diff") << QLatin1String("-sa");
-    PerforceResponse result = runP4Cmd(args, QStringList(), CommandToWindow|StdErrToWindow|ErrorToWindow, codec);
+    args << QLatin1String("diff") << QLatin1String("-sa") << state.relativeCurrentFile();
+    PerforceResponse result = runP4Cmd(state.currentFileTopLevel(), args,
+                                       RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow,
+                                       QStringList(), QByteArray(), codec);
     if (result.error)
         return;
+    // "foo.cpp - file(s) not opened on this client."
+    if (result.stdOut.isEmpty() || result.stdOut.contains(QLatin1String(" - ")))
+        return;
 
-    if (!result.stdOut.isEmpty()) {
-        bool doNotRevert = QMessageBox::warning(0, tr("p4 revert"),
-                                                tr("The file has been changed. Do you want to revert it?"),
-                                                QMessageBox::Yes, QMessageBox::No)
-                            == QMessageBox::No;
-        if (doNotRevert)
-            return;
-    }
+    const bool doNotRevert = QMessageBox::warning(0, tr("p4 revert"),
+                             tr("The file has been changed. Do you want to revert it?"),
+                             QMessageBox::Yes, QMessageBox::No) == QMessageBox::No;
+    if (doNotRevert)
+        return;
 
-    Core::FileChangeBlocker fcb(fileName);
+    Core::FileChangeBlocker fcb(state.currentFile());
     fcb.setModifiedReload(true);
-    PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    args.clear();
+    args << QLatin1String("revert") << state.relativeCurrentFile();
+    PerforceResponse result2 = runP4Cmd(state.currentFileTopLevel(), args,
+                                        CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
     if (!result2.error)
-        perforceVersionControl()->emitFilesChanged(QStringList(fileName));
+        perforceVersionControl()->emitFilesChanged(QStringList(state.currentFile()));
 }
 
 void PerforcePlugin::diffCurrentFile()
 {
-    p4Diff(QStringList(currentFileName()));
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    p4Diff(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
 }
 
 void PerforcePlugin::diffCurrentProject()
 {
-    QString name;
-    const QStringList nativeFiles = currentProjectFiles(&name);
-    p4Diff(nativeFiles, name);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasProject(), return)
+    p4Diff(state.currentProjectTopLevel(), perforceRelativeProjectDirectory(state));
 }
 
 void PerforcePlugin::diffAllOpened()
 {
-    p4Diff(QStringList());
+    p4Diff(m_settings.topLevel(), QStringList());
 }
 
-// Add the directory of a project to a list of p4 directory specifications
-// ("path/...")
-static inline void addProjectP4Directory(const ProjectExplorer::Project *p, QStringList *p4dirs)
+void PerforcePlugin::updateCurrentProject()
 {
-    if (const Core::IFile *file =  p->file()) {
-        const QFileInfo fi(file->fileName());
-        QString p4dir = fi.absolutePath();
-        if (!p4dir.isEmpty()) {
-            p4dir += QDir::separator();
-            p4dir += QLatin1String("...");
-            p4dirs->push_back(p4dir);
-        }
-    }
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasProject(), return)
+    updateCheckout(state.currentProjectTopLevel(), perforceRelativeProjectDirectory(state));
 }
 
-void PerforcePlugin::updateCurrentProject()
+void PerforcePlugin::updateAll()
+{
+    updateCheckout(m_settings.topLevel());
+}
+
+void PerforcePlugin::revertCurrentProject()
 {
-    if (!m_projectExplorer)
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasProject(), return)
+
+    const QString msg = tr("Do you want to revert all changes to the project \"%1\"?").arg(state.currentProjectName());
+    if (QMessageBox::warning(0, tr("p4 revert"), msg, QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
         return;
-    // Compile a list of project directories
-    QStringList p4Directories;
-    if (const ProjectExplorer::Project *proj = m_projectExplorer->currentProject()) {
-        addProjectP4Directory(proj, &p4Directories);
-    } else {
-        if (const ProjectExplorer::SessionManager *session = m_projectExplorer->session())
-            foreach(const ProjectExplorer::Project *proj, session->projects())
-                addProjectP4Directory(proj, &p4Directories);
-    }
-    if (!p4Directories.empty())
-        updateCheckout(p4Directories);
+    revertProject(state.currentProjectTopLevel(), perforceRelativeProjectDirectory(state), false);
 }
 
-void PerforcePlugin::updateAll()
+void PerforcePlugin::revertUnchangedCurrentProject()
 {
-    updateCheckout();
+    // revert -a.
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasProject(), return)
+    revertProject(state.currentProjectTopLevel(), perforceRelativeProjectDirectory(state), true);
 }
 
-void PerforcePlugin::updateCheckout(const QStringList &dirs)
+bool PerforcePlugin::revertProject(const QString &workingDir, const QStringList &pathArgs, bool unchangedOnly)
+{
+    QStringList args(QLatin1String("revert"));
+    if (unchangedOnly)
+        args.push_back(QLatin1String("-a"));
+    args.append(pathArgs);
+    const PerforceResponse resp = runP4Cmd(workingDir, args,
+                                           RunFullySynchronous|CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    return !resp.error;
+}
+
+void PerforcePlugin::updateCheckout(const QString &workingDir, const QStringList &dirs)
 {
     QStringList args(QLatin1String("sync"));
     args.append(dirs);
-    const PerforceResponse resp = runP4Cmd(args, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
-    if (!dirs.empty())
+    const PerforceResponse resp = runP4Cmd(workingDir, args,
+                                           CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    if (dirs.empty()) {
+        if (!workingDir.isEmpty())
+            perforceVersionControl()->emitRepositoryChanged(workingDir);
+    } else {
+        const QChar slash = QLatin1Char('/');
         foreach(const QString &dir, dirs)
-            perforceVersionControl()->emitRepositoryChanged(dir);
+            perforceVersionControl()->emitRepositoryChanged(workingDir + slash + dir);
+    }
 }
 
 void PerforcePlugin::printOpenedFileList()
 {
-    Core::IEditor *e = Core::EditorManager::instance()->currentEditor();
-    if (e)
-        e->widget()->setFocus();
-    PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("opened"), QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    runP4Cmd(m_settings.topLevel(), QStringList(QLatin1String("opened")),
+             CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
 }
 
-void PerforcePlugin::submit()
+void PerforcePlugin::startSubmitProject()
 {
-    if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
-        return;
 
-    QString errorMessage;
-    if (!checkP4Configuration(&errorMessage)) {
-        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
+    if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
         return;
-    }
 
     if (isCommitEditorOpen()) {
         VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Another submit is currently executed."));
         return;
     }
 
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasProject(), return)
+
     QTemporaryFile changeTmpFile;
     changeTmpFile.setAutoRemove(false);
     if (!changeTmpFile.open()) {
@@ -523,9 +571,15 @@ void PerforcePlugin::submit()
         cleanCommitMessageFile();
         return;
     }
+    // Revert all unchanged files.
+    if (!revertProject(state.currentProjectTopLevel(), perforceRelativeProjectDirectory(state), true))
+        return;
+    // Start a change
+    QStringList args;
 
-    PerforceResponse result = runP4Cmd(QStringList()<< QLatin1String("change") << QLatin1String("-o"), QStringList(),
-                                       CommandToWindow|StdErrToWindow|ErrorToWindow);
+    args << QLatin1String("change") << QLatin1String("-o");
+    PerforceResponse result = runP4Cmd(state.currentProjectTopLevel(), args,
+                                       RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow);
     if (result.error) {
         cleanCommitMessageFile();
         return;
@@ -535,19 +589,19 @@ void PerforcePlugin::submit()
     changeTmpFile.write(result.stdOut.toAscii());
     changeTmpFile.close();
 
-    // Assemble file list of project
-    QString name;
-    const QStringList nativeFiles = currentProjectFiles(&name);
-    PerforceResponse result2 = runP4Cmd(QStringList(QLatin1String("fstat")), nativeFiles,
-                                        CommandToWindow|StdErrToWindow|ErrorToWindow);
-    if (result2.error) {
+    args.clear();
+    args << QLatin1String("fstat");
+    args.append(perforceRelativeProjectDirectory(state));
+    PerforceResponse fstatResult = runP4Cmd(state.currentProjectTopLevel(), args,
+                                            RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow);
+    if (fstatResult.error) {
         cleanCommitMessageFile();
         return;
     }
 
-    QStringList stdOutLines = result2.stdOut.split(QLatin1Char('\n'));
+    QStringList fstatLines = fstatResult.stdOut.split(QLatin1Char('\n'));
     QStringList depotFileNames;
-    foreach (const QString &line, stdOutLines) {
+    foreach (const QString &line, fstatLines) {
         if (line.startsWith("... depotFile"))
             depotFileNames.append(line.mid(14));
     }
@@ -563,12 +617,12 @@ void PerforcePlugin::submit()
 Core::IEditor *PerforcePlugin::openPerforceSubmitEditor(const QString &fileName, const QStringList &depotFileNames)
 {
     Core::EditorManager *editorManager = Core::EditorManager::instance();
-    Core::IEditor *editor = editorManager->openEditor(fileName, Constants::PERFORCESUBMITEDITOR_KIND);
+    Core::IEditor *editor = editorManager->openEditor(fileName, Constants::PERFORCE_SUBMIT_EDITOR_KIND);
     editorManager->ensureEditorManagerVisible();
     PerforceSubmitEditor *submitEditor = static_cast<PerforceSubmitEditor*>(editor);
     submitEditor->restrictToProjectFiles(depotFileNames);
     submitEditor->registerActions(m_undoAction, m_redoAction, m_submitCurrentLogAction, m_diffSelectedFiles);
-    connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(slotDiff(QStringList)));
+    connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(slotSubmitDiff(QStringList)));
     return editor;
 }
 
@@ -581,7 +635,8 @@ void PerforcePlugin::printPendingChanges()
         const int i = dia.changeNumber();
         QStringList args(QLatin1String("submit"));
         args << QLatin1String("-c") << QString::number(i);
-        runP4Cmd(args, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+        runP4Cmd(m_settings.topLevel(), args,
+                 CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
     }
 }
 
@@ -594,29 +649,35 @@ void PerforcePlugin::describeChange()
 
 void PerforcePlugin::annotateCurrentFile()
 {
-    const QString file = currentFileName();
-    if (!file.isEmpty())
-        annotate(file);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void PerforcePlugin::annotate()
 {
-    const QString file = QFileDialog::getOpenFileName(0, tr("p4 annotate"), currentFileName());
-    if (!file.isEmpty())
-        annotate(file);
+    const QString file = QFileDialog::getOpenFileName(0, tr("p4 annotate"));
+    if (!file.isEmpty()) {
+        const QFileInfo fi(file);
+        annotate(fi.absolutePath(), fi.fileName());
+    }
 }
 
-void PerforcePlugin::annotate(const QString &fileName)
+void PerforcePlugin::annotate(const QString &workingDir, const QString &fileName)
 {
-    QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(fileName);
+    const QStringList files = QStringList(fileName);
+    QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(workingDir, files);
+    const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir, files);
+    const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files);
     QStringList args;
     args << QLatin1String("annotate") << QLatin1String("-cqi") << fileName;
-    const PerforceResponse result = runP4Cmd(args, QStringList(),
-                                             CommandToWindow|StdErrToWindow|ErrorToWindow, codec);
+    const PerforceResponse result = runP4Cmd(workingDir, args,
+                                             CommandToWindow|StdErrToWindow|ErrorToWindow,
+                                             QStringList(), QByteArray(), codec);
     if (!result.error) {
-        const int lineNumber = VCSBase::VCSBaseEditor::lineNumberOfCurrentEditor(fileName);
+        const int lineNumber = VCSBase::VCSBaseEditor::lineNumberOfCurrentEditor();
         const QFileInfo fi(fileName);
-        Core::IEditor *ed = showOutputInEditor(tr("p4 annotate %1").arg(fi.fileName()),
+        Core::IEditor *ed = showOutputInEditor(tr("p4 annotate %1").arg(id),
                                                result.stdOut, VCSBase::AnnotateOutput, codec);
         VCSBase::VCSBaseEditor::gotoLineOfEditor(ed, lineNumber);
     }
@@ -624,30 +685,32 @@ void PerforcePlugin::annotate(const QString &fileName)
 
 void PerforcePlugin::filelogCurrentFile()
 {
-    const QString file = currentFileName();
-    if (!file.isEmpty())
-        filelog(file);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    filelog(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
 }
 
 void PerforcePlugin::filelog()
 {
-    const QString file = QFileDialog::getOpenFileName(0, tr("p4 filelog"), currentFileName());
-    if (!file.isEmpty())
-        filelog(file);
+    const QString file = QFileDialog::getOpenFileName(0, tr("p4 filelog"));
+    if (!file.isEmpty()) {
+        const QFileInfo fi(file);
+        filelog(fi.absolutePath(), QStringList(fi.fileName()));
+    }
 }
 
-void PerforcePlugin::filelog(const QString &fileName)
+void PerforcePlugin::filelog(const QString &workingDir, const QStringList &fileNames)
 {
-    QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(fileName);
+    const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir, fileNames);
+    QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(workingDir, fileNames);
     QStringList args;
-    args << QLatin1String("filelog") << QLatin1String("-li") << fileName;
-    const PerforceResponse result = runP4Cmd(args, QStringList(),
-                                             CommandToWindow|StdErrToWindow|ErrorToWindow, codec);
-    if (!result.error) {
-        const QFileInfo fi(fileName);
-        showOutputInEditor(tr("p4 filelog %1").arg(fi.fileName()),
-            result.stdOut, VCSBase::LogOutput, codec);
-    }
+    args << QLatin1String("filelog") << QLatin1String("-li");
+    args.append(fileNames);
+    const PerforceResponse result = runP4Cmd(workingDir, args,
+                                             CommandToWindow|StdErrToWindow|ErrorToWindow,
+                                             QStringList(), QByteArray(), codec);
+    if (!result.error)
+        showOutputInEditor(tr("p4 filelog %1").arg(id), result.stdOut, VCSBase::LogOutput, codec);
 }
 
 void PerforcePlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
@@ -655,33 +718,21 @@ void PerforcePlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
     if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction))
         return;
 
-    const QString fileName = currentFileName();
-    const QString baseName = fileName.isEmpty() ? fileName : QFileInfo(fileName).fileName();
-
-    m_editAction->setParameter(baseName);
-    m_addAction->setParameter(baseName);
-    m_deleteAction->setParameter(baseName);
-    m_revertAction->setParameter(baseName);
-    m_diffCurrentAction->setParameter(baseName);
-    m_annotateCurrentAction->setParameter(baseName);
-    m_filelogCurrentAction->setParameter(baseName);
-
-    // The project actions refer to the current project or the projects
-    // of a session, provided there are any.
-    if (m_projectExplorer && m_projectExplorer->currentProject()) {
-        const QString currentProjectName = m_projectExplorer->currentProject()->name();
-        m_updateProjectAction->setParameter(currentProjectName);
-        m_diffProjectAction->setParameter(currentProjectName);
-        m_updateProjectAction->setEnabled(true);
-        m_diffProjectAction->setEnabled(true);
-    } else {
-        // Nope, either all projects of a session or none
-        m_updateProjectAction->setParameter(QString());
-        m_diffProjectAction->setParameter(QString());
-        const bool enabled = m_projectExplorer && m_projectExplorer->session() && !m_projectExplorer->session()->projects().empty();
-        m_updateProjectAction->setEnabled(enabled);
-        m_diffProjectAction->setEnabled(enabled);
-    }
+    const QString fileName = currentState().currentFileName();
+    m_editAction->setParameter(fileName);
+    m_addAction->setParameter(fileName);
+    m_deleteAction->setParameter(fileName);
+    m_revertFileAction->setParameter(fileName);
+    m_diffFileAction->setParameter(fileName);
+    m_annotateCurrentAction->setParameter(fileName);
+    m_filelogCurrentAction->setParameter(fileName);
+
+    const QString projectName = currentState().currentProjectName();
+    m_updateProjectAction->setParameter(projectName);
+    m_diffProjectAction->setParameter(projectName);
+    m_submitProjectAction->setParameter(projectName);
+    m_revertProjectAction->setParameter(projectName);
+    m_revertUnchangedAction->setParameter(projectName);
 
     m_diffAllAction->setEnabled(true);
     m_openedAction->setEnabled(true);
@@ -692,56 +743,73 @@ void PerforcePlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
     m_updateAllAction->setEnabled(true);
 }
 
-bool PerforcePlugin::managesDirectory(const QString &directory) const
+bool PerforcePlugin::managesDirectory(const QString &directory)
 {
-    if (!checkP4Configuration())
+    if (!m_settings.isValid())
         return false;
-    const QString p4Path = directory + QLatin1String("/...");
-    QStringList args;
-    args << QLatin1String("fstat") << QLatin1String("-m1") << p4Path;
-
-    const PerforceResponse result = runP4Cmd(args, QStringList(), 0u);
-    return result.stdOut.contains("depotFile") || result.stdErr.contains("... - no such file(s)");
+    // Cached?
+    const ManagedDirectoryCache::const_iterator cit = m_managedDirectoryCache.constFind(directory);
+    if (cit != m_managedDirectoryCache.constEnd())
+        return cit.value();
+    // Determine value and insert into cache
+    bool managed = false;
+    do {
+        // Quick check: Must be at or below top level and not "../../other_path"
+        const QStringList relativeDirArgs = m_settings.relativeToTopLevelArguments(directory);
+        if (!relativeDirArgs.empty() && relativeDirArgs.front().startsWith(QLatin1String("..")))
+            break;
+        // Is it actually managed by perforce?
+        QStringList args;
+        args << QLatin1String("fstat") << QLatin1String("-m1") << perforceRelativeFileArguments(relativeDirArgs);
+        const PerforceResponse result = runP4Cmd(m_settings.topLevel(), args,
+                                                 RunFullySynchronous);
+        managed = result.stdOut.contains("depotFile") || result.stdErr.contains("... - no such file(s)");
+    } while(false);
+
+    m_managedDirectoryCache.insert(directory, managed);
+    return managed;
 }
 
-QString PerforcePlugin::findTopLevelForDirectory(const QString & /* dir */) const
+QString PerforcePlugin::findTopLevelForDirectory(const QString &dir)
 {
-    // First check with p4 client -o
-    PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("client") << QLatin1String("-o"), QStringList(), 0u);
-    if (result.error)
-        return QString::null;
-
-    QRegExp regExp(QLatin1String("(\\n|\\r\\n|\\r)Root:\\s*(.*)(\\n|\\r\\n|\\r)"));
-    QTC_ASSERT(regExp.isValid(), /**/);
-    regExp.setMinimal(true);
-    if (regExp.indexIn(result.stdOut) != -1) {
-        QString file = regExp.cap(2).trimmed();
-        if (QFileInfo(file).exists())
-            return file;
-    }
-    return QString::null;
+    if (!m_settings.isValid())
+        return QString();
+    return managesDirectory(dir) ? m_settings.topLevelSymLinkTarget() : QString();
 }
 
-bool PerforcePlugin::vcsOpen(const QString &fileName)
+bool PerforcePlugin::vcsOpen(const QString &workingDir, const QString &fileName)
 {
-    PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("edit") << QDir::toNativeSeparators(fileName), QStringList(),
+    if (Perforce::Constants::debug)
+        qDebug() << "PerforcePlugin::vcsOpen" << workingDir << fileName;
+    QStringList args;
+    args << QLatin1String("edit") << QDir::toNativeSeparators(fileName);
+    const PerforceResponse result = runP4Cmd(workingDir, args,
                                        CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
     return !result.error;
 }
 
-bool PerforcePlugin::vcsAdd(const QString &fileName)
+bool PerforcePlugin::vcsAdd(const QString &workingDir, const QString &fileName)
 {
-    PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("add") << fileName, QStringList(),
+    QStringList args;
+    args << QLatin1String("add") << fileName;
+    const PerforceResponse result = runP4Cmd(workingDir, args,
                                        CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
     return !result.error;
 }
 
-bool PerforcePlugin::vcsDelete(const QString &fileName)
+bool PerforcePlugin::vcsDelete(const QString &workingDir, const QString &fileName)
 {
-    PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(),
+
+    QStringList args;
+    args << QLatin1String("revert") << fileName;
+    const PerforceResponse revertResult = runP4Cmd(workingDir, args,
                                        CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
-    PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("delete") << fileName, QStringList(),
-                                        CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    if (revertResult.error)
+        return false;
+    args.clear();
+    args << QLatin1String("delete") << fileName;
+    const PerforceResponse deleteResult = runP4Cmd(workingDir, args,
+                                             CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
     // TODO need to carefully parse the actual messages from perforce
     // or do a fstat before to decide what to do
 
@@ -749,7 +817,7 @@ bool PerforcePlugin::vcsDelete(const QString &fileName)
     // File is in depot and unopened => p4 delete %
     // File is in depot and opened => p4 revert %, p4 delete %
     // File is not in depot => p4 revert %
-    return !(result.error && result2.error);
+    return !deleteResult.error;
 }
 
 static QString formatCommand(const QString &cmd, const QStringList &args)
@@ -761,66 +829,97 @@ static QString formatCommand(const QString &cmd, const QStringList &args)
     return PerforcePlugin::tr("Executing: %1\n").arg(command);
 }
 
-PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args,
-                                          const QStringList &extraArgs,
-                                          unsigned logFlags,
-                                          QTextCodec *outputCodec) const
+// Write extra args to temporary file
+QSharedPointer<QTemporaryFile>
+        PerforcePlugin::createTemporaryArgumentFile(const QStringList &extraArgs) const
 {
-    if (Perforce::Constants::debug)
-        qDebug() << "PerforcePlugin::runP4Cmd" << args << extraArgs << debugCodec(outputCodec);
-    PerforceResponse response;
-    response.error = true;
-    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
-    if (!checkP4Configuration(&response.message)) {
-        outputWindow->appendError(response.message);
-        return response;
+    if (extraArgs.isEmpty())
+        return QSharedPointer<QTemporaryFile>();
+    // create pattern
+    if (m_tempFilePattern.isEmpty()) {
+        m_tempFilePattern = QDir::tempPath();
+        if (!m_tempFilePattern.endsWith(QDir::separator()))
+            m_tempFilePattern += QDir::separator();
+        m_tempFilePattern += QLatin1String("qtc_p4_XXXXXX.args");
     }
-
-    // handle extra args
-    QTemporaryFile tempfile;
-    tempfile.setAutoRemove(true);
-    const QChar newLine = QLatin1Char('\n');
-    const QChar blank = QLatin1Char(' ');
-    QStringList actualArgs = m_settings.basicP4Args();
-    if (!extraArgs.isEmpty()) {
-        if (tempfile.open()) {
-            QTextStream stream(&tempfile);
-            stream << extraArgs.join(QString(newLine));
-            actualArgs << QLatin1String("-x") << tempfile.fileName();
-            tempfile.close();
-        } else {
-            qWarning()<<"Could not create temporary file. Appending all file names to command line.";
-            actualArgs << extraArgs;
-        }
+    QSharedPointer<QTemporaryFile> rc(new QTemporaryFile(m_tempFilePattern));
+    rc->setAutoRemove(true);
+    if (!rc->open()) {
+        qWarning("Could not create temporary file: %s. Appending all file names to command line.",
+                 qPrintable(rc->errorString()));
+        return QSharedPointer<QTemporaryFile>();
     }
-    actualArgs << args;
+    const int last = extraArgs.size() - 1;
+    for (int i = 0; i <= last; i++) {
+        rc->write(extraArgs.at(i).toLocal8Bit());
+        if (i != last)
+            rc->write("\n");
+    }
+    rc->close();
+    return rc;
+}
 
-    if (logFlags & CommandToWindow)
-        outputWindow->appendCommand(formatCommand(m_settings.p4Command(), actualArgs));
+// Run messages
+
+static inline QString msgNotStarted(const QString &cmd)
+{
+    return PerforcePlugin::tr("Could not start perforce '%1'. Please check your settings in the preferences.").arg(cmd);
+}
+
+static inline QString msgTimeout()
+{
+    return PerforcePlugin::tr("Perforce did not respond within timeout limit (%1 ms).").arg(p4Timeout );
+}
+
+static inline QString msgCrash()
+{
+    return PerforcePlugin::tr("The process terminated abnormally.");
+}
+
+static inline QString msgExitCode(int ex)
+{
+    return PerforcePlugin::tr("The process terminated with exit code %1.").arg(ex);
+}
+
+// Run using a SynchronousProcess, emitting signals to the message window
+PerforceResponse PerforcePlugin::synchronousProcess(const QString &workingDir,
+                                                    const QStringList &args,
+                                                    unsigned flags,
+                                                    const QByteArray &stdInput,
+                                                    QTextCodec *outputCodec) const
+{
+    QTC_ASSERT(stdInput.isEmpty(), return PerforceResponse()) // Not supported here
 
+    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
     // Run, connect stderr to the output window
     Utils::SynchronousProcess process;
     process.setTimeout(p4Timeout);
     process.setStdOutCodec(outputCodec);
-    process.setEnvironment(environment());
+    if (flags & OverrideDiffEnvironment)
+        process.setProcessEnvironment(overrideDiffEnvironmentVariable());
+    if (!workingDir.isEmpty())
+        process.setWorkingDirectory(workingDir);
 
     // connect stderr to the output window if desired
-    if (logFlags & StdErrToWindow) {
+    if (flags & StdErrToWindow) {
         process.setStdErrBufferedSignalsEnabled(true);
         connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
     }
 
     // connect stdout to the output window if desired
-    if (logFlags & StdOutToWindow) {
+    if (flags & StdOutToWindow) {
         process.setStdOutBufferedSignalsEnabled(true);
         connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
     }
-
-    const Utils::SynchronousProcessResponse sp_resp = process.run(m_settings.p4Command(), actualArgs);
+    if (Perforce::Constants::debug)
+        qDebug() << "PerforcePlugin::run syncp actual args [" << process.workingDirectory() << ']' << args;
+    const Utils::SynchronousProcessResponse sp_resp = process.run(m_settings.p4Command(), args);
     if (Perforce::Constants::debug)
         qDebug() << sp_resp;
 
+    PerforceResponse response;
     response.error = true;
+    response.exitCode = sp_resp.exitCode;
     response.stdErr = sp_resp.stdErr;
     response.stdOut = sp_resp.stdOut;
     switch (sp_resp.result) {
@@ -828,22 +927,125 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args,
         response.error = false;
         break;
     case Utils::SynchronousProcessResponse::FinishedError:
-        response.message = tr("The process terminated with exit code %1.").arg(sp_resp.exitCode);
+        response.message = msgExitCode(sp_resp.exitCode);
+        response.error = !(flags & IgnoreExitCode);
         break;
     case Utils::SynchronousProcessResponse::TerminatedAbnormally:
-        response.message = tr("The process terminated abnormally.");
+        response.message = msgCrash();
         break;
     case Utils::SynchronousProcessResponse::StartFailed:
-        response.message = tr("Could not start perforce '%1'. Please check your settings in the preferences.").arg(m_settings.p4Command());
+        response.message = msgNotStarted(m_settings.p4Command());
         break;
     case Utils::SynchronousProcessResponse::Hang:
-        response.message = tr("Perforce did not respond within timeout limit (%1 ms).").arg(p4Timeout );
+        response.message = msgCrash();
         break;
     }
+    return response;
+}
+
+// Run using a QProcess, for short queries
+PerforceResponse PerforcePlugin::fullySynchronousProcess(const QString &workingDir,
+                                                         const QStringList &args,
+                                                         unsigned flags,
+                                                         const QByteArray &stdInput,
+                                                         QTextCodec *outputCodec) const
+{
+    QProcess process;
+
+    if (flags & OverrideDiffEnvironment)
+        process.setProcessEnvironment(overrideDiffEnvironmentVariable());
+    if (!workingDir.isEmpty())
+        process.setWorkingDirectory(workingDir);
+
+    if (Perforce::Constants::debug)
+        qDebug() << "PerforcePlugin::run fully syncp actual args [" << process.workingDirectory() << ']' << args;
+
+    PerforceResponse response;
+    process.start(m_settings.p4Command(), args);
+    if (stdInput.isEmpty())
+        process.closeWriteChannel();
+
+    if (!process.waitForStarted(3000)) {
+        response.error = true;
+        response.message = msgNotStarted(m_settings.p4Command());
+        return response;
+    }
+    if (!stdInput.isEmpty()) {
+        if (process.write(stdInput) == -1) {
+            response.error = true;
+            response.message = tr("Unable to write input data to process %1: %2").arg(m_settings.p4Command(), process.errorString());
+            return response;
+        }
+        process.closeWriteChannel();
+    }
+
+    if (!process.waitForFinished(p4Timeout)) {
+        PerforceChecker::ensureProcessStopped(process);
+        response.error = true;
+        response.message = msgTimeout();
+        return response;
+    }
+    if (process.exitStatus() != QProcess::NormalExit) {
+        response.error = true;
+        response.message = msgCrash();
+        return response;
+    }
+    response.exitCode = process.exitCode();
+    response.error = response.exitCode ? !(flags & IgnoreExitCode) : false;
+    response.stdErr = QString::fromLocal8Bit(process.readAllStandardError());
+    const QByteArray stdOut = process.readAllStandardOutput();
+    response.stdOut = outputCodec ? outputCodec->toUnicode(stdOut.constData(), stdOut.size()) :
+                                    QString::fromLocal8Bit(stdOut);
+    // Logging
+    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
+    if ((flags & StdErrToWindow) && !response.stdErr.isEmpty())
+        outputWindow->append(response.stdErr);
+    if ((flags & StdOutToWindow) && !response.stdOut.isEmpty())
+        outputWindow->append(response.stdOut);
+    return response;
+}
+
+PerforceResponse PerforcePlugin::runP4Cmd(const QString &workingDir,
+                                          const QStringList &args,
+                                          unsigned flags,
+                                          const QStringList &extraArgs,
+                                          const QByteArray &stdInput,
+                                          QTextCodec *outputCodec) const
+{
+    if (Perforce::Constants::debug)
+        qDebug() << "PerforcePlugin::runP4Cmd [" << workingDir << ']' << args << extraArgs << stdInput << debugCodec(outputCodec);
+
+    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
+    if (!m_settings.isValid()) {
+        PerforceResponse invalidConfigResponse;
+        invalidConfigResponse.error = true;
+        invalidConfigResponse.message = tr("Perforce is not correctly configured.");
+        outputWindow->appendError(invalidConfigResponse.message);
+        return invalidConfigResponse;
+    }
+    QStringList actualArgs = m_settings.commonP4Arguments(workingDir);
+    QSharedPointer<QTemporaryFile> tempFile = createTemporaryArgumentFile(extraArgs);
+    if (!tempFile.isNull())
+        actualArgs << QLatin1String("-x") << tempFile->fileName();
+    actualArgs.append(args);
+
+    if (flags & CommandToWindow)
+        outputWindow->appendCommand(formatCommand(m_settings.p4Command(), actualArgs));
+
+    if (flags & ShowBusyCursor)
+        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+
+    const PerforceResponse  response = (flags & RunFullySynchronous)  ?
+        fullySynchronousProcess(workingDir, actualArgs, flags, stdInput, outputCodec) :
+        synchronousProcess(workingDir, actualArgs, flags, stdInput, outputCodec);
+
+    if (flags & ShowBusyCursor)
+        QApplication::restoreOverrideCursor();
+
     if (response.error) {
         if (Perforce::Constants::debug)
             qDebug() << response.message;
-        if (logFlags & ErrorToWindow)
+        if (flags & ErrorToWindow)
             outputWindow->appendError(response.message);
     }
     return response;
@@ -871,68 +1073,47 @@ Core::IEditor * PerforcePlugin::showOutputInEditor(const QString& title, const Q
     return ie;
 }
 
-QStringList PerforcePlugin::environment() const
+void PerforcePlugin::slotSubmitDiff(const QStringList &files)
 {
-    QStringList newEnv = QProcess::systemEnvironment();
-    const QString name = "P4DIFF";
-    for (int i = 0; i < newEnv.count(); ++i) {
-        if (newEnv.at(i).startsWith(name)) {
-            newEnv.removeAt(i);
-            return newEnv;
-        }
-    }
-    return newEnv;
-}
-
-void PerforcePlugin::slotDiff(const QStringList &files)
-{
-    p4Diff(files);
+    p4Diff(m_commitWorkingDirectory, files);
 }
 
-void PerforcePlugin::p4Diff(const QStringList &files, QString diffname)
+void PerforcePlugin::p4Diff(const QString &workingDir, const QStringList &files)
 {
-    Core::IEditor *editor = 0;
-    bool displayInEditor = true;
     Core::IEditor *existingEditor = 0;
-    QTextCodec *codec = files.empty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(files.front());
-    if (Perforce::Constants::debug)
-        qDebug() << Q_FUNC_INFO << files << debugCodec(codec);
-
-    // diff of a single file? re-use an existing view if possible to support the common
-    // usage pattern of continuously changing and diffing a file
-    if (files.count() == 1) {
-        const QString fileName = files.at(0);
-        if (diffname.isEmpty()) {
-            const QFileInfo fi(fileName);
-            diffname = fi.fileName();
-        }
 
-        foreach (Core::IEditor *ed, Core::EditorManager::instance()->openedEditors()) {
-            if (ed->file()->property("originalFileName").toString() == fileName) {
-                existingEditor = ed;
-                displayInEditor = false;
-                break;
-            }
+    QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(workingDir, files);
+    const QString id = VCSBase::VCSBaseEditor::getTitleId(workingDir, files);
+    const QString source = VCSBase::VCSBaseEditor::getSource(workingDir, files);
+
+    // Reuse existing editors for that id
+    foreach (Core::IEditor *ed, Core::EditorManager::instance()->openedEditors()) {
+        if (ed->file()->property("originalFileName").toString() == id) {
+            existingEditor = ed;
+            break;
         }
     }
-
-    const PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("diff") << QLatin1String("-du"), files, CommandToWindow|StdErrToWindow|ErrorToWindow, codec);
+    // Split arguments according to size
+    QStringList args;
+    args << QLatin1String("diff") << QLatin1String("-du");
+    QStringList extraArgs;
+    if (files.size() > 1) {
+        extraArgs = files;
+    } else {
+        args.append(files);
+    }
+    const unsigned flags = CommandToWindow|StdErrToWindow|ErrorToWindow|OverrideDiffEnvironment;
+    const PerforceResponse result = runP4Cmd(workingDir, args, flags,
+                                             extraArgs, QByteArray(), codec);
     if (result.error)
         return;
 
-    if (displayInEditor)
-        editor = showOutputInEditor(tr("p4 diff %1").arg(diffname), result.stdOut, VCSBase::DiffOutput, codec);
-
-
-    if (files.count() == 1) {
-        if (displayInEditor && editor != 0) {
-            editor->file()->setProperty("originalFileName", files.at(0));
-        } else if (!displayInEditor && existingEditor) {
-            if (existingEditor) {
-                existingEditor->createNew(result.stdOut);
-                Core::EditorManager::instance()->activateEditor(existingEditor);
-            }
-        }
+    if (existingEditor) {
+        existingEditor->createNew(result.stdOut);
+        Core::EditorManager::instance()->activateEditor(existingEditor);
+    } else {
+        Core::IEditor *editor = showOutputInEditor(tr("p4 diff %1").arg(id), result.stdOut, VCSBase::DiffOutput, codec);
+        editor->file()->setProperty("originalFileName", id);
     }
 }
 
@@ -941,7 +1122,8 @@ void PerforcePlugin::describe(const QString & source, const QString &n)
     QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(source);
     QStringList args;
     args << QLatin1String("describe") << QLatin1String("-du") << n;
-    const PerforceResponse result = runP4Cmd(args, QStringList(), CommandToWindow|StdErrToWindow|ErrorToWindow, codec);
+    const PerforceResponse result = runP4Cmd(m_settings.topLevel(), args, CommandToWindow|StdErrToWindow|ErrorToWindow,
+                                             QStringList(), QByteArray(), codec);
     if (!result.error)
         showOutputInEditor(tr("p4 describe %1").arg(n), result.stdOut, VCSBase::DiffOutput, codec);
 }
@@ -958,6 +1140,7 @@ void PerforcePlugin::cleanCommitMessageFile()
     if (!m_commitMessageFileName.isEmpty()) {
         QFile::remove(m_commitMessageFileName);
         m_commitMessageFileName.clear();
+        m_commitWorkingDirectory.clear();
     }
 }
 
@@ -974,164 +1157,98 @@ bool PerforcePlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *subm
     const PerforceSubmitEditor *perforceEditor = qobject_cast<PerforceSubmitEditor *>(submitEditor);
     if (!fileIFace || !perforceEditor)
         return true;
-    const QFileInfo editorFile(fileIFace->fileName());
-    const QFileInfo changeFile(m_commitMessageFileName);
-    if (editorFile.absoluteFilePath() == changeFile.absoluteFilePath()) {
-        // Prompt the user. Force a prompt unless submit was actually invoked (that
-        // is, the editor was closed or shutdown).
-        bool wantsPrompt = m_settings.promptToSubmit();
-         const VCSBase::VCSBaseSubmitEditor::PromptSubmitResult answer =
+    // Prompt the user. Force a prompt unless submit was actually invoked (that
+    // is, the editor was closed or shutdown).
+    bool wantsPrompt = m_settings.promptToSubmit();
+    const VCSBase::VCSBaseSubmitEditor::PromptSubmitResult answer =
             perforceEditor->promptSubmit(tr("Closing p4 Editor"),
                                          tr("Do you want to submit this change list?"),
                                          tr("The commit message check failed. Do you want to submit this change list"),
                                          &wantsPrompt, !m_submitActionTriggered);
-         m_submitActionTriggered = false;
+    m_submitActionTriggered = false;
 
-        if (answer == VCSBase::VCSBaseSubmitEditor::SubmitCanceled)
-            return false;
+    if (answer == VCSBase::VCSBaseSubmitEditor::SubmitCanceled)
+        return false;
 
-        // Set without triggering the checking mechanism
-        if (wantsPrompt != m_settings.promptToSubmit()) {
-            m_settings.setPromptToSubmit(wantsPrompt);
-            m_settings.toSettings(Core::ICore::instance()->settings());
-        }
-        Core::FileManager *fileManager = Core::ICore::instance()->fileManager();
-        fileManager->blockFileChange(fileIFace);
-        fileIFace->save();
-        fileManager->unblockFileChange(fileIFace);
-        if (answer == VCSBase::VCSBaseSubmitEditor::SubmitConfirmed) {
-            QFile commitMessageFile(m_commitMessageFileName);
-            if (!commitMessageFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
-                VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot open temporary file."));
-                return false;
-            }
-            QByteArray change = commitMessageFile.readAll();
-            commitMessageFile.close();
-            QString errorMessage;
-            if (!checkP4Configuration(&errorMessage)) {
-                VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
-                return false;
-            }
-            QProcess proc;
-            proc.setEnvironment(environment());
-
-            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
-            QStringList submitArgs = m_settings.basicP4Args();
-            submitArgs << QLatin1String("submit") << QLatin1String("-i");
-            VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(m_settings.p4Command(), submitArgs));
-            proc.start(m_settings.p4Command(),submitArgs);
-            if (!proc.waitForStarted(p4Timeout)) {
-                VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot execute p4 submit."));
-                QApplication::restoreOverrideCursor();
-                return false;
-            }
-            proc.write(change);
-            proc.closeWriteChannel();
-
-            if (!proc.waitForFinished()) {
-                VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot execute p4 submit."));
-                QApplication::restoreOverrideCursor();
-                return false;
-            }
-            const int exitCode = proc.exitCode();
-            if (exitCode) {
-                VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("p4 submit failed (exit code %1).").arg(exitCode));
-                QApplication::restoreOverrideCursor();
-                return false;
-            }
-            const QString output = QString::fromLocal8Bit(proc.readAll());
-            VCSBase::VCSBaseOutputWindow::instance()->append(output);
-            if (output.contains(QLatin1String("Out of date files must be resolved or reverted)"))) {
-                QMessageBox::warning(submitEditor->widget(), tr("Pending change"), tr("Could not submit the change, because your workspace was out of date. Created a pending submit instead."));
-            }
-            QApplication::restoreOverrideCursor();
-        }
+    // Set without triggering the checking mechanism
+    if (wantsPrompt != m_settings.promptToSubmit()) {
+        m_settings.setPromptToSubmit(wantsPrompt);
+        m_settings.toSettings(Core::ICore::instance()->settings());
+    }
+    Core::FileManager *fileManager = Core::ICore::instance()->fileManager();
+    fileManager->blockFileChange(fileIFace);
+    fileIFace->save();
+    fileManager->unblockFileChange(fileIFace);
+    if (answer == VCSBase::VCSBaseSubmitEditor::SubmitDiscarded) {
         cleanCommitMessageFile();
+        return true;
+    }
+    // Pipe file into p4 submit -i
+    QFile commitMessageFile(m_commitMessageFileName);
+    if (!commitMessageFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot open temporary file."));
+        return false;
     }
-    return true;
-}
 
-void PerforcePlugin::openFiles(const QStringList &files)
-{
-    Core::EditorManager *em = Core::EditorManager::instance();
-    foreach (const QString &s, files)
-        em->openEditor(clientFilePath(s));
-    em->ensureEditorManagerVisible();
+    const QByteArray changeDescription = commitMessageFile.readAll();
+    commitMessageFile.close();
+    QStringList submitArgs;
+    submitArgs << QLatin1String("submit") << QLatin1String("-i");
+    const PerforceResponse submitResponse = runP4Cmd(m_settings.topLevelSymLinkTarget(), submitArgs,
+                                                     RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow|ShowBusyCursor,
+                                                     QStringList(), changeDescription);
+    if (submitResponse.error) {
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("p4 submit failed: %1").arg(submitResponse.message));
+        return false;
+    }
+    VCSBase::VCSBaseOutputWindow::instance()->append(submitResponse.stdOut);
+    if (submitResponse.stdOut.contains(QLatin1String("Out of date files must be resolved or reverted)")))
+        QMessageBox::warning(submitEditor->widget(), tr("Pending change"), tr("Could not submit the change, because your workspace was out of date. Created a pending submit instead."));
+
+    cleanCommitMessageFile();
+    return true;
 }
 
 QString PerforcePlugin::clientFilePath(const QString &serverFilePath)
 {
-    if (!checkP4Configuration())
-        return QString();
+    QTC_ASSERT(m_settings.isValid(), return QString())
 
-    QApplication::setOverrideCursor(Qt::WaitCursor);
-    QProcess proc;
-    proc.setEnvironment(environment());
-    proc.start(m_settings.p4Command(),
-        m_settings.basicP4Args() << QLatin1String("fstat") << serverFilePath);
-
-    QString path;
-    if (proc.waitForFinished(3000)) {
-        QString output = QString::fromUtf8(proc.readAllStandardOutput());
-        if (!output.isEmpty()) {
-            QRegExp r(QLatin1String("\\.\\.\\.\\sclientFile\\s(.+)\n"));
-            r.setMinimal(true);
-            if (r.indexIn(output) != -1)
-                path = r.cap(1).trimmed();
-        }
-    }
-    QApplication::restoreOverrideCursor();
+    QStringList args;
+    args << QLatin1String("fstat") << serverFilePath;
+    const PerforceResponse response = runP4Cmd(m_settings.topLevelSymLinkTarget(), args,
+                                               ShowBusyCursor|RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow);
+    if (response.error)
+        return QString::null;
+
+    QRegExp r(QLatin1String("\\.\\.\\.\\sclientFile\\s(.+)\n"));
+    r.setMinimal(true);
+    const QString path = r.indexIn(response.stdOut) != -1 ? r.cap(1).trimmed() : QString();
+    if (Perforce::Constants::debug)
+        qDebug() << "clientFilePath" << serverFilePath << path;
     return path;
 }
 
-QString PerforcePlugin::currentFileName()
+QString PerforcePlugin::pendingChangesData()
 {
-    QString fileName = Core::ICore::instance()->fileManager()->currentFile();
+    QTC_ASSERT(m_settings.isValid(), return QString())
 
-    // TODO: Use FileManager::fixPath
-    const QFileInfo fileInfo(fileName);
-    if (fileInfo.exists())
-        fileName = fileInfo.absoluteFilePath();
-    fileName = QDir::toNativeSeparators(fileName);
-    return fileName;
-}
-
-bool PerforcePlugin::checkP4Configuration(QString *errorMessage /* = 0 */) const
-{
-    if (m_settings.isValid())
-        return true;
-    if (errorMessage)
-        *errorMessage = tr("Invalid configuration: %1").arg(m_settings.errorString());
-    return false;
-}
+    QStringList args = QStringList(QLatin1String("info"));
+    const PerforceResponse userResponse = runP4Cmd(m_settings.topLevelSymLinkTarget(), args,
+                                               RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow);
+    if (userResponse.error)
+        return QString::null;
 
-QString PerforcePlugin::pendingChangesData()
-{
-    QString data;
-    if (!checkP4Configuration())
-        return data;
-
-    QString user;
-    QProcess proc;
-    proc.setEnvironment(environment());
-    proc.start(m_settings.p4Command(),
-        m_settings.basicP4Args() << QLatin1String("info"));
-    if (proc.waitForFinished(3000)) {
-        QString output = QString::fromUtf8(proc.readAllStandardOutput());
-        if (!output.isEmpty()) {
-            QRegExp r(QLatin1String("User\\sname:\\s(\\S+)\\s*\n"));
-            r.setMinimal(true);
-            if (r.indexIn(output) != -1)
-                user = r.cap(1).trimmed();
-        }
-    }
+    QRegExp r(QLatin1String("User\\sname:\\s(\\S+)\\s*\n"));
+    QTC_ASSERT(r.isValid(), return QString())
+    r.setMinimal(true);
+    const QString user = r.indexIn(userResponse.stdOut) != -1 ? r.cap(1).trimmed() : QString::null;
     if (user.isEmpty())
-        return data;
-    proc.start(m_settings.p4Command(),
-        m_settings.basicP4Args() << QLatin1String("changes") << QLatin1String("-s") << QLatin1String("pending") << QLatin1String("-u") << user);
-    if (proc.waitForFinished(3000))
-        data = QString::fromUtf8(proc.readAllStandardOutput());
-    return data;
+        return QString::null;
+    args.clear();
+    args << QLatin1String("changes") << QLatin1String("-s") << QLatin1String("pending") << QLatin1String("-u") << user;
+    const PerforceResponse dataResponse = runP4Cmd(m_settings.topLevelSymLinkTarget(), args,
+                                                   RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow);
+    return dataResponse.error ? QString::null : dataResponse.stdOut;
 }
 
 PerforcePlugin::~PerforcePlugin()
@@ -1147,10 +1264,17 @@ void PerforcePlugin::setSettings(const Settings &newSettings)
 {
     if (newSettings != m_settings.settings()) {
         m_settings.setSettings(newSettings);
+        m_managedDirectoryCache.clear();
         m_settings.toSettings(Core::ICore::instance()->settings());
+        getTopLevel();
     }
 }
 
+static inline QString msgWhereFailed(const QString & file, const QString &why)
+{
+    return PerforcePlugin::tr("Error running \"where\" on %1: %2").arg(file, why);
+}
+
 // Map a perforce name "//xx" to its real name in the file system
 QString PerforcePlugin::fileNameFromPerforceName(const QString& perforceName,
                                                  QString *errorMessage) const
@@ -1159,28 +1283,29 @@ QString PerforcePlugin::fileNameFromPerforceName(const QString& perforceName,
     if (!perforceName.startsWith(QLatin1String("//")))
         return perforceName;
     // "where" remaps the file to client file tree
-    QProcess proc;
-    QStringList args(m_settings.basicP4Args());
+    QStringList args;
     args << QLatin1String("where") << perforceName;
-    proc.start(m_settings.p4Command(), args);
-    if (!proc.waitForFinished()) {
-        *errorMessage = tr("Timeout waiting for \"where\" (%1).").arg(perforceName);
-        return QString();
+    const PerforceResponse response = runP4Cmd(m_settings.topLevelSymLinkTarget(), args,
+                                               RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow);
+    if (response.error) {
+        *errorMessage = msgWhereFailed(perforceName, response.message);
+        return QString::null;
     }
 
-    QString output = QString::fromLocal8Bit(proc.readAllStandardOutput());
+    QString output = response.stdOut;
     if (output.endsWith(QLatin1Char('\r')))
         output.chop(1);
     if (output.endsWith(QLatin1Char('\n')))
         output.chop(1);
 
     if (output.isEmpty()) {
-        *errorMessage = tr("Error running \"where\" on %1: The file is not mapped").arg(perforceName);
+        *errorMessage = msgWhereFailed(perforceName, tr("The file is not mapped"));
         return QString();
     }
-    const QString rc = output.mid(output.lastIndexOf(QLatin1Char(' ')) + 1);
+    const QString p4fileSpec = output.mid(output.lastIndexOf(QLatin1Char(' ')) + 1);
+    const QString rc = m_settings.mapToFileSystem(p4fileSpec);
     if (Perforce::Constants::debug)
-        qDebug() << "fileNameFromPerforceName" << perforceName << rc;
+        qDebug() << "fileNameFromPerforceName" << perforceName << p4fileSpec << rc;
     return rc;
 }
 
@@ -1195,5 +1320,35 @@ PerforceVersionControl *PerforcePlugin::perforceVersionControl() const
     return static_cast<PerforceVersionControl *>(versionControl());
 }
 
-Q_EXPORT_PLUGIN(PerforcePlugin)
+void PerforcePlugin::slotTopLevelFound(const QString &t)
+{
+    m_settings.setTopLevel(t);
+    VCSBase::VCSBaseOutputWindow::instance()->appendSilently(tr("Perforce repository: %1").arg(t));
+    if (Perforce::Constants::debug)
+        qDebug() << "P4: " << t;
+}
+
+void PerforcePlugin::slotTopLevelFailed(const QString &errorMessage)
+{
+    VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Perforce: Unable to determine the repository: %1").arg(errorMessage));
+    if (Perforce::Constants::debug)
+        qDebug() << errorMessage;
+}
+
+void PerforcePlugin::getTopLevel()
+{
+    // Run a new checker
+    if (m_settings.p4Command().isEmpty())
+        return;
+    PerforceChecker *checker = new PerforceChecker(this);
+    connect(checker, SIGNAL(failed(QString)), this, SLOT(slotTopLevelFailed(QString)));
+    connect(checker, SIGNAL(failed(QString)), checker, SLOT(deleteLater()));
+    connect(checker, SIGNAL(succeeded(QString)), this, SLOT(slotTopLevelFound(QString)));
+    connect(checker, SIGNAL(succeeded(QString)),checker, SLOT(deleteLater()));
+    checker->start(m_settings.p4Command(), m_settings.commonP4Arguments(QString()), 30000);
+}
+
+}
+}
 
+Q_EXPORT_PLUGIN(Perforce::Internal::PerforcePlugin)
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
index 2aba09194c0c03df54e4a2bf7733698f468f786b..ca184caef21b6cdd9dd248d65cbb9a1958203db1 100644
--- a/src/plugins/perforce/perforceplugin.h
+++ b/src/plugins/perforce/perforceplugin.h
@@ -35,16 +35,18 @@
 #include <coreplugin/editormanager/ieditorfactory.h>
 #include <coreplugin/iversioncontrol.h>
 #include <vcsbase/vcsbaseplugin.h>
-#include <projectexplorer/projectexplorer.h>
 
 #include <QtCore/QObject>
 #include <QtCore/QProcess>
 #include <QtCore/QStringList>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QHash>
 
 QT_BEGIN_NAMESPACE
 class QFile;
 class QAction;
 class QTextCodec;
+class QTemporaryFile;
 QT_END_NAMESPACE
 
 namespace Utils {
@@ -58,7 +60,10 @@ class PerforceVersionControl;
 
 struct PerforceResponse
 {
+    PerforceResponse();
+
     bool error;
+    int exitCode;
     QString stdOut;
     QString stdErr;
     QString message;
@@ -75,13 +80,13 @@ public:
     bool initialize(const QStringList &arguments, QString *error_message);
     void extensionsInitialized();
 
-    bool managesDirectory(const QString &directory) const;
-    QString findTopLevelForDirectory(const QString &directory) const;
-    bool vcsOpen(const QString &fileName);
-    bool vcsAdd(const QString &fileName);
-    bool vcsDelete(const QString &filename);
+    bool managesDirectory(const QString &directory);
+    QString findTopLevelForDirectory(const QString &directory);
+    bool vcsOpen(const QString &workingDir, const QString &fileName);
+    bool vcsAdd(const QString &workingDir, const QString &fileName);
+    bool vcsDelete(const QString &workingDir, const QString &filename);
 
-    void p4Diff(const QStringList &files, QString diffname = QString());
+    void p4Diff(const QString &workingDir, const QStringList &files);
 
     Core::IEditor *openPerforceSubmitEditor(const QString &fileName, const QStringList &depotFileNames);
 
@@ -105,9 +110,11 @@ private slots:
     void diffCurrentFile();
     void diffCurrentProject();
     void updateCurrentProject();
+    void revertCurrentProject();
+    void revertUnchangedCurrentProject();
     void updateAll();
     void diffAllOpened();
-    void submit();
+    void startSubmitProject();
     void describeChange();
     void annotateCurrentFile();
     void annotate();
@@ -116,55 +123,80 @@ private slots:
 
     void submitCurrentLog();
     void printPendingChanges();
-    void slotDiff(const QStringList &files);
+    void slotSubmitDiff(const QStringList &files);
+    void slotTopLevelFound(const QString &);
+    void slotTopLevelFailed(const QString &);
 
 protected:
     virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
     virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor);
 
+
 private:
-    QStringList environment() const;
+    typedef QHash<QString, bool> ManagedDirectoryCache;
 
     Core::IEditor *showOutputInEditor(const QString& title, const QString output,
                                       int editorType,
                                       QTextCodec *codec = 0);
 
-    // Verbosity flags for runP4Cmd.
-    enum  RunLogFlags { CommandToWindow = 0x1, StdOutToWindow = 0x2, StdErrToWindow = 0x4, ErrorToWindow = 0x8 };
+    // Flags for runP4Cmd.
+    enum RunFlags { CommandToWindow = 0x1, StdOutToWindow = 0x2,
+                    StdErrToWindow = 0x4, ErrorToWindow = 0x8,
+                    OverrideDiffEnvironment = 0x10,
+                    // Run completely synchronously, no signals emitted
+                    RunFullySynchronous = 0x20,
+                    IgnoreExitCode = 0x40,
+                    ShowBusyCursor = 0x80
+                   };
 
     // args are passed as command line arguments
     // extra args via a tempfile and the option -x "temp-filename"
-    PerforceResponse runP4Cmd(const QStringList &args,
+    PerforceResponse runP4Cmd(const QString &workingDir,
+                              const QStringList &args,
+                              unsigned flags = CommandToWindow|StdErrToWindow|ErrorToWindow,
                               const QStringList &extraArgs = QStringList(),
-                              unsigned logFlags = CommandToWindow|StdErrToWindow|ErrorToWindow,
+                              const QByteArray &stdInput = QByteArray(),
                               QTextCodec *outputCodec = 0) const;
 
-    void openFiles(const QStringList &files);
+    inline PerforceResponse synchronousProcess(const QString &workingDir,
+                                               const QStringList &args,
+                                               unsigned flags,
+                                               const QByteArray &stdInput,
+                                               QTextCodec *outputCodec) const;
+
+    inline PerforceResponse fullySynchronousProcess(const QString &workingDir,
+                                                    const QStringList &args,
+                                                    unsigned flags,
+                                                    const QByteArray &stdInput,
+                                                    QTextCodec *outputCodec) const;
 
     QString clientFilePath(const QString &serverFilePath);
-    QString currentFileName();
-    bool checkP4Configuration(QString *errorMessage = 0) const;
-    void annotate(const QString &fileName);
-    void filelog(const QString &fileName);
+    void annotate(const QString &workingDir, const QString &fileName);
+    void filelog(const QString &workingDir, const QStringList &fileNames);
     void cleanCommitMessageFile();
     bool isCommitEditorOpen() const;
+    QSharedPointer<QTemporaryFile> createTemporaryArgumentFile(const QStringList &extraArgs) const;
+    void getTopLevel();
+    QString pendingChangesData();
 
-    void updateCheckout(const QStringList &dirs = QStringList());
-    inline PerforceVersionControl *perforceVersionControl() const;
+    void updateCheckout(const QString &workingDir = QString(),
+                        const QStringList &dirs = QStringList());
+    bool revertProject(const QString &workingDir, const QStringList &args, bool unchangedOnly);
 
-    ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+    inline PerforceVersionControl *perforceVersionControl() const;
 
     Utils::ParameterAction *m_editAction;
     Utils::ParameterAction *m_addAction;
     Utils::ParameterAction *m_deleteAction;
     QAction *m_openedAction;
-    Utils::ParameterAction *m_revertAction;
-    Utils::ParameterAction *m_diffCurrentAction;
+    Utils::ParameterAction *m_revertFileAction;
+    Utils::ParameterAction *m_diffFileAction;
     Utils::ParameterAction *m_diffProjectAction;
     Utils::ParameterAction *m_updateProjectAction;
+    Utils::ParameterAction *m_revertProjectAction;
+    Utils::ParameterAction *m_revertUnchangedAction;
     QAction *m_diffAllAction;
-    QAction *m_resolveAction;
-    QAction *m_submitAction;
+    Utils::ParameterAction *m_submitProjectAction;
     QAction *m_pendingAction;
     QAction *m_describeAction;
     Utils::ParameterAction *m_annotateCurrentAction;
@@ -176,15 +208,16 @@ private:
     bool m_submitActionTriggered;
     QAction *m_diffSelectedFiles;
     QString m_commitMessageFileName;
-
+    QString m_commitWorkingDirectory;
+    mutable QString m_tempFilePattern;
     QAction *m_undoAction;
     QAction *m_redoAction;
     QAction *m_menuAction;
 
     static PerforcePlugin *m_perforcePluginInstance;
-    QString pendingChangesData();
 
     PerforceSettings m_settings;
+    ManagedDirectoryCache m_managedDirectoryCache;
 };
 
 } // namespace Perforce
diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp
index 8c72774a29db3ccdede8be20106ff78a679ae432..949857d4a379c7398f9a13ac672b62a862ab7d2c 100644
--- a/src/plugins/perforce/perforcesettings.cpp
+++ b/src/plugins/perforce/perforcesettings.cpp
@@ -28,15 +28,16 @@
 **************************************************************************/
 
 #include "perforcesettings.h"
+#include "perforceplugin.h"
+#include "perforceconstants.h"
+
+#include <utils/qtcassert.h>
 
-#include <qtconcurrent/QtConcurrentTools>
-#include <QtCore/QtConcurrentRun>
 #include <QtCore/QSettings>
 #include <QtCore/QStringList>
 #include <QtCore/QCoreApplication>
-#include <QtCore/QProcess>
-
-enum { debug = 0 };
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
 
 static const char *groupC = "Perforce";
 static const char *commandKeyC = "Command";
@@ -73,7 +74,7 @@ bool Settings::equals(const Settings &rhs) const
             && promptToSubmit == rhs.promptToSubmit;
 };
 
-QStringList Settings::basicP4Args() const
+QStringList Settings::commonP4Arguments() const
 {
     if (defaultEnv)
         return QStringList();
@@ -87,104 +88,17 @@ QStringList Settings::basicP4Args() const
     return lst;
 }
 
-bool Settings::check(QString *errorMessage) const
-{
-    return doCheck(p4Command, basicP4Args(), errorMessage);
-}
-
-// Check on a p4 view by grepping "view -o" for mapped files
-bool Settings::doCheck(const QString &binary, const QStringList &basicArgs, QString *errorMessage)
-{
-    errorMessage->clear();
-    if (binary.isEmpty()) {
-        *errorMessage = QCoreApplication::translate("Perforce::Internal",  "No executable specified");
-        return false;
-    }
-    // List the client state and check for mapped files
-    QProcess p4;
-    QStringList args = basicArgs;
-    args << QLatin1String("client") << QLatin1String("-o");
-    if (debug)
-        qDebug() << binary << args;
-    p4.start(binary, args);
-    if (!p4.waitForStarted()) {
-        *errorMessage = QCoreApplication::translate("Perforce::Internal", "Unable to launch \"%1\": %2").arg(binary, p4.errorString());
-        return false;
-    }
-    p4.closeWriteChannel();
-    const int timeOutMS = 5000;
-    if (!p4.waitForFinished(timeOutMS)) {
-        p4.kill();
-        p4.waitForFinished();
-        *errorMessage = QCoreApplication::translate("Perforce::Internal", "\"%1\" timed out after %2ms.").arg(binary).arg(timeOutMS);
-        return false;
-    }
-    if (p4.exitStatus() != QProcess::NormalExit) {
-        *errorMessage = QCoreApplication::translate("Perforce::Internal", "\"%1\" crashed.").arg(binary);
-        return false;
-    }
-    const QString stdErr = QString::fromLocal8Bit(p4.readAllStandardError());
-    if (p4.exitCode()) {
-        *errorMessage = QCoreApplication::translate("Perforce::Internal", "\"%1\" terminated with exit code %2: %3").
-                        arg(binary).arg(p4.exitCode()).arg(stdErr);
-        return false;
-
-    }
-    // List the client state and check for "View"
-    const QString response = QString::fromLocal8Bit(p4.readAllStandardOutput());
-    if (!response.contains(QLatin1String("View:")) && !response.contains(QLatin1String("//depot/"))) {
-        *errorMessage = QCoreApplication::translate("Perforce::Internal", "The client does not seem to contain any mapped files.");
-        return false;
-    }
-    return true;
-}
-
 // --------------------PerforceSettings
 PerforceSettings::PerforceSettings()
-    : m_valid(false)
 {
-    // We do all the initialization in fromSettings
 }
 
 PerforceSettings::~PerforceSettings()
 {
-    // ensure that we are not still running
-    m_future.waitForFinished();
-}
-
-bool PerforceSettings::isValid() const
-{
-    m_future.waitForFinished();
-    m_mutex.lock();
-    bool valid = m_valid;
-    m_mutex.unlock();
-    return valid;
-}
-
-void PerforceSettings::run(QFutureInterface<void> &fi)
-{
-    m_mutex.lock();
-    const QString executable = m_settings.p4Command;
-    const QStringList arguments = basicP4Args();
-    m_mutex.unlock();
-
-    QString errorString;
-    const bool isValid = Settings::doCheck(executable, arguments, &errorString);
-    if (debug)
-        qDebug() << isValid << errorString;
-
-    m_mutex.lock();
-    if (executable == m_settings.p4Command && arguments == basicP4Args()) { // Check that those settings weren't changed in between
-        m_errorString = errorString;
-        m_valid = isValid;
-    }
-    m_mutex.unlock();
-    fi.reportFinished();
 }
 
 void PerforceSettings::fromSettings(QSettings *settings)
 {
-    m_mutex.lock();
     settings->beginGroup(QLatin1String(groupC));
     m_settings.p4Command = settings->value(QLatin1String(commandKeyC), defaultCommand()).toString();
     m_settings.defaultEnv = settings->value(QLatin1String(defaultKeyC), true).toBool();
@@ -193,14 +107,10 @@ void PerforceSettings::fromSettings(QSettings *settings)
     m_settings.p4User = settings->value(QLatin1String(userKeyC), QString()).toString();
     m_settings.promptToSubmit = settings->value(QLatin1String(promptToSubmitKeyC), true).toBool();
     settings->endGroup();
-    m_mutex.unlock();
-
-    m_future = QtConcurrent::run(&PerforceSettings::run, this);
 }
 
 void PerforceSettings::toSettings(QSettings *settings) const
 {
-    m_mutex.lock();
     settings->beginGroup(QLatin1String(groupC));
     settings->setValue(QLatin1String(commandKeyC), m_settings.p4Command);
     settings->setValue(QLatin1String(defaultKeyC), m_settings.defaultEnv);
@@ -209,18 +119,13 @@ void PerforceSettings::toSettings(QSettings *settings) const
     settings->setValue(QLatin1String(userKeyC), m_settings.p4User);
     settings->setValue(QLatin1String(promptToSubmitKeyC), m_settings.promptToSubmit);
     settings->endGroup();
-    m_mutex.unlock();
 }
 
 void PerforceSettings::setSettings(const Settings &newSettings)
-{    
+{
     if (newSettings != m_settings) {
-        // trigger check
         m_settings = newSettings;
-        m_mutex.lock();
-        m_valid = false;
-        m_mutex.unlock();
-        m_future = QtConcurrent::run(&PerforceSettings::run, this);
+        clearTopLevel();
     }
 }
 
@@ -264,17 +169,87 @@ void PerforceSettings::setPromptToSubmit(bool p)
     m_settings.promptToSubmit = p;
 }
 
-QString PerforceSettings::errorString() const
+QString PerforceSettings::topLevel() const
 {
-    m_mutex.lock();
-    const QString rc = m_errorString;
-    m_mutex.unlock();
+    return m_topLevel;
+}
+
+QString PerforceSettings::topLevelSymLinkTarget() const
+{
+    return m_topLevelSymLinkTarget;
+}
+
+void PerforceSettings::setTopLevel(const QString &t)
+{
+    if (m_topLevel == t)
+        return;
+    clearTopLevel();
+    if (!t.isEmpty()) {
+        // Check/expand symlinks as creator always has expanded file paths
+        QFileInfo fi(t);
+        if (fi.isSymLink()) {
+            m_topLevel = t;
+            m_topLevelSymLinkTarget = QFileInfo(fi.symLinkTarget()).absoluteFilePath();
+        } else {
+            m_topLevelSymLinkTarget = m_topLevel = t;
+        }
+        m_topLevelDir.reset(new QDir(m_topLevelSymLinkTarget));
+        if (Perforce::Constants::debug)
+            qDebug() << "PerforceSettings::setTopLevel" << m_topLevel << m_topLevelSymLinkTarget;
+    }
+}
+
+void PerforceSettings::clearTopLevel()
+{
+    m_topLevelDir.reset();
+    m_topLevel.clear();
+}
+
+QString PerforceSettings::relativeToTopLevel(const QString &dir) const
+{
+    QTC_ASSERT(!m_topLevelDir.isNull(), return QLatin1String("../") + dir)
+    return m_topLevelDir->relativeFilePath(dir);
+}
+
+QStringList PerforceSettings::relativeToTopLevelArguments(const QString &dir) const
+{
+    const QString relative = relativeToTopLevel(dir);
+    return relative.isEmpty() ? QStringList() : QStringList(relative);
+}
+
+// Map the root part of a path:
+// Calling "/home/john/foo" with old="/home", new="/user"
+// results in "/user/john/foo"
+
+static inline QString mapPathRoot(const QString &path,
+                                  const QString &oldPrefix,
+                                  const QString &newPrefix)
+{
+    if (path.isEmpty() || oldPrefix.isEmpty() || newPrefix.isEmpty() || oldPrefix == newPrefix)
+        return path;
+    if (path == oldPrefix)
+        return newPrefix;
+    if (path.startsWith(oldPrefix))
+        return newPrefix + path.right(path.size() - oldPrefix.size());
+    return path;
+}
+
+QStringList PerforceSettings::commonP4Arguments(const QString &workingDir) const
+{
+    QStringList rc;
+    if (!workingDir.isEmpty()) {
+        /* Determine the -d argument for the working directory for matching relative paths.
+         * It is is below the toplevel, replace top level portion by exact specification. */
+        rc << QLatin1String("-d")
+           << QDir::toNativeSeparators(mapPathRoot(workingDir, m_topLevelSymLinkTarget, m_topLevel));
+    }
+    rc.append(m_settings.commonP4Arguments());
     return rc;
 }
 
-QStringList PerforceSettings::basicP4Args() const
+QString PerforceSettings::mapToFileSystem(const QString &perforceFilePath) const
 {
-    return m_settings.basicP4Args();
+    return mapPathRoot(perforceFilePath, m_topLevel, m_topLevelSymLinkTarget);
 }
 
 } // Internal
diff --git a/src/plugins/perforce/perforcesettings.h b/src/plugins/perforce/perforcesettings.h
index 06c1b46f09c8ab2fab415b5bbcc47cf461efb99b..8b6e3897cd27634ced76c9b3b1b5f861ee9ec326 100644
--- a/src/plugins/perforce/perforcesettings.h
+++ b/src/plugins/perforce/perforcesettings.h
@@ -31,10 +31,11 @@
 #define PERFOCESETTINGS_H
 
 #include <QtCore/QString>
-#include <QtCore/QFuture>
+#include <QtCore/QScopedPointer>
 
 QT_BEGIN_NAMESPACE
 class QSettings;
+class QDir;
 QT_END_NAMESPACE
 
 namespace Perforce {
@@ -43,10 +44,13 @@ namespace Internal {
 struct Settings {
     Settings();
     bool equals(const Settings &s) const;
-    QStringList basicP4Args() const;
+    QStringList commonP4Arguments() const;
 
-    bool check(QString *errorMessage) const;
-    static bool doCheck(const QString &binary, const QStringList &basicArgs, QString *errorMessage);
+    // Checks. On success, errorMessage will contains the client root.
+    bool check(QString *repositoryRoot /* = 0*/, QString *errorMessage) const;
+    static bool doCheck(const QString &binary, const QStringList &basicArgs,
+                        QString *repositoryRoot /* = 0 */,
+                        QString *errorMessage);
 
     QString p4Command;
     QString p4Port;
@@ -60,22 +64,48 @@ struct Settings {
 inline bool operator==(const Settings &s1, const Settings &s2) { return s1.equals(s2); }
 inline bool operator!=(const Settings &s1, const Settings &s2) { return !s1.equals(s2); }
 
-// PerforceSettings: Aggregates settings struct and contains a sophisticated
-// background check invoked on setSettings() to figure out whether the p4
-// configuration is actually valid (disabling it when invalid to save time
-// when updating actions. etc.)
+/* PerforceSettings: Aggregates settings struct and toplevel directory
+ * which is determined externally by background checks and provides a convenience
+ * for determining the common arguments.
+ * Those must contain (apart from server connection settings) the working directory
+ * with the "-d" option. This is because the p4 command line client detects its path
+ * from the PWD environment variable which breaks relative paths since that is set by
+ * the shell running Creator and is not necessarily that of the working directory
+ * (see p4 documentation).
+ * An additional complication is that the repository might be a symbolic link on Unix,
+ * say "$HOME/dev" linked to "/depot". If the p4 client specification contains
+ * "$HOME/dev", paths containing "/depot" will be refused as "not under client's view" by
+ * p4. This is why the client root portion of working directory must be mapped for the
+ * "-d" option, so that running p4 in "/depot/dev/foo" results in "-d $HOME/dev/foo". */
 
 class PerforceSettings {
+    Q_DISABLE_COPY(PerforceSettings);
 public:
     PerforceSettings();
     ~PerforceSettings();
+
+    inline bool isValid() const { return !m_topLevel.isEmpty(); }
+
     void fromSettings(QSettings *settings);
     void toSettings(QSettings *) const;
 
     void setSettings(const Settings &s);
     Settings settings() const;
 
-    bool isValid() const;
+    QString topLevel() const;
+    QString topLevelSymLinkTarget() const;
+
+    void setTopLevel(const QString &);
+
+    // Return relative path to top level. Returns "" if it is the same directory,
+    // ".." if it is not within.
+    QString relativeToTopLevel(const QString &dir) const;
+    // Return argument list relative to top level (empty meaning,
+    // it is the same directory).
+    QStringList relativeToTopLevelArguments(const QString &dir) const;
+
+    // Map p4 path back to file system in case of a symlinked top-level
+    QString mapToFileSystem(const QString &perforceFilePath) const;
 
     QString p4Command() const;
     QString p4Port() const;
@@ -85,21 +115,17 @@ public:
     bool promptToSubmit() const;
     void setPromptToSubmit(bool p);
 
-    QStringList basicP4Args() const;
-
-    // Error code of last check
-    QString errorString() const;
+    // Return basic arguments, including -d and server connection parameters.
+    QStringList commonP4Arguments(const QString &workingDir) const;
 
 private:
-    void run(QFutureInterface<void> &fi);
-
-    mutable QFuture<void> m_future;
-    mutable QMutex m_mutex;
+    inline QStringList workingDirectoryArguments(const QString &workingDir) const;
+    void clearTopLevel();
 
     Settings m_settings;
-    QString m_errorString;
-    bool m_valid;
-    Q_DISABLE_COPY(PerforceSettings);
+    QString m_topLevel;
+    QString m_topLevelSymLinkTarget;
+    QScopedPointer<QDir> m_topLevelDir;
 };
 
 } // Internal
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
index f5424082810328d52e7abcc168b5fb4ce4df4d78..0fe7bb6a07c27ba1c21c295e0eb82fc3aa289176 100644
--- a/src/plugins/perforce/perforceversioncontrol.cpp
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -29,6 +29,10 @@
 
 #include "perforceversioncontrol.h"
 #include "perforceplugin.h"
+#include "perforceconstants.h"
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
 
 namespace Perforce {
 namespace Internal {
@@ -38,7 +42,7 @@ PerforceVersionControl::PerforceVersionControl(PerforcePlugin *plugin) :
     m_plugin(plugin)
 {
 }
-    
+
 QString PerforceVersionControl::name() const
 {
     return QLatin1String("perforce");
@@ -58,27 +62,36 @@ bool PerforceVersionControl::supportsOperation(Operation operation) const
 
 bool PerforceVersionControl::vcsOpen(const QString &fileName)
 {
-    return m_plugin->vcsOpen(fileName);
+    const QFileInfo fi(fileName);
+    return m_plugin->vcsOpen(fi.absolutePath(), fi.fileName());
 }
 
 bool PerforceVersionControl::vcsAdd(const QString &fileName)
 {
-    return m_plugin->vcsAdd(fileName);
+    const QFileInfo fi(fileName);
+    return m_plugin->vcsAdd(fi.absolutePath(), fi.fileName());
 }
 
 bool PerforceVersionControl::vcsDelete(const QString &fileName)
 {
-    return m_plugin->vcsDelete(fileName);
+    const QFileInfo fi(fileName);
+    return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
 }
 
 bool PerforceVersionControl::managesDirectory(const QString &directory) const
 {
-    return m_plugin->managesDirectory(directory);
+    const bool rc = m_plugin->managesDirectory(directory);
+    if (Perforce::Constants::debug)
+        qDebug() << "managesDirectory" << directory << rc;
+    return rc;
 }
 
 QString PerforceVersionControl::findTopLevelForDirectory(const QString &directory) const
 {
-    return m_plugin->findTopLevelForDirectory(directory);
+    const QString rc = m_plugin->findTopLevelForDirectory(directory);
+    if (Perforce::Constants::debug)
+        qDebug() << "findTopLevelForDirectory" << directory << rc;
+    return rc;
 }
 
 void PerforceVersionControl::emitRepositoryChanged(const QString &s)
diff --git a/src/plugins/perforce/settingspage.cpp b/src/plugins/perforce/settingspage.cpp
index 41a5239bc3f89dae669970b724b7a375201f785e..ede4c7012f60cd51063d85ab4cfc70e07e45d27e 100644
--- a/src/plugins/perforce/settingspage.cpp
+++ b/src/plugins/perforce/settingspage.cpp
@@ -30,6 +30,7 @@
 #include "settingspage.h"
 #include "perforcesettings.h"
 #include "perforceplugin.h"
+#include "perforcechecker.h"
 
 #include <vcsbase/vcsbaseconstants.h>
 
@@ -52,15 +53,24 @@ SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
 
 void SettingsPageWidget::slotTest()
 {
-    QString message;
-    QApplication::setOverrideCursor(Qt::BusyCursor);
-    setStatusText(true, tr("Testing..."));
-    QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
-    const bool ok = settings().check(&message);
-    QApplication::restoreOverrideCursor();
-    if (ok)
-        message = tr("Test succeeded.");
-    setStatusText(ok, message);
+    if (!m_checker) {
+        m_checker = new PerforceChecker(this);
+        m_checker->setUseOverideCursor(true);
+        connect(m_checker.data(), SIGNAL(failed(QString)), this, SLOT(setStatusError(QString)));
+        connect(m_checker.data(), SIGNAL(succeeded(QString)), this, SLOT(testSucceeded(QString)));
+    }
+
+    if (m_checker->isRunning())
+        return;
+
+    setStatusText(tr("Testing..."));
+    const Settings s = settings();
+    m_checker->start(s.p4Command, s.commonP4Arguments(), 10000);
+}
+
+void SettingsPageWidget::testSucceeded(const QString &repo)
+{
+    setStatusText(tr("Test succeeded (%1).").arg(repo));
 }
 
 Settings SettingsPageWidget::settings() const
@@ -83,13 +93,17 @@ void SettingsPageWidget::setSettings(const PerforceSettings &s)
     m_ui.clientLineEdit->setText(s.p4Client());
     m_ui.userLineEdit->setText(s.p4User());
     m_ui.promptToSubmitCheckBox->setChecked(s.promptToSubmit());
-    const QString errorString = s.errorString();
-    setStatusText(errorString.isEmpty(), errorString);
 }
 
-void SettingsPageWidget::setStatusText(bool ok, const QString &t)
+void SettingsPageWidget::setStatusText(const QString &t)
+{
+    m_ui.errorLabel->setStyleSheet(QString::null);
+    m_ui.errorLabel->setText(t);
+}
+
+void SettingsPageWidget::setStatusError(const QString &t)
 {
-    m_ui.errorLabel->setStyleSheet(ok ? QString() : QString(QLatin1String("background-color: red")));
+    m_ui.errorLabel->setStyleSheet(QLatin1String("background-color: red"));
     m_ui.errorLabel->setText(t);
 }
 
diff --git a/src/plugins/perforce/settingspage.h b/src/plugins/perforce/settingspage.h
index 3836d2cc1ed067c22de1feb290ab55a5fc7edbbc..a0c5db04084a9569bf8285401d33e6736410aa2f 100644
--- a/src/plugins/perforce/settingspage.h
+++ b/src/plugins/perforce/settingspage.h
@@ -41,6 +41,7 @@ namespace Perforce {
 namespace Internal {
 
 class PerforceSettings;
+class PerforceChecker;
 struct Settings;
 
 class SettingsPageWidget : public QWidget {
@@ -55,11 +56,14 @@ public:
 
 private slots:
     void slotTest();
+    void setStatusText(const QString &);
+    void setStatusError(const QString &);
+    void testSucceeded(const QString &repo);
 
 private:
-    void setStatusText(bool ok, const QString &);
 
     Ui::SettingsPage m_ui;
+    QPointer<PerforceChecker> m_checker;
 };
 
 class SettingsPage : public Core::IOptionsPage
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
index dba5cc254180574bbb6c784a1ffe0ae52528a471..47b07aeca92a3fd02df90caaa7a8602e48e8e5d5 100644
--- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
@@ -204,7 +204,7 @@ void VCSBaseSubmitEditor::createUserFields(const QString &fieldConfigFile)
 
     Utils::SubmitFieldWidget *fieldWidget = new Utils::SubmitFieldWidget;
     connect(fieldWidget, SIGNAL(browseButtonClicked(int,QString)),
-            this, SLOT(slotSetFieldNickName(int)));    
+            this, SLOT(slotSetFieldNickName(int)));
     fieldWidget->setCompleter(completer);
     fieldWidget->setAllowDuplicateFields(true);
     fieldWidget->setHasBrowseButton(true);
@@ -557,7 +557,7 @@ bool VCSBaseSubmitEditor::runSubmitMessageCheckScript(const QString &checkScript
     if (!checkProcess.waitForFinished()) {
         *errorMessage = tr("The check script '%1' could not be run: %2").arg(checkScript, checkProcess.errorString());
         return false;
-    }    
+    }
     const int exitCode = checkProcess.exitCode();
     if (exitCode != 0) {
         *errorMessage = QString::fromLocal8Bit(checkProcess.readAllStandardError());
@@ -581,32 +581,23 @@ QIcon VCSBaseSubmitEditor::submitIcon()
 // Compile a list if files in the current projects. TODO: Recurse down qrc files?
 QStringList VCSBaseSubmitEditor::currentProjectFiles(bool nativeSeparators, QString *name)
 {
-    using namespace ProjectExplorer;
     if (name)
         name->clear();
-    ProjectExplorerPlugin *pe = ProjectExplorerPlugin::instance();
-    if (!pe)
-        return QStringList();
-    QStringList files;
-    if (const Project *currentProject = pe->currentProject()) {
-        files << currentProject->files(Project::ExcludeGeneratedFiles);
-        if (name)
-            *name = currentProject->name();
-    } else {
-        if (const SessionManager *session = pe->session()) {
+
+    if (ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance()) {
+        if (const ProjectExplorer::Project *currentProject = pe->currentProject()) {
+            QStringList files = currentProject->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
             if (name)
-                *name = session->file()->fileName();
-            const QList<Project *> projects = session->projects();
-            foreach (Project *project, projects)
-                files << project->files(Project::ExcludeGeneratedFiles);
+                *name = currentProject->name();
+            if (nativeSeparators && !files.empty()) {
+                const QStringList::iterator end = files.end();
+                for (QStringList::iterator it = files.begin(); it != end; ++it)
+                    *it = QDir::toNativeSeparators(*it);
+            }
+            return files;
         }
     }
-    if (nativeSeparators && !files.empty()) {
-        const QStringList::iterator end = files.end();
-        for (QStringList::iterator it = files.begin(); it != end; ++it)
-            *it = QDir::toNativeSeparators(*it);
-    }
-    return files;
+    return QStringList();
 }
 
 // Reduce a list of untracked files reported by a VCS down to the files