From 1e64d9f9b25070bdea60dc4b0ae66d969545c732 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Mon, 10 Aug 2009 15:46:45 +0200
Subject: [PATCH] Version control: Replace per-VCS output panes with a single
 one.

...and give it some color and formatting.
---
 src/plugins/cvs/cvs.pro                       |   2 -
 src/plugins/cvs/cvsoutputwindow.cpp           | 127 --------
 src/plugins/cvs/cvsoutputwindow.h             |  84 -----
 src/plugins/cvs/cvsplugin.cpp                 |  39 +--
 src/plugins/cvs/cvsplugin.h                   |   3 -
 src/plugins/git/git.pro                       |   2 -
 src/plugins/git/gitclient.cpp                 |  78 ++---
 src/plugins/git/gitclient.h                   |   4 -
 src/plugins/git/gitoutputwindow.cpp           | 143 ---------
 src/plugins/git/gitoutputwindow.h             |  81 -----
 src/plugins/git/gitplugin.cpp                 |  32 +-
 src/plugins/git/gitplugin.h                   |   4 -
 src/plugins/perforce/perforce.pro             |   2 -
 src/plugins/perforce/perforceoutputwindow.cpp | 186 -----------
 src/plugins/perforce/perforceoutputwindow.h   |  90 ------
 src/plugins/perforce/perforceplugin.cpp       | 100 ++----
 src/plugins/perforce/perforceplugin.h         |  13 -
 src/plugins/subversion/subversion.pro         |   2 -
 .../subversion/subversionoutputwindow.cpp     | 127 --------
 .../subversion/subversionoutputwindow.h       |  84 -----
 src/plugins/subversion/subversionplugin.cpp   |  33 +-
 src/plugins/subversion/subversionplugin.h     |   5 -
 src/plugins/vcsbase/vcsbase.pro               |   6 +-
 src/plugins/vcsbase/vcsbaseoutputwindow.cpp   | 295 ++++++++++++++++++
 src/plugins/vcsbase/vcsbaseoutputwindow.h     | 107 +++++++
 src/plugins/vcsbase/vcsbaseplugin.cpp         |   2 +
 26 files changed, 490 insertions(+), 1161 deletions(-)
 delete mode 100644 src/plugins/cvs/cvsoutputwindow.cpp
 delete mode 100644 src/plugins/cvs/cvsoutputwindow.h
 delete mode 100644 src/plugins/git/gitoutputwindow.cpp
 delete mode 100644 src/plugins/git/gitoutputwindow.h
 delete mode 100644 src/plugins/perforce/perforceoutputwindow.cpp
 delete mode 100644 src/plugins/perforce/perforceoutputwindow.h
 delete mode 100644 src/plugins/subversion/subversionoutputwindow.cpp
 delete mode 100644 src/plugins/subversion/subversionoutputwindow.h
 create mode 100644 src/plugins/vcsbase/vcsbaseoutputwindow.cpp
 create mode 100644 src/plugins/vcsbase/vcsbaseoutputwindow.h

diff --git a/src/plugins/cvs/cvs.pro b/src/plugins/cvs/cvs.pro
index a0d6f04602c..c4f6478e933 100644
--- a/src/plugins/cvs/cvs.pro
+++ b/src/plugins/cvs/cvs.pro
@@ -11,7 +11,6 @@ include(../../libs/utils/utils.pri)
 HEADERS += annotationhighlighter.h \
     cvsplugin.h \
     cvscontrol.h \
-    cvsoutputwindow.h \
     settingspage.h \
     cvseditor.h \
     cvssubmiteditor.h \
@@ -24,7 +23,6 @@ HEADERS += annotationhighlighter.h \
 SOURCES += annotationhighlighter.cpp \
     cvsplugin.cpp \
     cvscontrol.cpp \
-    cvsoutputwindow.cpp \
     settingspage.cpp \
     cvseditor.cpp \
     cvssubmiteditor.cpp \
diff --git a/src/plugins/cvs/cvsoutputwindow.cpp b/src/plugins/cvs/cvsoutputwindow.cpp
deleted file mode 100644
index 2168a03d33e..00000000000
--- a/src/plugins/cvs/cvsoutputwindow.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://www.qtsoftware.com/contact.
-**
-**************************************************************************/
-
-#include "cvsoutputwindow.h"
-#include "cvsplugin.h"
-
-#include <QtGui/QListWidget>
-#include <QtCore/QDebug>
-
-using namespace CVS::Internal;
-
-CVSOutputWindow::CVSOutputWindow(CVSPlugin *cvsPlugin)
-    : m_cvsPlugin(cvsPlugin)
-{
-    m_outputListWidget = new QListWidget;
-    m_outputListWidget->setFrameStyle(QFrame::NoFrame);
-    m_outputListWidget->setWindowTitle(tr("CVS Output"));
-    m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
-}
-
-CVSOutputWindow::~CVSOutputWindow()
-{
-    delete m_outputListWidget;
-}
-
-QWidget *CVSOutputWindow::outputWidget(QWidget *parent)
-{
-    m_outputListWidget->setParent(parent);
-    return m_outputListWidget;
-}
-
-QString CVSOutputWindow::name() const
-{
-    return tr("CVS");
-}
-
-void CVSOutputWindow::clearContents()
-{
-    m_outputListWidget->clear();
-}
-
-int CVSOutputWindow::priorityInStatusBar() const
-{
-    return -1;
-}
-
-void CVSOutputWindow::visibilityChanged(bool b)
-{
-    if (b)
-        m_outputListWidget->setFocus();
-}
-
-void CVSOutputWindow::append(const QString &txt, bool doPopup)
-{
-    const QStringList lines = txt.split(QLatin1Char('\n'));
-    foreach (const QString &s, lines)
-        m_outputListWidget->addItem(s);
-    m_outputListWidget->scrollToBottom();
-
-    if (doPopup)
-        popup();
-}
-
-bool CVSOutputWindow::canFocus()
-{
-    return false;
-}
-
-bool CVSOutputWindow::hasFocus()
-{
-    return m_outputListWidget->hasFocus();
-}
-
-void CVSOutputWindow::setFocus()
-{
-}
-
-bool CVSOutputWindow::canNext()
-{
-    return false;
-}
-
-bool CVSOutputWindow::canPrevious()
-{
-    return false;
-}
-
-void CVSOutputWindow::goToNext()
-{
-
-}
-
-void CVSOutputWindow::goToPrev()
-{
-
-}
-
-bool CVSOutputWindow::canNavigate()
-{
-    return false;
-}
diff --git a/src/plugins/cvs/cvsoutputwindow.h b/src/plugins/cvs/cvsoutputwindow.h
deleted file mode 100644
index badb98c92bb..00000000000
--- a/src/plugins/cvs/cvsoutputwindow.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://www.qtsoftware.com/contact.
-**
-**************************************************************************/
-
-#ifndef CVSOUTPUTWINDOW_H
-#define CVSOUTPUTWINDOW_H
-
-#include <coreplugin/ioutputpane.h>
-
-QT_BEGIN_NAMESPACE
-class QListWidget;
-QT_END_NAMESPACE
-
-namespace CVS {
-namespace Internal {
-
-class CVSPlugin;
-
-class CVSOutputWindow : public Core::IOutputPane
-{
-    Q_OBJECT
-
-public:
-    CVSOutputWindow(CVSPlugin *cvsPlugin);
-    ~CVSOutputWindow();
-
-    QWidget *outputWidget(QWidget *parent);
-    QList<QWidget*> toolBarWidgets() const {
-        return QList<QWidget *>();
-    }
-
-    QString name() const;
-    void clearContents();
-    int priorityInStatusBar() const;
-    void visibilityChanged(bool visible);
-
-    bool canFocus();
-    bool hasFocus();
-    void setFocus();
-
-    bool canNext();
-    bool canPrevious();
-    void goToNext();
-    void goToPrev();
-    bool canNavigate();
-
-public slots:
-    void append(const QString &txt, bool popup = false);
-
-private:
-
-    CVSPlugin *m_cvsPlugin;
-    QListWidget *m_outputListWidget;
-};
-
-} // namespace CVS
-} // namespace Internal
-
-#endif // CVSOUTPUTWINDOW_H
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index 83d10fe004f..d46efdacef4 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -30,7 +30,6 @@
 #include "cvsplugin.h"
 #include "settingspage.h"
 #include "cvseditor.h"
-#include "cvsoutputwindow.h"
 #include "cvssubmiteditor.h"
 #include "cvsconstants.h"
 #include "cvscontrol.h"
@@ -39,6 +38,7 @@
 #include <vcsbase/basevcseditorfactory.h>
 #include <vcsbase/vcsbaseeditor.h>
 #include <vcsbase/basevcssubmiteditorfactory.h>
+#include <vcsbase/vcsbaseoutputwindow.h>
 #include <utils/synchronousprocess.h>
 #include <utils/parameteraction.h>
 
@@ -152,7 +152,6 @@ CVSPlugin *CVSPlugin::m_cvsPluginInstance = 0;
 CVSPlugin::CVSPlugin() :
     m_versionControl(0),
     m_changeTmpFile(0),
-    m_cvsOutputWindow(0),
     m_projectExplorer(0),
     m_addAction(0),
     m_deleteAction(0),
@@ -239,9 +238,6 @@ bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage)
     for (int i = 0; i < editorCount; i++)
         addAutoReleasedObject(new CVSEditorFactory(editorParameters + i, this, describeSlotC));
 
-    m_cvsOutputWindow = new CVSOutputWindow(this);
-    addAutoReleasedObject(m_cvsOutputWindow);
-
     addAutoReleasedObject(new CheckoutWizard);
 
     //register actions
@@ -644,14 +640,14 @@ void CVSPlugin::startCommit(const QString &source)
     if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
         return;
     if (m_changeTmpFile) {
-        showOutput(tr("Another commit is currently being executed."));
+        VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Another commit is currently being executed."));
         return;
     }
     const QFileInfo sourceFi(source);
     const QString sourceDir = sourceFi.isDir() ? source : sourceFi.absolutePath();
     const QString topLevel = findTopLevelForDirectory(sourceDir);
     if (topLevel.isEmpty()) {
-        showOutput(msgCannotFindTopLevel(source), true);
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(msgCannotFindTopLevel(source));
         return;
     }
     // We need the "Examining <subdir>" stderr output to tell
@@ -673,7 +669,7 @@ void CVSPlugin::startCommit(const QString &source)
         qDebug() << Q_FUNC_INFO << '\n' << source << "top" << topLevel;
 
     if (statusOutput.empty()) {
-        showOutput(tr("There are no modified files."), true);
+        VCSBase::VCSBaseOutputWindow::instance()->append(tr("There are no modified files."));
         return;
     }
 
@@ -681,7 +677,7 @@ void CVSPlugin::startCommit(const QString &source)
     QTemporaryFile *changeTmpFile = new QTemporaryFile(this);
     changeTmpFile->setAutoRemove(true);
     if (!changeTmpFile->open()) {
-        showOutput(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
         delete changeTmpFile;
         return;
     }
@@ -807,7 +803,7 @@ void CVSPlugin::slotDescribe(const QString &source, const QString &changeNr)
 {
     QString errorMessage;
     if (!describe(source, changeNr, &errorMessage))
-        showOutput(errorMessage, true);
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
 }
 
 bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *errorMessage)
@@ -1034,12 +1030,11 @@ static inline QString fixFileArgs(QStringList *files)
 // Format log entry for command
 static inline QString msgExecutionLogEntry(const QString &workingDir, const QString &executable, const QStringList &arguments)
 {
-    const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm"));
-    //: <timestamp> Executing: <executable> <arguments>
+    //: Executing: <executable> <arguments>
     const QString args = arguments.join(QString(QLatin1Char(' ')));
     if (workingDir.isEmpty())
-        return CVSPlugin::tr("%1 Executing: %2 %3\n").arg(timeStamp, executable, args);
-    return CVSPlugin::tr("%1 Executing in %2: %3 %4\n").arg(timeStamp, workingDir, executable, args);
+        return CVSPlugin::tr("Executing: %2 %3\n").arg(executable, args);
+    return CVSPlugin::tr("Executing in %2: %3 %4\n").arg(workingDir, executable, args);
 }
 
 // Figure out a working directory for the process,
@@ -1075,7 +1070,7 @@ CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
     const QStringList allArgs = m_settings.addOptions(arguments);
 
     const QString outputText = msgExecutionLogEntry(response.workingDirectory, executable, allArgs);
-    showOutput(outputText, false);
+    VCSBase::VCSBaseOutputWindow::instance()->appendCommand(outputText);
 
     if (CVS::Constants::debug)
         qDebug() << "runCVS" << timeOut << outputText;
@@ -1092,12 +1087,13 @@ CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
     process.setStdOutCodec(outputCodec);
 
     process.setStdErrBufferedSignalsEnabled(true);
-    connect(&process, SIGNAL(stdErrBuffered(QString,bool)), m_cvsOutputWindow, SLOT(append(QString,bool)));
+    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
+    connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
 
     // connect stdout to the output window if desired
     if (showStdOutInOutputWindow) {
         process.setStdOutBufferedSignalsEnabled(true);
-        connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_cvsOutputWindow, SLOT(append(QString,bool)));
+        connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
     }
 
     const Core::Utils::SynchronousProcessResponse sp_resp = process.run(executable, allArgs);
@@ -1123,18 +1119,11 @@ CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
         break;
     }
     if (response.result != CVSResponse::Ok)
-        m_cvsOutputWindow->append(response.message, true);
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(response.message);
 
     return response;
 }
 
-void CVSPlugin::showOutput(const QString &output, bool bringToForeground)
-{
-    m_cvsOutputWindow->append(output);
-    if (bringToForeground)
-        m_cvsOutputWindow->popup();
-}
-
 Core::IEditor * CVSPlugin::showOutputInEditor(const QString& title, const QString &output,
                                                      int editorType, const QString &source,
                                                      QTextCodec *codec)
diff --git a/src/plugins/cvs/cvsplugin.h b/src/plugins/cvs/cvsplugin.h
index ef54049e71b..4fe430b9bd0 100644
--- a/src/plugins/cvs/cvsplugin.h
+++ b/src/plugins/cvs/cvsplugin.h
@@ -58,7 +58,6 @@ namespace ProjectExplorer {
 namespace CVS {
 namespace Internal {
 
-class CVSOutputWindow;
 class CVSSubmitEditor;
 
 struct CVSResponse
@@ -141,7 +140,6 @@ private:
                        bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0,
                        bool mergeStderr = false);
 
-    void showOutput(const QString &output, bool bringToForeground = true);
     void annotate(const QString &file);
     bool describe(const QString &source, const QString &changeNr, QString *errorMessage);
     bool describe(const QString &repository, QList<CVS_LogEntry> entries, QString *errorMessage);
@@ -157,7 +155,6 @@ private:
     Core::IVersionControl *m_versionControl;
     QTemporaryFile *m_changeTmpFile;
 
-    CVSOutputWindow *m_cvsOutputWindow;
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
 
     Core::Utils::ParameterAction *m_addAction;
diff --git a/src/plugins/git/git.pro b/src/plugins/git/git.pro
index 86556815eb8..fa87f66d3d8 100644
--- a/src/plugins/git/git.pro
+++ b/src/plugins/git/git.pro
@@ -8,7 +8,6 @@ include(../../plugins/vcsbase/vcsbase.pri)
 include(../../libs/utils/utils.pri)
 HEADERS += gitplugin.h \
     gitconstants.h \
-    gitoutputwindow.h \
     gitclient.h \
     changeselectiondialog.h \
     commitdata.h \
@@ -25,7 +24,6 @@ HEADERS += gitplugin.h \
     clonewizard.h \
     clonewizardpage.h
 SOURCES += gitplugin.cpp \
-    gitoutputwindow.cpp \
     gitclient.cpp \
     changeselectiondialog.cpp \
     commitdata.cpp \
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 5c50e52ffdd..4c75d60cd87 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -46,6 +46,7 @@
 #include <texteditor/itexteditor.h>
 #include <utils/qtcassert.h>
 #include <vcsbase/vcsbaseeditor.h>
+#include <vcsbase/vcsbaseoutputwindow.h>
 
 #include <QtCore/QRegExp>
 #include <QtCore/QTemporaryFile>
@@ -89,9 +90,8 @@ static inline QString msgParseFilesFailed()
 // Format a command for the status window
 static QString formatCommand(const QString &binary, const QStringList &args)
 {
-    const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm"));
-    //: <timestamp> Executing: <executable> <arguments>
-    return GitClient::tr("%1 Executing: %2 %3\n").arg(timeStamp, binary, args.join(QString(QLatin1Char(' '))));
+    //: Executing: <executable> <arguments>
+    return GitClient::tr("Executing: %1 %2\n").arg(binary, args.join(QString(QLatin1Char(' '))));
 }
 
 // ---------------- GitClient
@@ -210,20 +210,20 @@ void GitClient::diff(const QString &workingDirectory,
     if (unstagedFileNames.empty() && stagedFileNames.empty()) {
        QStringList arguments(commonDiffArgs);
        arguments << diffArgs;
-       m_plugin->outputWindow()->append(formatCommand(binary, arguments));
+       VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(binary, arguments));
        command->addJob(arguments, m_settings.timeout);
     } else {
         // Files diff.
         if (!unstagedFileNames.empty()) {
            QStringList arguments(commonDiffArgs);
            arguments << QLatin1String("--") << unstagedFileNames;
-           m_plugin->outputWindow()->append(formatCommand(binary, arguments));
+           VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(binary, arguments));
            command->addJob(arguments, m_settings.timeout);
         }
         if (!stagedFileNames.empty()) {
            QStringList arguments(commonDiffArgs);
            arguments << QLatin1String("--cached") << diffArgs << QLatin1String("--") << stagedFileNames;
-           m_plugin->outputWindow()->append(formatCommand(binary, arguments));
+           VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(binary, arguments));
            command->addJob(arguments, m_settings.timeout);
         }
     }
@@ -360,8 +360,7 @@ bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringLis
     if (!rc) {
         const QString errorMessage = tr("Unable to add %n file(s) to %1: %2", 0, files.size()).
                                      arg(workingDirectory, QString::fromLocal8Bit(errorText));
-        m_plugin->outputWindow()->append(errorMessage);
-        m_plugin->outputWindow()->popup(false);
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
     }
     return rc;
 }
@@ -371,10 +370,8 @@ bool GitClient::synchronousReset(const QString &workingDirectory,
 {
     QString errorMessage;
     const bool rc = synchronousReset(workingDirectory, files, &errorMessage);
-    if (!rc) {
-        m_plugin->outputWindow()->append(errorMessage);
-        m_plugin->outputWindow()->popup(false);
-    }
+    if (!rc)
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
     return rc;
 }
 
@@ -390,8 +387,7 @@ bool GitClient::synchronousReset(const QString &workingDirectory,
     arguments << QLatin1String("reset") << QLatin1String("HEAD") << QLatin1String("--") << files;
     const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
     const QString output = QString::fromLocal8Bit(outputText);
-    m_plugin->outputWindow()->popup(false);
-    m_plugin->outputWindow()->append(output);
+    VCSBase::VCSBaseOutputWindow::instance()->append(output);
     // Note that git exits with 1 even if the operation is successful
     // Assume real failure if the output does not contain "foo.cpp modified"
     if (!rc && !output.contains(QLatin1String("modified"))) {
@@ -478,12 +474,11 @@ GitCommand *GitClient::createCommand(const QString &workingDirectory,
     if (Git::Constants::debug)
         qDebug() << Q_FUNC_INFO << workingDirectory << editor;
 
-    GitOutputWindow *outputWindow = m_plugin->outputWindow();
-
+    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
     GitCommand* command = new GitCommand(binary(), workingDirectory, processEnvironment());
     if (outputToWindow) {
-        if (!editor) { // assume that the commands output is the important thing
-            connect(command, SIGNAL(outputData(QByteArray)), this, SLOT(appendDataAndPopup(QByteArray)));
+        if (editor) { // assume that the commands output is the important thing
+            connect(command, SIGNAL(outputData(QByteArray)), outputWindow, SLOT(appendDataSilently(QByteArray)));
         } else {
             connect(command, SIGNAL(outputData(QByteArray)), outputWindow, SLOT(appendData(QByteArray)));
         }
@@ -493,7 +488,7 @@ GitCommand *GitClient::createCommand(const QString &workingDirectory,
     }
 
     if (outputWindow)
-        connect(command, SIGNAL(errorText(QString)), this, SLOT(appendAndPopup(QString)));
+        connect(command, SIGNAL(errorText(QString)), outputWindow, SLOT(appendError(QString)));
     return command;
 }
 
@@ -504,25 +499,13 @@ void GitClient::executeGit(const QString &workingDirectory,
                            bool outputToWindow,
                            GitCommand::TerminationReportMode tm)
 {
-    m_plugin->outputWindow()->append(formatCommand(QLatin1String(Constants::GIT_BINARY), arguments));
+    VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(QLatin1String(Constants::GIT_BINARY), arguments));
     GitCommand *command = createCommand(workingDirectory, editor, outputToWindow);
     command->addJob(arguments, m_settings.timeout);
     command->setTerminationReportMode(tm);
     command->execute();
 }
 
-void GitClient::appendDataAndPopup(const QByteArray &data)
-{
-    m_plugin->outputWindow()->appendData(data);
-    m_plugin->outputWindow()->popup(false);
-}
-
-void GitClient::appendAndPopup(const QString &text)
-{
-    m_plugin->outputWindow()->append(text);
-    m_plugin->outputWindow()->popup(false);
-}
-
 // Return fixed arguments required to run
 QStringList GitClient::binary() const
 {
@@ -553,7 +536,7 @@ bool GitClient::synchronousGit(const QString &workingDirectory,
         qDebug() << "synchronousGit" << workingDirectory << arguments;
 
     if (logCommandToWindow)
-        m_plugin->outputWindow()->append(formatCommand(m_binaryPath, arguments));
+        VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(m_binaryPath, arguments));
 
     QProcess process;
     process.setWorkingDirectory(workingDirectory);
@@ -602,10 +585,8 @@ GitClient::StashResult GitClient::ensureStash(const QString &workingDirectory)
 {
     QString errorMessage;
     const StashResult sr = ensureStash(workingDirectory, &errorMessage);
-    if (sr == StashFailed) {
-        m_plugin->outputWindow()->append(errorMessage);
-        m_plugin->outputWindow()->popup();
-    }
+    if (sr == StashFailed)
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
     return sr;
 }
 
@@ -810,12 +791,11 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
     QByteArray outputText;
     QByteArray errorText;
     const bool rc = synchronousGit(repositoryDirectory, args, &outputText, &errorText);
-    const QString message = rc ?
-        tr("Committed %n file(s).\n", 0, checkedFiles.size()) :
-        tr("Unable to commit %n file(s): %1\n", 0, checkedFiles.size()).arg(QString::fromLocal8Bit(errorText));
-
-    m_plugin->outputWindow()->append(message);
-    m_plugin->outputWindow()->popup(false);
+    if (rc) {
+        VCSBase::VCSBaseOutputWindow::instance()->append(tr("Committed %n file(s).\n", 0, checkedFiles.size()));
+    } else {
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Unable to commit %n file(s): %1\n", 0, checkedFiles.size()).arg(QString::fromLocal8Bit(errorText)));
+    }
     return rc;
 }
 
@@ -919,13 +899,11 @@ void GitClient::revert(const QStringList &files)
         break;
     case RevertUnchanged: {
         const QString msg = (isDirectory || files.size() > 1) ? msgNoChangedFiles() : tr("The file is not modified.");
-        m_plugin->outputWindow()->append(msg);
-        m_plugin->outputWindow()->popup();
+        VCSBase::VCSBaseOutputWindow::instance()->append(msg);
     }
         break;
     case RevertFailed:
-        m_plugin->outputWindow()->append(errorMessage);
-        m_plugin->outputWindow()->popup();
+        VCSBase::VCSBaseOutputWindow::instance()->append(errorMessage);
         break;
     }
 }
@@ -954,12 +932,10 @@ void GitClient::stash(const QString &workingDirectory)
         executeGit(workingDirectory, QStringList(QLatin1String("stash")), 0, true);
         break;
     case StatusUnchanged:
-        m_plugin->outputWindow()->append(msgNoChangedFiles());
-        m_plugin->outputWindow()->popup();
+        VCSBase::VCSBaseOutputWindow::instance()->append(msgNoChangedFiles());
         break;
     case StatusFailed:
-        m_plugin->outputWindow()->append(errorMessage);
-        m_plugin->outputWindow()->popup();
+        VCSBase::VCSBaseOutputWindow::instance()->append(errorMessage);
         break;
     }
 }
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index cfe14269671..6e8eef99b75 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -145,10 +145,6 @@ public:
 public slots:
     void show(const QString &source, const QString &id);
 
-private slots:
-    void appendAndPopup(const QString &text);
-    void appendDataAndPopup(const QByteArray &data);
-
 private:
     VCSBase::VCSBaseEditor *createVCSEditor(const QString &kind,
                                                  QString title,
diff --git a/src/plugins/git/gitoutputwindow.cpp b/src/plugins/git/gitoutputwindow.cpp
deleted file mode 100644
index b507ebb8adc..00000000000
--- a/src/plugins/git/gitoutputwindow.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://www.qtsoftware.com/contact.
-**
-**************************************************************************/
-
-#include "gitoutputwindow.h"
-
-#include <QtCore/QTextCodec>
-#include <QtGui/QKeyEvent>
-#include <QtGui/QMouseEvent>
-#include <QtGui/QMenu>
-#include <QtGui/QAction>
-#include <QtGui/QListWidget>
-
-using namespace Git::Internal;
-
-GitOutputWindow::GitOutputWindow()
-    : Core::IOutputPane()
-{
-    m_outputListWidget = new QListWidget;
-    m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
-    m_outputListWidget->setFrameStyle(QFrame::NoFrame);
-
-    m_outputListWidget->setWindowTitle(tr("Git Output"));
-}
-
-GitOutputWindow::~GitOutputWindow()
-{
-    delete m_outputListWidget;
-}
-
-QWidget *GitOutputWindow::outputWidget(QWidget *parent)
-{
-    m_outputListWidget->setParent(parent);
-    return m_outputListWidget;
-}
-
-QString GitOutputWindow::name() const
-{
-    return tr("Git");
-}
-
-void GitOutputWindow::clearContents()
-{
-    m_outputListWidget->clear();
-}
-
-void GitOutputWindow::visibilityChanged(bool b)
-{
-    if (b)
-        m_outputListWidget->setFocus();
-}
-
-bool GitOutputWindow::hasFocus()
-{
-    return m_outputListWidget->hasFocus();
-}
-
-bool GitOutputWindow::canFocus()
-{
-    return false;
-}
-
-void GitOutputWindow::setFocus()
-{
-}
-
-void GitOutputWindow::setText(const QString &text)
-{
-    clearContents();
-    append(text);
-}
-
-void GitOutputWindow::append(const QString &text)
-{
-    const QStringList lines = text.split(QLatin1Char('\n'));
-    foreach (const QString &s, lines)
-        m_outputListWidget->addItem(s);
-    m_outputListWidget->scrollToBottom();
-}
-
-void GitOutputWindow::setData(const QByteArray &data)
-{
-    setText(QTextCodec::codecForLocale()->toUnicode(data));
-}
-
-void GitOutputWindow::appendData(const QByteArray &data)
-{
-    append(QTextCodec::codecForLocale()->toUnicode(data));
-}
-
-int GitOutputWindow::priorityInStatusBar() const
-{
-    return -1;
-}
-
-bool GitOutputWindow::canNext()
-{
-    return false;
-}
-
-bool GitOutputWindow::canPrevious()
-{
-    return false;
-}
-
-void GitOutputWindow::goToNext()
-{
-}
-
-void GitOutputWindow::goToPrev()
-{
-
-}
-
-bool GitOutputWindow::canNavigate()
-{
-    return false;
-}
diff --git a/src/plugins/git/gitoutputwindow.h b/src/plugins/git/gitoutputwindow.h
deleted file mode 100644
index dc6d9d61049..00000000000
--- a/src/plugins/git/gitoutputwindow.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://www.qtsoftware.com/contact.
-**
-**************************************************************************/
-
-#ifndef GITOUTPUTWINDOW_H
-#define GITOUTPUTWINDOW_H
-
-#include <coreplugin/ioutputpane.h>
-
-#include <QtGui/QAction>
-#include <QtGui/QListWidget>
-#include <QtGui/QListWidgetItem>
-
-namespace Git {
-namespace Internal {
-
-class GitOutputWindow : public Core::IOutputPane
-{
-    Q_OBJECT
-
-public:
-    GitOutputWindow();
-    ~GitOutputWindow();
-
-    QWidget *outputWidget(QWidget *parent);
-    QList<QWidget*> toolBarWidgets() const { return QList<QWidget *>(); }
-
-    QString name() const;
-    int priorityInStatusBar() const;
-    void clearContents();
-    void visibilityChanged(bool visible);
-
-    bool canFocus();
-    bool hasFocus();
-    void setFocus();
-
-    bool canNext();
-    bool canPrevious();
-    void goToNext();
-    void goToPrev();
-    bool canNavigate();
-
-public slots:
-    void setText(const QString &text);
-    void append(const QString &text);
-    void setData(const QByteArray &data);
-    void appendData(const QByteArray &data);
-
-private:
-    QListWidget *m_outputListWidget;
-};
-
-} // namespace Internal
-} // namespace Git
-
-#endif // GITOUTPUTWINDOW_H
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index 14e36fcb165..834ce75e1b7 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -54,6 +54,7 @@
 #include <vcsbase/basevcseditorfactory.h>
 #include <vcsbase/vcsbaseeditor.h>
 #include <vcsbase/basevcssubmiteditorfactory.h>
+#include <vcsbase/vcsbaseoutputwindow.h>
 
 #include <QtCore/QDebug>
 #include <QtCore/QDir>
@@ -139,7 +140,6 @@ GitPlugin::GitPlugin() :
     m_branchListAction(0),
     m_projectExplorer(0),
     m_gitClient(0),
-    m_outputWindow(0),
     m_changeSelectionDialog(0),
     m_changeTmpFile(0),
     m_submitActionTriggered(false)
@@ -197,10 +197,6 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
     QList<int> globalcontext;
     globalcontext << m_core->uniqueIDManager()->uniqueIdentifier(Core::Constants::C_GLOBAL);
 
-    // Create the output Window
-    m_outputWindow = new GitOutputWindow();
-    addAutoReleasedObject(m_outputWindow);
-
     // Create the settings Page
     addAutoReleasedObject(new SettingsPage());
 
@@ -464,8 +460,7 @@ QString GitPlugin::getWorkingDirectory()
         qDebug() << Q_FUNC_INFO << "file" << workingDirectory;
 
     if (workingDirectory.isEmpty()) {
-        m_outputWindow->append(tr("Could not find working directory"));
-        m_outputWindow->popup(false);
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Could not find working directory"));
         return QString();
     }
     return workingDirectory;
@@ -519,7 +514,7 @@ void GitPlugin::undoFileChanges()
 
     QString errorMessage;
     if (!m_gitClient->synchronousCheckout(workingDirectory, QStringList() << fileName, &errorMessage))
-        m_outputWindow->append(errorMessage);
+        VCSBase::VCSBaseOutputWindow::instance()->append(errorMessage);
 
 }
 
@@ -561,8 +556,7 @@ void GitPlugin::startCommit()
     if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
         return;
     if (m_changeTmpFile) {
-        m_outputWindow->append(tr("Another submit is currently beeing executed."));
-        m_outputWindow->popup(false);
+        VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Another submit is currently being executed."));
         return;
     }
 
@@ -575,8 +569,7 @@ void GitPlugin::startCommit()
     QString errorMessage, commitTemplate;
     CommitData data;
     if (!m_gitClient->getCommitData(workingDirectory, &commitTemplate, &data, &errorMessage)) {
-        m_outputWindow->append(errorMessage);
-        m_outputWindow->popup(false);
+        VCSBase::VCSBaseOutputWindow::instance()->append(errorMessage);
         return;
     }
 
@@ -593,8 +586,7 @@ void GitPlugin::startCommit()
     QTemporaryFile *changeTmpFile = new QTemporaryFile(this);
     changeTmpFile->setAutoRemove(true);
     if (!changeTmpFile->open()) {
-        m_outputWindow->append(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
-        m_outputWindow->popup(false);
+        VCSBase::VCSBaseOutputWindow::instance()->append(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
         delete changeTmpFile;
         return;
     }
@@ -734,19 +726,14 @@ void GitPlugin::branchList()
     const QString workingDirectory = getWorkingDirectory();
     if (workingDirectory.isEmpty())
         return;
-#ifndef USE_BRANCHDIALOG
     QString errorMessage;
     BranchDialog dialog(m_core->mainWindow());
 
     if (!dialog.init(m_gitClient, workingDirectory, &errorMessage)) {
-        m_outputWindow->append(errorMessage);
-        m_outputWindow->popup(false);
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
         return;
     }
     dialog.exec();
-#else
-    m_gitClient->branchList(workingDirectory);
-#endif
 }
 
 void GitPlugin::stashList()
@@ -833,11 +820,6 @@ void GitPlugin::showCommit()
     m_gitClient->show(m_changeSelectionDialog->m_ui.repositoryEdit->text(), change);
 }
 
-GitOutputWindow *GitPlugin::outputWindow() const
-{
-    return m_outputWindow;
-}
-
 GitSettings GitPlugin::settings() const
 {
     return m_gitClient->settings();
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
index d473697cd91..7e9ed981466 100644
--- a/src/plugins/git/gitplugin.h
+++ b/src/plugins/git/gitplugin.h
@@ -30,7 +30,6 @@
 #ifndef GITPLUGIN_H
 #define GITPLUGIN_H
 
-#include "gitoutputwindow.h"
 #include "settingspage.h"
 
 #include <coreplugin/editormanager/ieditorfactory.h>
@@ -94,8 +93,6 @@ public:
 
     QString getWorkingDirectory();
 
-    GitOutputWindow *outputWindow() const;
-
     GitSettings settings() const;
     void setSettings(const GitSettings &s);
 
@@ -165,7 +162,6 @@ private:
 
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
     GitClient                   *m_gitClient;
-    GitOutputWindow             *m_outputWindow;
     ChangeSelectionDialog       *m_changeSelectionDialog;
     QString                     m_submitRepository;
     QStringList                 m_submitOrigCommitFiles;
diff --git a/src/plugins/perforce/perforce.pro b/src/plugins/perforce/perforce.pro
index 017dda29819..e93e3378d85 100644
--- a/src/plugins/perforce/perforce.pro
+++ b/src/plugins/perforce/perforce.pro
@@ -6,7 +6,6 @@ include(perforce_dependencies.pri)
 
 HEADERS += \
     perforceplugin.h \
-    perforceoutputwindow.h \
     settingspage.h \
     perforceeditor.h \
     changenumberdialog.h \
@@ -19,7 +18,6 @@ HEADERS += \
     perforcesubmiteditorwidget.h
 
 SOURCES += perforceplugin.cpp \
-    perforceoutputwindow.cpp \
     settingspage.cpp \
     perforceeditor.cpp \
     changenumberdialog.cpp \
diff --git a/src/plugins/perforce/perforceoutputwindow.cpp b/src/plugins/perforce/perforceoutputwindow.cpp
deleted file mode 100644
index 3d363710f0d..00000000000
--- a/src/plugins/perforce/perforceoutputwindow.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://www.qtsoftware.com/contact.
-**
-**************************************************************************/
-
-#include "perforceoutputwindow.h"
-#include "perforceplugin.h"
-
-#include <QtGui/QKeyEvent>
-#include <QtGui/QMouseEvent>
-#include <QtGui/QMenu>
-#include <QtGui/QAction>
-#include <QtGui/QListWidget>
-
-using namespace Perforce::Internal;
-
-PerforceOutputWindow::PerforceOutputWindow(PerforcePlugin *p4Plugin)
-    : m_p4Plugin(p4Plugin)
-{
-    m_outputListWidget = new QListWidget;
-    m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
-    m_outputListWidget->setFrameStyle(QFrame::NoFrame);
-
-    m_outputListWidget->setWindowTitle(tr("Perforce Output"));
-
-    m_diffAction = new QAction(tr("Diff"), this);
-    connect(m_diffAction, SIGNAL(triggered()), this, SLOT(diff()));
-
-    connect(m_outputListWidget, SIGNAL(itemActivated(QListWidgetItem*)),
-        this, SLOT(openFiles()));
-}
-
-PerforceOutputWindow::~PerforceOutputWindow()
-{
-    delete m_outputListWidget;
-}
-
-bool PerforceOutputWindow::hasFocus()
-{
-    return m_outputListWidget->hasFocus();
-}
-
-bool PerforceOutputWindow::canFocus()
-{
-    return false;
-}
-
-void PerforceOutputWindow::setFocus()
-{
-}
-
-QWidget *PerforceOutputWindow::outputWidget(QWidget *parent)
-{
-    m_outputListWidget->setParent(parent);
-    return m_outputListWidget;
-}
-
-QString PerforceOutputWindow::name() const
-{
-    return tr("Perforce");
-}
-
-void PerforceOutputWindow::clearContents()
-{
-    m_outputListWidget->clear();
-}
-
-void PerforceOutputWindow::visibilityChanged(bool /* b */)
-{
-}
-
-void PerforceOutputWindow::append(const QString &txt, bool doPopup)
-{
-    const QStringList lines = txt.split(QLatin1Char('\n'));
-    foreach (const QString &s, lines)
-        m_outputListWidget->addItem(s);
-    m_outputListWidget->scrollToBottom();
-    if (doPopup)
-        popup();
-}
-
-void PerforceOutputWindow::contextMenuEvent(QContextMenuEvent *event)
-{
-    QMenu *menu = new QMenu(m_outputListWidget);
-    menu->addAction(m_diffAction);
-    menu->exec(event->globalPos());
-    delete menu;
-}
-
-void PerforceOutputWindow::diff()
-{
-    QStringList files;
-    foreach (QListWidgetItem *i, m_outputListWidget->selectedItems()) {
-        if (m_outputListWidget->row(i) > 0)
-            files.append(getFileName(i));
-    }
-    if (files.count() == 0 && m_outputListWidget->row(m_outputListWidget->currentItem()) > 0)
-        files.append(getFileName(m_outputListWidget->currentItem()));
-
-    m_p4Plugin->p4Diff(files);
-}
-
-QString PerforceOutputWindow::getFileName(const QListWidgetItem *item)
-{
-    QString fileName;
-    if (!item || item->text().isEmpty())
-        return fileName;
-
-    QString line = item->text();
-    QRegExp regExp("(/.+)#\\d+\\s-\\s(.+)$");
-    regExp.setMinimal(true);
-    if (regExp.indexIn(line) > -1 && regExp.numCaptures() >= 1) {
-        fileName = regExp.cap(1);
-        QString description;
-        if (regExp.numCaptures() >= 2)
-            description = regExp.cap(2);
-    }
-    return fileName;
-}
-
-void PerforceOutputWindow::openFiles()
-{
-    QStringList files;
-    foreach (QListWidgetItem *i, m_outputListWidget->selectedItems()) {
-        if (m_outputListWidget->row(i) > 0)
-            files.append(getFileName(i));
-    }
-    if (files.count() == 0 && m_outputListWidget->row(m_outputListWidget->currentItem()) > 0)
-        files.append(getFileName(m_outputListWidget->currentItem()));
-
-    m_p4Plugin->openFiles(files);
-}
-
-int PerforceOutputWindow::priorityInStatusBar() const
-{
-    return -1;
-}
-
-bool PerforceOutputWindow::canNext()
-{
-    return false;
-}
-
-bool PerforceOutputWindow::canPrevious()
-{
-    return false;
-}
-
-void PerforceOutputWindow::goToNext()
-{
-
-}
-
-void PerforceOutputWindow::goToPrev()
-{
-
-}
-
-bool PerforceOutputWindow::canNavigate()
-{
-    return false;
-}
diff --git a/src/plugins/perforce/perforceoutputwindow.h b/src/plugins/perforce/perforceoutputwindow.h
deleted file mode 100644
index fb610b91cf1..00000000000
--- a/src/plugins/perforce/perforceoutputwindow.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://www.qtsoftware.com/contact.
-**
-**************************************************************************/
-
-#ifndef PERFORCEOUTPUTWINDOW_H
-#define PERFORCEOUTPUTWINDOW_H
-
-#include <coreplugin/ioutputpane.h>
-
-#include <QtGui/QAction>
-#include <QtGui/QListWidget>
-#include <QtGui/QListWidgetItem>
-
-namespace Perforce {
-namespace Internal {
-
-class PerforcePlugin;
-
-class PerforceOutputWindow : public Core::IOutputPane
-{
-    Q_OBJECT
-
-public:
-    PerforceOutputWindow(PerforcePlugin *p4Plugin);
-    ~PerforceOutputWindow();
-
-    QWidget *outputWidget(QWidget *parent);
-    QList<QWidget*> toolBarWidgets() const { return QList<QWidget *>(); }
-
-    QString name() const;
-    int priorityInStatusBar() const;
-    void clearContents();
-    void visibilityChanged(bool visible);
-
-    bool canFocus();
-    bool hasFocus();
-    void setFocus();
-
-    bool canNext();
-    bool canPrevious();
-    void goToNext();
-    void goToPrev();
-    bool canNavigate();
-
-public slots:
-     void append(const QString &txt, bool doPopup = false);
-
-private slots:
-    void diff();
-    void openFiles();
-
-private:
-    void contextMenuEvent(QContextMenuEvent *event);
-
-    static QString getFileName(const QListWidgetItem *item);
-
-    PerforcePlugin *m_p4Plugin;
-    QListWidget *m_outputListWidget;
-    QAction *m_diffAction;
-};
-
-} // namespace Perforce
-} // namespace Internal
-
-#endif // PERFORCEOUTPUTWINDOW_H
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 4dfb5ea5081..ff28c6a0494 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -33,7 +33,6 @@
 #include "pendingchangesdialog.h"
 #include "perforceconstants.h"
 #include "perforceeditor.h"
-#include "perforceoutputwindow.h"
 #include "perforcesubmiteditor.h"
 #include "perforceversioncontrol.h"
 #include "settingspage.h"
@@ -52,6 +51,7 @@
 #include <vcsbase/basevcseditorfactory.h>
 #include <vcsbase/basevcssubmiteditorfactory.h>
 #include <vcsbase/vcsbaseeditor.h>
+#include <vcsbase/vcsbaseoutputwindow.h>
 
 #include <QtCore/QtPlugin>
 #include <QtCore/QDebug>
@@ -166,8 +166,6 @@ bool CoreListener::editorAboutToClose(Core::IEditor *editor)
 PerforcePlugin *PerforcePlugin::m_perforcePluginInstance = NULL;
 
 PerforcePlugin::PerforcePlugin() :
-    m_perforceOutputWindow(0),
-    m_settingsPage(0),
     m_editAction(0),
     m_addAction(0),
     m_deleteAction(0),
@@ -192,8 +190,6 @@ PerforcePlugin::PerforcePlugin() :
     m_undoAction(0),
     m_redoAction(0),
     m_changeTmpFile(0),
-    m_coreListener(0),
-    m_submitEditorFactory(0),
     m_versionControl(0)
 {
 }
@@ -220,28 +216,20 @@ bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMess
     if (QSettings *settings = core->settings())
         m_settings.fromSettings(settings);
 
-    m_perforceOutputWindow = new PerforceOutputWindow(this);
-    addObject(m_perforceOutputWindow);
-
-    m_settingsPage = new SettingsPage;
-    addObject(m_settingsPage);
+    addAutoReleasedObject(new SettingsPage);
 
     // Editor factories
-    m_submitEditorFactory = new PerforceSubmitEditorFactory(&submitParameters);
-    addObject(m_submitEditorFactory);
+    addAutoReleasedObject(new PerforceSubmitEditorFactory(&submitParameters));
 
     static const char *describeSlot = SLOT(describe(QString,QString));
     const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
-    for (int i = 0; i < editorCount; i++) {
-        m_editorFactories.push_back(new PerforceEditorFactory(editorParameters + i, this, describeSlot));
-        addObject(m_editorFactories.back());
-    }
+    for (int i = 0; i < editorCount; i++)
+        addAutoReleasedObject(new PerforceEditorFactory(editorParameters + i, this, describeSlot));
 
     m_versionControl = new PerforceVersionControl(this);
-    addObject(m_versionControl);
+    addAutoReleasedObject(m_versionControl);
 
-    m_coreListener = new CoreListener(this);
-    addObject(m_coreListener);
+    addAutoReleasedObject(new CoreListener(this));
 
     //register actions
     Core::ActionManager *am = Core::ICore::instance()->actionManager();
@@ -555,19 +543,18 @@ void PerforcePlugin::submit()
 
     QString errorMessage;
     if (!checkP4Configuration(&errorMessage)) {
-        showOutput(errorMessage, true);
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
         return;
     }
 
     if (m_changeTmpFile) {
-        showOutput(tr("Another submit is currently executed."), true);
-        m_perforceOutputWindow->popup(false);
+        VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Another submit is currently executed."));
         return;
     }
 
     m_changeTmpFile = new QTemporaryFile(this);
     if (!m_changeTmpFile->open()) {
-        showOutput(tr("Cannot create temporary file."), true);
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot create temporary file."));
         cleanChangeTmpFile();
         return;
     }
@@ -599,7 +586,7 @@ void PerforcePlugin::submit()
             depotFileNames.append(line.mid(14));
     }
     if (depotFileNames.isEmpty()) {
-        showOutput(tr("Project has no files"));
+        VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Project has no files"));
         cleanChangeTmpFile();
         return;
     }
@@ -804,8 +791,9 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args,
         qDebug() << "PerforcePlugin::runP4Cmd" << args << extraArgs << debugCodec(outputCodec);
     PerforceResponse response;
     response.error = true;
+    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
     if (!checkP4Configuration(&response.message)) {
-        m_perforceOutputWindow->append(response.message, true);
+        outputWindow->appendError(response.message);
         return response;
     }
 
@@ -832,9 +820,8 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args,
         QString command = m_settings.p4Command();
         command += blank;
         command += actualArgs.join(QString(blank));
-        const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm"));
-        const QString outputText = tr("%1 Executing: %2\n").arg(timeStamp, command);
-        showOutput(outputText, false);
+        const QString outputText = tr("Executing: %1\n").arg(command);
+        outputWindow->appendCommand(outputText);
     }
 
     // Run, connect stderr to the output window
@@ -846,13 +833,13 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args,
     // connect stderr to the output window if desired
     if (logFlags & StdErrToWindow) {
         process.setStdErrBufferedSignalsEnabled(true);
-        connect(&process, SIGNAL(stdErrBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool)));
+        connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
     }
 
     // connect stdout to the output window if desired
     if (logFlags & StdOutToWindow) {
         process.setStdOutBufferedSignalsEnabled(true);
-        connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool)));
+        connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
     }
 
     const Core::Utils::SynchronousProcessResponse sp_resp = process.run(m_settings.p4Command(), actualArgs);
@@ -883,7 +870,7 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args,
         if (Perforce::Constants::debug)
             qDebug() << response.message;
         if (logFlags & ErrorToWindow)
-            m_perforceOutputWindow->append(response.message, true);
+            outputWindow->appendError(response.message);
     }
     return response;
 }
@@ -1043,7 +1030,7 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
             QByteArray change = m_changeTmpFile->readAll();
             QString errorMessage;
             if (!checkP4Configuration(&errorMessage)) {
-                showOutput(errorMessage, true);
+                VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
                 return false;
             }
 
@@ -1054,7 +1041,7 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
             proc.start(m_settings.p4Command(),
                 m_settings.basicP4Args() << QLatin1String("submit") << QLatin1String("-i"));
             if (!proc.waitForStarted(p4Timeout)) {
-                showOutput(tr("Cannot execute p4 submit."), true);
+                VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot execute p4 submit."));
                 QApplication::restoreOverrideCursor();
                 return false;
             }
@@ -1062,12 +1049,12 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
             proc.closeWriteChannel();
 
             if (!proc.waitForFinished()) {
-                showOutput(tr("Cannot execute p4 submit."), true);
+                VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot execute p4 submit."));
                 QApplication::restoreOverrideCursor();
                 return false;
             }
-            const QString output = QString::fromUtf8(proc.readAll());
-            showOutput(output);
+            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(editor->widget(), tr("Pending change"), tr("Could not submit the change, because your workspace was out of date. Created a pending submit instead."));
             }
@@ -1161,49 +1148,8 @@ QString PerforcePlugin::pendingChangesData()
     return data;
 }
 
-void PerforcePlugin::showOutput(const QString &output, bool popup) const
-{
-    m_perforceOutputWindow->append(output, popup);
-}
-
 PerforcePlugin::~PerforcePlugin()
 {
-    if (m_settingsPage) {
-        removeObject(m_settingsPage);
-        delete m_settingsPage;
-        m_settingsPage = 0;
-    }
-
-    if (m_perforceOutputWindow) {
-        removeObject(m_perforceOutputWindow);
-        delete  m_perforceOutputWindow;
-        m_perforceOutputWindow = 0;
-    }
-
-    if (m_submitEditorFactory) {
-        removeObject(m_submitEditorFactory);
-        delete m_submitEditorFactory;
-        m_submitEditorFactory = 0;
-    }
-
-    if (m_versionControl) {
-        removeObject(m_versionControl);
-        delete m_versionControl;
-        m_versionControl = 0;
-    }
-
-    if (!m_editorFactories.empty()) {
-        foreach (Core::IEditorFactory *pf, m_editorFactories)
-            removeObject(pf);
-        qDeleteAll(m_editorFactories);
-        m_editorFactories.clear();
-    }
-
-    if (m_coreListener) {
-        removeObject(m_coreListener);
-        delete m_coreListener;
-        m_coreListener = 0;
-    }
 }
 
 const PerforceSettings& PerforcePlugin::settings() const
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
index 423b352e3f6..6f2645c7827 100644
--- a/src/plugins/perforce/perforceplugin.h
+++ b/src/plugins/perforce/perforceplugin.h
@@ -50,7 +50,6 @@ class QTextCodec;
 QT_END_NAMESPACE
 
 namespace Core {
-    class IEditorFactory;
     namespace Utils {
         class ParameterAction;
     }
@@ -59,8 +58,6 @@ namespace Core {
 namespace Perforce {
 namespace Internal {
 
-class PerforceOutputWindow;
-class SettingsPage;
 class PerforceVersionControl;
 class PerforcePlugin;
 
@@ -92,8 +89,6 @@ public:
     PerforcePlugin();
     ~PerforcePlugin();
 
-    SettingsPage *settingsPage() const { return m_settingsPage; }
-
     bool initialize(const QStringList &arguments, QString *error_message);
     void extensionsInitialized();
 
@@ -165,16 +160,12 @@ private:
     QString clientFilePath(const QString &serverFilePath);
     QString currentFileName();
     bool checkP4Configuration(QString *errorMessage = 0) const;
-    void showOutput(const QString &output, bool popup = false) const;
     void annotate(const QString &fileName);
     void filelog(const QString &fileName);
     void cleanChangeTmpFile();
     void updateCheckout(const QStringList &dirs = QStringList());
 
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
-    PerforceOutputWindow *m_perforceOutputWindow;
-    SettingsPage *m_settingsPage;
-    QList<Core::IEditorFactory*> m_editorFactories;
 
     Core::Utils::ParameterAction *m_editAction;
     Core::Utils::ParameterAction *m_addAction;
@@ -206,12 +197,8 @@ private:
     static PerforcePlugin *m_perforcePluginInstance;
     QString pendingChangesData();
 
-    CoreListener *m_coreListener;
-    Core::IEditorFactory *m_submitEditorFactory;
     PerforceVersionControl *m_versionControl;
     PerforceSettings m_settings;
-
-    friend class PerforceOutputWindow; // needs openFiles()
 };
 
 } // namespace Perforce
diff --git a/src/plugins/subversion/subversion.pro b/src/plugins/subversion/subversion.pro
index f72f0096bb5..3879d42568c 100644
--- a/src/plugins/subversion/subversion.pro
+++ b/src/plugins/subversion/subversion.pro
@@ -11,7 +11,6 @@ include(../../libs/utils/utils.pri)
 HEADERS += annotationhighlighter.h \
     subversionplugin.h \
     subversioncontrol.h \
-    subversionoutputwindow.h \
     settingspage.h \
     subversioneditor.h \
     subversionsubmiteditor.h \
@@ -22,7 +21,6 @@ HEADERS += annotationhighlighter.h \
 SOURCES += annotationhighlighter.cpp \
     subversionplugin.cpp \
     subversioncontrol.cpp \
-    subversionoutputwindow.cpp \
     settingspage.cpp \
     subversioneditor.cpp \
     subversionsubmiteditor.cpp \
diff --git a/src/plugins/subversion/subversionoutputwindow.cpp b/src/plugins/subversion/subversionoutputwindow.cpp
deleted file mode 100644
index 8386d62700a..00000000000
--- a/src/plugins/subversion/subversionoutputwindow.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://www.qtsoftware.com/contact.
-**
-**************************************************************************/
-
-#include "subversionoutputwindow.h"
-#include "subversionplugin.h"
-
-#include <QtGui/QListWidget>
-#include <QtCore/QDebug>
-
-using namespace Subversion::Internal;
-
-SubversionOutputWindow::SubversionOutputWindow(SubversionPlugin *svnPlugin)
-    : m_svnPlugin(svnPlugin)
-{
-    m_outputListWidget = new QListWidget;
-    m_outputListWidget->setFrameStyle(QFrame::NoFrame);
-    m_outputListWidget->setWindowTitle(tr("Subversion Output"));
-    m_outputListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
-}
-
-SubversionOutputWindow::~SubversionOutputWindow()
-{
-    delete m_outputListWidget;
-}
-
-QWidget *SubversionOutputWindow::outputWidget(QWidget *parent)
-{
-    m_outputListWidget->setParent(parent);
-    return m_outputListWidget;
-}
-
-QString SubversionOutputWindow::name() const
-{
-    return tr("Subversion");
-}
-
-void SubversionOutputWindow::clearContents()
-{
-    m_outputListWidget->clear();
-}
-
-int SubversionOutputWindow::priorityInStatusBar() const
-{
-    return -1;
-}
-
-void SubversionOutputWindow::visibilityChanged(bool b)
-{
-    if (b)
-        m_outputListWidget->setFocus();
-}
-
-void SubversionOutputWindow::append(const QString &txt, bool doPopup)
-{
-    const QStringList lines = txt.split(QLatin1Char('\n'));
-    foreach (const QString &s, lines)
-        m_outputListWidget->addItem(s);
-    m_outputListWidget->scrollToBottom();
-
-    if (doPopup)
-        popup();
-}
-
-bool SubversionOutputWindow::canFocus()
-{
-    return false;
-}
-
-bool SubversionOutputWindow::hasFocus()
-{
-    return m_outputListWidget->hasFocus();
-}
-
-void SubversionOutputWindow::setFocus()
-{
-}
-
-bool SubversionOutputWindow::canNext()
-{
-    return false;
-}
-
-bool SubversionOutputWindow::canPrevious()
-{
-    return false;
-}
-
-void SubversionOutputWindow::goToNext()
-{
-
-}
-
-void SubversionOutputWindow::goToPrev()
-{
-
-}
-
-bool SubversionOutputWindow::canNavigate()
-{
-    return false;
-}
diff --git a/src/plugins/subversion/subversionoutputwindow.h b/src/plugins/subversion/subversionoutputwindow.h
deleted file mode 100644
index bc940fa2e52..00000000000
--- a/src/plugins/subversion/subversionoutputwindow.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://www.qtsoftware.com/contact.
-**
-**************************************************************************/
-
-#ifndef SUBVERSIONOUTPUTWINDOW_H
-#define SUBVERSIONOUTPUTWINDOW_H
-
-#include <coreplugin/ioutputpane.h>
-
-QT_BEGIN_NAMESPACE
-class QListWidget;
-QT_END_NAMESPACE
-
-namespace Subversion {
-namespace Internal {
-
-class SubversionPlugin;
-
-class SubversionOutputWindow : public Core::IOutputPane
-{
-    Q_OBJECT
-
-public:
-    SubversionOutputWindow(SubversionPlugin *svnPlugin);
-    ~SubversionOutputWindow();
-
-    QWidget *outputWidget(QWidget *parent);
-    QList<QWidget*> toolBarWidgets() const {
-        return QList<QWidget *>();
-    }
-
-    QString name() const;
-    void clearContents();
-    int priorityInStatusBar() const;
-    void visibilityChanged(bool visible);
-
-    bool canFocus();
-    bool hasFocus();
-    void setFocus();
-
-    bool canNext();
-    bool canPrevious();
-    void goToNext();
-    void goToPrev();
-    bool canNavigate();
-
-public slots:
-    void append(const QString &txt, bool popup = false);
-
-private:
-
-    SubversionPlugin *m_svnPlugin;
-    QListWidget *m_outputListWidget;
-};
-
-} // namespace Subversion
-} // namespace Internal
-
-#endif // SUBVERSIONOUTPUTWINDOW_H
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index e25750fe217..2dad22ccd9d 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -32,7 +32,6 @@
 #include "settingspage.h"
 #include "subversioneditor.h"
 
-#include "subversionoutputwindow.h"
 #include "subversionsubmiteditor.h"
 #include "subversionconstants.h"
 #include "subversioncontrol.h"
@@ -41,6 +40,7 @@
 #include <vcsbase/basevcseditorfactory.h>
 #include <vcsbase/vcsbaseeditor.h>
 #include <vcsbase/basevcssubmiteditorfactory.h>
+#include <vcsbase/vcsbaseoutputwindow.h>
 #include <utils/synchronousprocess.h>
 #include <utils/parameteraction.h>
 
@@ -181,7 +181,6 @@ SubversionPlugin::SubversionPlugin() :
     m_svnDirectories(svnDirectories()),
     m_versionControl(0),
     m_changeTmpFile(0),
-    m_subversionOutputWindow(0),
     m_projectExplorer(0),
     m_addAction(0),
     m_deleteAction(0),
@@ -267,9 +266,6 @@ bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMe
     for (int i = 0; i < editorCount; i++)
         addAutoReleasedObject(new SubversionEditorFactory(editorParameters + i, this, describeSlot));
 
-    m_subversionOutputWindow = new SubversionOutputWindow(this);
-    addAutoReleasedObject(m_subversionOutputWindow);
-
     addAutoReleasedObject(new CheckoutWizard);
 
     //register actions
@@ -663,7 +659,7 @@ void SubversionPlugin::startCommit(const QStringList &files)
     if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
         return;
     if (m_changeTmpFile) {
-        showOutput(tr("Another commit is currently being executed."));
+        VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("Another commit is currently being executed."));
         return;
     }
 
@@ -678,7 +674,7 @@ void SubversionPlugin::startCommit(const QStringList &files)
     // Get list of added/modified/deleted files
     const StatusList statusOutput = parseStatusOutput(response.stdOut);
     if (statusOutput.empty()) {
-        showOutput(tr("There are no modified files."), true);
+        VCSBase::VCSBaseOutputWindow::instance()->appendWarning(tr("There are no modified files."));
         return;
     }
 
@@ -686,7 +682,7 @@ void SubversionPlugin::startCommit(const QStringList &files)
     QTemporaryFile *changeTmpFile = new QTemporaryFile(this);
     changeTmpFile->setAutoRemove(true);
     if (!changeTmpFile->open()) {
-        showOutput(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Cannot create temporary file: %1").arg(changeTmpFile->errorString()));
         delete changeTmpFile;
         return;
     }
@@ -923,11 +919,11 @@ SubversionResponse SubversionPlugin::runSvn(const QStringList &arguments,
     }
     const QStringList allArgs = m_settings.addOptions(arguments);
 
+    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
     // Hide passwords, etc in the log window
-    const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm"));
-    //: <timestamp> Executing: <executable> <arguments>
-    const QString outputText = tr("%1 Executing: %2 %3\n").arg(timeStamp, executable, SubversionSettings::formatArguments(allArgs));
-    showOutput(outputText, false);
+    //: Executing: <executable> <arguments>
+    const QString outputText = tr("Executing: %1 %2\n").arg(executable, SubversionSettings::formatArguments(allArgs));
+    outputWindow->appendCommand(outputText);
 
     if (Subversion::Constants::debug)
         qDebug() << "runSvn" << timeOut << outputText;
@@ -938,12 +934,12 @@ SubversionResponse SubversionPlugin::runSvn(const QStringList &arguments,
     process.setStdOutCodec(outputCodec);
 
     process.setStdErrBufferedSignalsEnabled(true);
-    connect(&process, SIGNAL(stdErrBuffered(QString,bool)), m_subversionOutputWindow, SLOT(append(QString,bool)));
+    connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
 
     // connect stdout to the output window if desired
     if (showStdOutInOutputWindow) {
         process.setStdOutBufferedSignalsEnabled(true);
-        connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_subversionOutputWindow, SLOT(append(QString,bool)));
+        connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
     }
 
     const Core::Utils::SynchronousProcessResponse sp_resp = process.run(executable, allArgs);
@@ -968,18 +964,11 @@ SubversionResponse SubversionPlugin::runSvn(const QStringList &arguments,
         break;
     }
     if (response.error)
-        m_subversionOutputWindow->append(response.message, true);
+        outputWindow->appendError(response.message);
 
     return response;
 }
 
-void SubversionPlugin::showOutput(const QString &output, bool bringToForeground)
-{
-    m_subversionOutputWindow->append(output);
-    if (bringToForeground)
-        m_subversionOutputWindow->popup();
-}
-
 Core::IEditor * SubversionPlugin::showOutputInEditor(const QString& title, const QString &output,
                                                      int editorType, const QString &source,
                                                      QTextCodec *codec)
diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h
index 199f419dbfd..d2640c8e186 100644
--- a/src/plugins/subversion/subversionplugin.h
+++ b/src/plugins/subversion/subversionplugin.h
@@ -56,7 +56,6 @@ namespace ProjectExplorer {
 namespace Subversion {
 namespace Internal {
 
-class SubversionOutputWindow;
 class SubversionSubmitEditor;
 
 struct SubversionResponse
@@ -120,7 +119,6 @@ private:
                                        QTextCodec *codec);
     SubversionResponse runSvn(const QStringList &arguments, int timeOut,
                               bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0);
-    void showOutput(const QString &output, bool bringToForeground = true);
     void annotate(const QString &file);
     void filelog(const QString &file);
     bool managesDirectory(const QDir &directory) const;
@@ -136,7 +134,6 @@ private:
     Core::IVersionControl *m_versionControl;
     QTemporaryFile *m_changeTmpFile;
 
-    SubversionOutputWindow *m_subversionOutputWindow;
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
 
     Core::Utils::ParameterAction *m_addAction;
@@ -159,8 +156,6 @@ private:
     bool    m_submitActionTriggered;
 
     static SubversionPlugin *m_subversionPluginInstance;
-
-    friend class SubversionOutputWindow;
 };
 
 // Just a proxy for SubversionPlugin
diff --git a/src/plugins/vcsbase/vcsbase.pro b/src/plugins/vcsbase/vcsbase.pro
index 1465c9db7f2..45461211b95 100644
--- a/src/plugins/vcsbase/vcsbase.pro
+++ b/src/plugins/vcsbase/vcsbase.pro
@@ -22,7 +22,8 @@ HEADERS += vcsbase_global.h \
     checkoutwizarddialog.h \
     checkoutprogresswizardpage.h \
     checkoutjobs.h \
-    basecheckoutwizardpage.h
+    basecheckoutwizardpage.h \
+    vcsbaseoutputwindow.h
 
 SOURCES += vcsbaseplugin.cpp \
     baseannotationhighlighter.cpp \
@@ -41,7 +42,8 @@ SOURCES += vcsbaseplugin.cpp \
     checkoutwizarddialog.cpp \
     checkoutprogresswizardpage.cpp \
     checkoutjobs.cpp \
-    basecheckoutwizardpage.cpp
+    basecheckoutwizardpage.cpp \
+    vcsbaseoutputwindow.cpp
 
 RESOURCES += vcsbase.qrc
 
diff --git a/src/plugins/vcsbase/vcsbaseoutputwindow.cpp b/src/plugins/vcsbase/vcsbaseoutputwindow.cpp
new file mode 100644
index 00000000000..4ddfb4cb817
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbaseoutputwindow.cpp
@@ -0,0 +1,295 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#include "vcsbaseoutputwindow.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QTextCharFormat>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+
+#include <QtCore/QPointer>
+#include <QtCore/QTextCodec>
+#include <QtCore/QTime>
+
+namespace VCSBase {
+
+namespace Internal {
+
+// A plain text edit with a special context menu containing "Clear" and
+// and functions to append specially formatted entries.
+class OutputWindowPlainTextEdit : public QPlainTextEdit {
+public:
+    explicit OutputWindowPlainTextEdit(QWidget *parent);
+
+    void appendLines(QString s);
+    // Append red error text and pop up.
+    void appendError(const QString &text);
+    // Append warning error text and pop up.
+    void appendWarning(const QString &text);
+    // Append a bold command "10:00 " + "Executing: vcs -diff"
+    void appendCommand(const QString &text);
+
+protected:
+    virtual void contextMenuEvent(QContextMenuEvent *event);
+
+private:
+    const QTextCharFormat m_defaultFormat;
+    QTextCharFormat m_errorFormat;
+    QTextCharFormat m_warningFormat;
+    QTextCharFormat m_commandFormat;
+};
+
+OutputWindowPlainTextEdit::OutputWindowPlainTextEdit(QWidget *parent) :
+    QPlainTextEdit(parent),
+    m_defaultFormat(currentCharFormat()),
+    m_errorFormat(m_defaultFormat),
+    m_warningFormat(m_defaultFormat),
+    m_commandFormat(m_defaultFormat)
+{
+    setReadOnly(true);
+    setFrameStyle(QFrame::NoFrame);
+    m_errorFormat.setForeground(Qt::red);
+    m_warningFormat.setForeground(Qt::darkYellow);
+    m_commandFormat.setFontWeight(QFont::Bold);
+}
+
+void OutputWindowPlainTextEdit::contextMenuEvent(QContextMenuEvent *event)
+{
+    QMenu *menu = createStandardContextMenu();
+    menu->addSeparator();
+    QAction *clearAction = menu->addAction(VCSBaseOutputWindow::tr("Clear"));
+    connect(clearAction, SIGNAL(triggered()), this, SLOT(clear()));
+    menu->exec(event->globalPos());
+    delete menu;
+}
+
+void OutputWindowPlainTextEdit::appendLines(QString s)
+{
+    if (s.isEmpty())
+        return;
+    // Avoid additional new line character generated by appendPlainText
+    if (s.endsWith(QLatin1Char('\n')))
+        s.truncate(s.size() - 1);
+    appendPlainText(s);
+    // Scroll down
+    moveCursor(QTextCursor::End);
+    ensureCursorVisible();
+}
+
+void OutputWindowPlainTextEdit::appendError(const QString &text)
+{
+    setCurrentCharFormat(m_errorFormat);
+    appendLines(text);
+    setCurrentCharFormat(m_defaultFormat);
+}
+
+void OutputWindowPlainTextEdit::appendWarning(const QString &text)
+{
+    setCurrentCharFormat(m_warningFormat);
+    appendLines(text);
+    setCurrentCharFormat(m_defaultFormat);
+}
+
+// Append command with new line and log time stamp
+void OutputWindowPlainTextEdit::appendCommand(const QString &text)
+{
+    setCurrentCharFormat(m_commandFormat);
+    const QString timeStamp = QTime::currentTime().toString(QLatin1String("\nHH:mm "));
+    appendLines(timeStamp + text);
+    setCurrentCharFormat(m_defaultFormat);
+}
+
+} // namespace Internal
+
+// ------------------- VCSBaseOutputWindowPrivate
+struct VCSBaseOutputWindowPrivate {
+    static VCSBaseOutputWindow *instance;
+    QPointer<Internal::OutputWindowPlainTextEdit> plainTextEdit;
+};
+
+VCSBaseOutputWindow *VCSBaseOutputWindowPrivate::instance = 0;
+
+VCSBaseOutputWindow::VCSBaseOutputWindow() :
+    d(new VCSBaseOutputWindowPrivate)
+{
+    VCSBaseOutputWindowPrivate::instance = this;
+}
+
+VCSBaseOutputWindow::~VCSBaseOutputWindow()
+{
+    VCSBaseOutputWindowPrivate::instance = 0;
+    delete d;
+}
+
+QWidget *VCSBaseOutputWindow::outputWidget(QWidget *parent)
+{
+    if (!d->plainTextEdit)
+        d->plainTextEdit = new Internal::OutputWindowPlainTextEdit(parent);
+    return d->plainTextEdit;
+}
+
+QWidgetList VCSBaseOutputWindow::toolBarWidgets() const
+{
+    return QWidgetList();
+}
+
+QString VCSBaseOutputWindow::name() const
+{
+    return tr("Version Control");
+}
+
+int VCSBaseOutputWindow::priorityInStatusBar() const
+{
+    return -1;
+}
+
+void VCSBaseOutputWindow::clearContents()
+{
+    QTC_ASSERT(d->plainTextEdit, return)
+    d->plainTextEdit->clear();
+}
+
+void VCSBaseOutputWindow::visibilityChanged(bool visible)
+{
+    if (visible && d->plainTextEdit)
+        d->plainTextEdit->setFocus();
+}
+
+void VCSBaseOutputWindow::setFocus()
+{
+}
+
+bool VCSBaseOutputWindow::hasFocus()
+{
+    return false;
+}
+
+bool VCSBaseOutputWindow::canFocus()
+{
+    return false;
+}
+
+bool VCSBaseOutputWindow::canNavigate()
+{
+    return false;
+}
+
+bool VCSBaseOutputWindow::canNext()
+{
+    return false;
+}
+
+bool VCSBaseOutputWindow::canPrevious()
+{
+    return false;
+}
+
+void VCSBaseOutputWindow::goToNext()
+{
+}
+
+void VCSBaseOutputWindow::goToPrev()
+{
+}
+
+void VCSBaseOutputWindow::setText(const QString &text)
+{
+    QTC_ASSERT(d->plainTextEdit, return)
+    d->plainTextEdit->setPlainText(text);
+}
+
+void VCSBaseOutputWindow::setData(const QByteArray &data)
+{
+    setText(QTextCodec::codecForLocale()->toUnicode(data));
+}
+
+void VCSBaseOutputWindow::appendSilently(const QString &text)
+{
+    QTC_ASSERT(d->plainTextEdit, return)
+    d->plainTextEdit->appendLines(text);
+}
+
+void VCSBaseOutputWindow::append(const QString &text)
+{
+    QTC_ASSERT(d->plainTextEdit, return)
+    appendSilently(text);
+    // Pop up without focus
+    if (!d->plainTextEdit->isVisible())
+        popup(false);
+}
+
+void VCSBaseOutputWindow::appendError(const QString &text)
+{
+    QTC_ASSERT(d->plainTextEdit, return)
+    d->plainTextEdit->appendError(text);
+    if (!d->plainTextEdit->isVisible())
+        popup(false); // Pop up without focus
+}
+
+void VCSBaseOutputWindow::appendWarning(const QString &text)
+{
+    QTC_ASSERT(d->plainTextEdit, return)
+    d->plainTextEdit->appendWarning(text);
+    if (!d->plainTextEdit->isVisible())
+        popup(false); // Pop up without focus
+}
+
+void VCSBaseOutputWindow::appendCommand(const QString &text)
+{
+    QTC_ASSERT(d->plainTextEdit, return)
+    d->plainTextEdit->appendCommand(text);
+}
+
+void VCSBaseOutputWindow::appendData(const QByteArray &data)
+{
+    QTC_ASSERT(d->plainTextEdit, return)
+    appendDataSilently(data);
+    if (!d->plainTextEdit->isVisible())
+        popup(false); // Pop up without focus
+}
+
+void VCSBaseOutputWindow::appendDataSilently(const QByteArray &data)
+{
+    append(QTextCodec::codecForLocale()->toUnicode(data));
+}
+
+VCSBaseOutputWindow *VCSBaseOutputWindow::instance()
+{
+    if (!VCSBaseOutputWindowPrivate::instance) {
+        VCSBaseOutputWindow *w = new VCSBaseOutputWindow;
+        Q_UNUSED(w)
+    }
+    return VCSBaseOutputWindowPrivate::instance;
+}
+
+} // namespace VCSBase
diff --git a/src/plugins/vcsbase/vcsbaseoutputwindow.h b/src/plugins/vcsbase/vcsbaseoutputwindow.h
new file mode 100644
index 00000000000..dce15448245
--- /dev/null
+++ b/src/plugins/vcsbase/vcsbaseoutputwindow.h
@@ -0,0 +1,107 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef VCSBASEOUTPUTWINDOW_H
+#define VCSBASEOUTPUTWINDOW_H
+
+#include "vcsbase_global.h"
+
+#include  <coreplugin/ioutputpane.h>
+
+namespace VCSBase {
+
+struct VCSBaseOutputWindowPrivate;
+
+/* Common OutputWindow for Version Control System command and other output.
+ * Installed by the base plugin and accessible for the other plugins
+ * via static instance()-accessor. Provides slots to append output with
+ * special formatting. */
+
+class VCSBASE_EXPORT VCSBaseOutputWindow : public Core::IOutputPane
+{
+    Q_OBJECT
+public:
+    virtual ~VCSBaseOutputWindow();
+
+    virtual QWidget *outputWidget(QWidget *parent);
+    virtual QWidgetList toolBarWidgets() const;
+    virtual QString name() const;
+
+    virtual int priorityInStatusBar() const;
+
+    virtual void clearContents();
+    virtual void visibilityChanged(bool visible);
+
+    virtual void setFocus();
+    virtual bool hasFocus();
+    virtual bool canFocus();
+
+    virtual bool canNavigate();
+    virtual bool canNext();
+    virtual bool canPrevious();
+    virtual void goToNext();
+    virtual void goToPrev();
+
+    static VCSBaseOutputWindow *instance();
+
+public slots:
+    // Set the whole text.
+    void setText(const QString &text);
+    // Set text from QProcess' output data using the Locale's converter.
+    void setData(const QByteArray &data);
+
+    // Append text and pop up.
+    void append(const QString &text);
+    // Append data using the Locale's converter and pop up.
+    void appendData(const QByteArray &data);
+
+    // Silently append text, do not pop up.
+    void appendSilently(const QString &text);
+    // Silently append data using the Locale's converter, do not pop up.
+    void appendDataSilently(const QByteArray &data);
+
+    // Append red error text and pop up.
+    void appendError(const QString &text);
+
+    // Append dark-yellow warning text and pop up.
+    void appendWarning(const QString &text);
+
+    // Append a command, prepended by a log time stamp. "Executing: vcs -diff"
+    // will result in "10:00 Executing: vcs -diff" in bold
+    void appendCommand(const QString &text);
+
+private:
+    VCSBaseOutputWindow();
+
+    VCSBaseOutputWindowPrivate *d;
+};
+
+} // namespace VCSBase
+
+#endif // VCSBASEOUTPUTWINDOW_H
diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp
index 6a869aca38f..eec73468ce9 100644
--- a/src/plugins/vcsbase/vcsbaseplugin.cpp
+++ b/src/plugins/vcsbase/vcsbaseplugin.cpp
@@ -31,6 +31,7 @@
 #include "diffhighlighter.h"
 #include "vcsbasesettingspage.h"
 #include "nicknamedialog.h"
+#include "vcsbaseoutputwindow.h"
 
 #include <coreplugin/icore.h>
 #include <coreplugin/coreconstants.h>
@@ -68,6 +69,7 @@ bool VCSBasePlugin::initialize(const QStringList &arguments, QString *errorMessa
 
     m_settingsPage = new VCSBaseSettingsPage;
     addAutoReleasedObject(m_settingsPage);
+    addAutoReleasedObject(VCSBaseOutputWindow::instance());
     connect(m_settingsPage, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)),
             this, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)));
     connect(m_settingsPage, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)),
-- 
GitLab