OSDN Git Service

Make output window implementation reusable.
authorcon <qtc-committer@nokia.com>
Thu, 14 Apr 2011 08:39:09 +0000 (10:39 +0200)
committercon <qtc-committer@nokia.com>
Tue, 26 Apr 2011 08:45:25 +0000 (10:45 +0200)
Removes the dependencies to project explorer and text editor plugins
and moves unrelated code to its own file.

src/plugins/coreplugin/outputwindow.cpp [new file with mode: 0644]
src/plugins/coreplugin/outputwindow.h [new file with mode: 0644]
src/plugins/projectexplorer/appoutputpane.cpp [new file with mode: 0644]
src/plugins/projectexplorer/appoutputpane.h [moved from src/plugins/projectexplorer/outputwindow.h with 55% similarity]
src/plugins/projectexplorer/compileoutputwindow.cpp
src/plugins/projectexplorer/compileoutputwindow.h
src/plugins/projectexplorer/localapplicationruncontrol.cpp
src/plugins/projectexplorer/outputwindow.cpp [deleted file]
src/plugins/projectexplorer/projectexplorer.cpp
src/plugins/projectexplorer/projectexplorer.pro
src/plugins/projectexplorer/projectexplorerconstants.h

diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp
new file mode 100644 (file)
index 0000000..e992df6
--- /dev/null
@@ -0,0 +1,335 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#include "outputwindow.h"
+
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/icore.h>
+
+#include <utils/qtcassert.h>
+#include <utils/outputformatter.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QScrollBar>
+
+static const int MaxBlockCount = 100000;
+
+using namespace Utils;
+
+namespace ProjectExplorer {
+namespace Internal {
+
+/*******************/
+
+OutputWindow::OutputWindow(Core::Context context, QWidget *parent)
+    : QPlainTextEdit(parent)
+    , m_formatter(0)
+    , m_enforceNewline(false)
+    , m_scrollToBottom(false)
+    , m_linksActive(true)
+    , m_mousePressed(false)
+{
+    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+    //setCenterOnScroll(false);
+    setFrameShape(QFrame::NoFrame);
+    setMouseTracking(true);
+
+    Core::ICore *core = Core::ICore::instance();
+
+    m_outputWindowContext = new Core::IContext;
+    m_outputWindowContext->setContext(context);
+    m_outputWindowContext->setWidget(this);
+    core->addContextObject(m_outputWindowContext);
+
+    QAction *undoAction = new QAction(this);
+    QAction *redoAction = new QAction(this);
+    QAction *cutAction = new QAction(this);
+    QAction *copyAction = new QAction(this);
+    QAction *pasteAction = new QAction(this);
+    QAction *selectAllAction = new QAction(this);
+
+    Core::ActionManager *am = core->actionManager();
+    am->registerAction(undoAction, Core::Constants::UNDO, context);
+    am->registerAction(redoAction, Core::Constants::REDO, context);
+    am->registerAction(cutAction, Core::Constants::CUT, context);
+    am->registerAction(copyAction, Core::Constants::COPY, context);
+    am->registerAction(pasteAction, Core::Constants::PASTE, context);
+    am->registerAction(selectAllAction, Core::Constants::SELECTALL, context);
+
+    connect(undoAction, SIGNAL(triggered()), this, SLOT(undo()));
+    connect(redoAction, SIGNAL(triggered()), this, SLOT(redo()));
+    connect(cutAction, SIGNAL(triggered()), this, SLOT(cut()));
+    connect(copyAction, SIGNAL(triggered()), this, SLOT(copy()));
+    connect(pasteAction, SIGNAL(triggered()), this, SLOT(paste()));
+    connect(selectAllAction, SIGNAL(triggered()), this, SLOT(selectAll()));
+
+    connect(this, SIGNAL(undoAvailable(bool)), undoAction, SLOT(setEnabled(bool)));
+    connect(this, SIGNAL(redoAvailable(bool)), redoAction, SLOT(setEnabled(bool)));
+    connect(this, SIGNAL(copyAvailable(bool)), cutAction, SLOT(setEnabled(bool)));  // OutputWindow never read-only
+    connect(this, SIGNAL(copyAvailable(bool)), copyAction, SLOT(setEnabled(bool)));
+
+    undoAction->setEnabled(false);
+    redoAction->setEnabled(false);
+    cutAction->setEnabled(false);
+    copyAction->setEnabled(false);
+}
+
+OutputWindow::~OutputWindow()
+{
+    Core::ICore::instance()->removeContextObject(m_outputWindowContext);
+    delete m_outputWindowContext;
+}
+
+void OutputWindow::mousePressEvent(QMouseEvent * e)
+{
+    m_mousePressed = true;
+    QPlainTextEdit::mousePressEvent(e);
+}
+
+void OutputWindow::mouseReleaseEvent(QMouseEvent *e)
+{
+    m_mousePressed = false;
+
+    if (m_linksActive) {
+        const QString href = anchorAt(e->pos());
+        if (m_formatter)
+            m_formatter->handleLink(href);
+    }
+
+    // Mouse was released, activate links again
+    m_linksActive = true;
+
+    QPlainTextEdit::mouseReleaseEvent(e);
+}
+
+void OutputWindow::mouseMoveEvent(QMouseEvent *e)
+{
+    // Cursor was dragged to make a selection, deactivate links
+    if (m_mousePressed && textCursor().hasSelection())
+        m_linksActive = false;
+
+    if (!m_linksActive || anchorAt(e->pos()).isEmpty())
+        viewport()->setCursor(Qt::IBeamCursor);
+    else
+        viewport()->setCursor(Qt::PointingHandCursor);
+    QPlainTextEdit::mouseMoveEvent(e);
+}
+
+void OutputWindow::resizeEvent(QResizeEvent *e)
+{
+    //Keep scrollbar at bottom of window while resizing, to ensure we keep scrolling
+    //This can happen if window is resized while building, or if the horizontal scrollbar appears
+    bool atBottom = isScrollbarAtBottom();
+    QPlainTextEdit::resizeEvent(e);
+    if (atBottom)
+        scrollToBottom();
+}
+
+void OutputWindow::keyPressEvent(QKeyEvent *ev)
+{
+    QPlainTextEdit::keyPressEvent(ev);
+
+    //Ensure we scroll also on Ctrl+Home or Ctrl+End
+    if (ev->matches(QKeySequence::MoveToStartOfDocument))
+        verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMinimum);
+    else if (ev->matches(QKeySequence::MoveToEndOfDocument))
+        verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
+}
+
+OutputFormatter *OutputWindow::formatter() const
+{
+    return m_formatter;
+}
+
+void OutputWindow::setFormatter(OutputFormatter *formatter)
+{
+    m_formatter = formatter;
+    m_formatter->setPlainTextEdit(this);
+}
+
+void OutputWindow::showEvent(QShowEvent *e)
+{
+    QPlainTextEdit::showEvent(e);
+    if (m_scrollToBottom) {
+        verticalScrollBar()->setValue(verticalScrollBar()->maximum());
+    }
+    m_scrollToBottom = false;
+}
+
+QString OutputWindow::doNewlineEnfocement(const QString &out)
+{
+    m_scrollToBottom = true;
+    QString s = out;
+    if (m_enforceNewline) {
+        s.prepend(QLatin1Char('\n'));
+        m_enforceNewline = false;
+    }
+
+    if (s.endsWith(QLatin1Char('\n'))) {
+        m_enforceNewline = true; // make appendOutputInline put in a newline next time
+        s.chop(1);
+    }
+
+    return s;
+}
+
+void OutputWindow::appendMessage(const QString &output, OutputFormat format)
+{
+    QString out = output;
+    out.remove(QLatin1Char('\r'));
+    setMaximumBlockCount(MaxBlockCount);
+    const bool atBottom = isScrollbarAtBottom();
+
+    if (format == ErrorMessageFormat || format == NormalMessageFormat) {
+
+        m_formatter->appendMessage(doNewlineEnfocement(out), format);
+
+    } else {
+
+        bool sameLine = format == StdOutFormatSameLine
+                     || format == StdErrFormatSameLine;
+
+        if (sameLine) {
+            m_scrollToBottom = true;
+
+            int newline = -1;
+            bool enforceNewline = m_enforceNewline;
+            m_enforceNewline = false;
+
+            if (!enforceNewline) {
+                newline = out.indexOf(QLatin1Char('\n'));
+                moveCursor(QTextCursor::End);
+                if (newline != -1)
+                    m_formatter->appendMessage(out.left(newline), format);// doesn't enforce new paragraph like appendPlainText
+            }
+
+            QString s = out.mid(newline+1);
+            if (s.isEmpty()) {
+                m_enforceNewline = true;
+            } else {
+                if (s.endsWith(QLatin1Char('\n'))) {
+                    m_enforceNewline = true;
+                    s.chop(1);
+                }
+                m_formatter->appendMessage(QLatin1Char('\n') + s, format);
+            }
+        } else {
+            m_formatter->appendMessage(doNewlineEnfocement(out), format);
+        }
+    }
+
+    if (atBottom)
+        scrollToBottom();
+    enableUndoRedo();
+}
+
+// TODO rename
+void OutputWindow::appendText(const QString &textIn, const QTextCharFormat &format, int maxLineCount)
+{
+    QString text = textIn;
+    text.remove(QLatin1Char('\r'));
+    if (document()->blockCount() > maxLineCount)
+        return;
+    const bool atBottom = isScrollbarAtBottom();
+    QTextCursor cursor = QTextCursor(document());
+    cursor.movePosition(QTextCursor::End);
+    cursor.beginEditBlock();
+    cursor.insertText(doNewlineEnfocement(text), format);
+
+    if (document()->blockCount() > maxLineCount) {
+        QTextCharFormat tmp;
+        tmp.setFontWeight(QFont::Bold);
+        cursor.insertText(tr("Additional output omitted\n"), tmp);
+    }
+
+    cursor.endEditBlock();
+    if (atBottom)
+        scrollToBottom();
+}
+
+bool OutputWindow::isScrollbarAtBottom() const
+{
+    return verticalScrollBar()->value() == verticalScrollBar()->maximum();
+}
+
+void OutputWindow::clear()
+{
+    m_enforceNewline = false;
+    QPlainTextEdit::clear();
+}
+
+void OutputWindow::scrollToBottom()
+{
+    verticalScrollBar()->setValue(verticalScrollBar()->maximum());
+}
+
+void OutputWindow::grayOutOldContent()
+{
+    QTextCursor cursor = textCursor();
+    cursor.movePosition(QTextCursor::End);
+    QTextCharFormat endFormat = cursor.charFormat();
+
+    cursor.select(QTextCursor::Document);
+
+    QTextCharFormat format;
+    const QColor bkgColor = palette().base().color();
+    const QColor fgdColor = palette().text().color();
+    double bkgFactor = 0.50;
+    double fgdFactor = 1.-bkgFactor;
+    format.setForeground(QColor((bkgFactor * bkgColor.red() + fgdFactor * fgdColor.red()),
+                             (bkgFactor * bkgColor.green() + fgdFactor * fgdColor.green()),
+                             (bkgFactor * bkgColor.blue() + fgdFactor * fgdColor.blue()) ));
+    cursor.mergeCharFormat(format);
+
+    cursor.movePosition(QTextCursor::End);
+    cursor.setCharFormat(endFormat);
+    cursor.insertBlock(QTextBlockFormat());
+}
+
+void OutputWindow::enableUndoRedo()
+{
+    setMaximumBlockCount(0);
+    setUndoRedoEnabled(true);
+}
+
+void OutputWindow::setWordWrapEnabled(bool wrap)
+{
+    if (wrap)
+        setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+    else
+        setWordWrapMode(QTextOption::NoWrap);
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h
new file mode 100644 (file)
index 0000000..37bde29
--- /dev/null
@@ -0,0 +1,99 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#ifndef OUTPUTWINDOW_H
+#define OUTPUTWINDOW_H
+
+#include <utils/outputformatter.h>
+#include <coreplugin/icontext.h>
+
+#include <QtGui/QPlainTextEdit>
+
+namespace Core {
+    class IContext;
+}
+
+namespace ProjectExplorer {
+
+namespace Internal {
+
+class OutputWindow : public QPlainTextEdit
+{
+    Q_OBJECT
+
+public:
+    OutputWindow(Core::Context context, QWidget *parent = 0);
+    ~OutputWindow();
+
+    Utils::OutputFormatter* formatter() const;
+    void setFormatter(Utils::OutputFormatter *formatter);
+
+    void appendMessage(const QString &out, Utils::OutputFormat format);
+    /// appends a \p text using \p format without using formater
+    void appendText(const QString &text, const QTextCharFormat &format, int maxLineCount);
+
+    void grayOutOldContent();
+    void clear();
+
+    void showEvent(QShowEvent *);
+
+    void scrollToBottom();
+
+public slots:
+    void setWordWrapEnabled(bool wrap);
+
+protected:
+    bool isScrollbarAtBottom() const;
+
+    virtual void mousePressEvent(QMouseEvent *e);
+    virtual void mouseReleaseEvent(QMouseEvent *e);
+    virtual void mouseMoveEvent(QMouseEvent *e);
+    virtual void resizeEvent(QResizeEvent *e);
+    virtual void keyPressEvent(QKeyEvent *ev);
+
+private:
+    void enableUndoRedo();
+    QString doNewlineEnfocement(const QString &out);
+
+    Core::IContext *m_outputWindowContext;
+    Utils::OutputFormatter *m_formatter;
+
+    bool m_enforceNewline;
+    bool m_scrollToBottom;
+    bool m_linksActive;
+    bool m_mousePressed;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // OUTPUTWINDOW_H
diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp
new file mode 100644 (file)
index 0000000..1b7b9aa
--- /dev/null
@@ -0,0 +1,483 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** No Commercial Usage
+**
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#include "appoutputpane.h"
+#include "outputwindow.h"
+#include "projectexplorerconstants.h"
+#include "projectexplorer.h"
+#include "projectexplorersettings.h"
+#include "runconfiguration.h"
+#include "session.h"
+
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/icontext.h>
+#include <find/basetextfind.h>
+#include <aggregation/aggregate.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorsettings.h>
+
+#include <qt4projectmanager/qt4projectmanagerconstants.h>
+#include <utils/qtcassert.h>
+#include <utils/outputformatter.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QTabWidget>
+#include <QtGui/QToolButton>
+
+#include <QtCore/QDebug>
+
+enum { debug = 0 };
+
+using namespace ProjectExplorer;
+using namespace ProjectExplorer::Internal;
+
+AppOutputPane::RunControlTab::RunControlTab(RunControl *rc, OutputWindow *w) :
+    runControl(rc), window(w), asyncClosing(false)
+{
+}
+
+AppOutputPane::AppOutputPane() :
+    m_mainWidget(new QWidget),
+    m_tabWidget(new QTabWidget),
+    m_stopAction(new QAction(QIcon(QLatin1String(Constants::ICON_STOP)), tr("Stop"), this)),
+    m_reRunButton(new QToolButton),
+    m_stopButton(new QToolButton)
+{
+    // Rerun
+    m_reRunButton->setIcon(QIcon(ProjectExplorer::Constants::ICON_RUN_SMALL));
+    m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
+    m_reRunButton->setAutoRaise(true);
+    m_reRunButton->setEnabled(false);
+    connect(m_reRunButton, SIGNAL(clicked()),
+            this, SLOT(reRunRunControl()));
+
+    // Stop
+    Core::ActionManager *am = Core::ICore::instance()->actionManager();
+    Core::Context globalcontext(Core::Constants::C_GLOBAL);
+
+    m_stopAction->setToolTip(tr("Stop"));
+    m_stopAction->setEnabled(false);
+
+    Core::Command *cmd = am->registerAction(m_stopAction, Constants::STOP, globalcontext);
+
+    m_stopButton->setDefaultAction(cmd->action());
+    m_stopButton->setAutoRaise(true);
+
+    connect(m_stopAction, SIGNAL(triggered()),
+            this, SLOT(stopRunControl()));
+
+    // Spacer (?)
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->setMargin(0);
+    m_tabWidget->setDocumentMode(true);
+    m_tabWidget->setTabsClosable(true);
+    m_tabWidget->setMovable(true);
+    connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
+    layout->addWidget(m_tabWidget);
+
+    connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
+
+    m_mainWidget->setLayout(layout);
+
+    connect(ProjectExplorerPlugin::instance()->session(), SIGNAL(aboutToUnloadSession()),
+            this, SLOT(aboutToUnloadSession()));
+    connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
+            this, SLOT(updateWordWrapMode()));
+}
+
+AppOutputPane::~AppOutputPane()
+{
+    if (debug)
+        qDebug() << "OutputPane::~OutputPane: Entries left" << m_runControlTabs.size();
+
+    foreach(const RunControlTab &rt, m_runControlTabs)
+        delete rt.runControl;
+    delete m_mainWidget;
+}
+
+int AppOutputPane::currentIndex() const
+{
+    if (const QWidget *w = m_tabWidget->currentWidget())
+        return indexOf(w);
+    return -1;
+}
+
+RunControl *AppOutputPane::currentRunControl() const
+{
+    const int index = currentIndex();
+    if (index != -1)
+        return m_runControlTabs.at(index).runControl;
+    return 0;
+}
+
+int AppOutputPane::indexOf(const RunControl *rc) const
+{
+    for (int i = m_runControlTabs.size() - 1; i >= 0; i--)
+        if (m_runControlTabs.at(i).runControl == rc)
+            return i;
+    return -1;
+}
+
+int AppOutputPane::indexOf(const QWidget *outputWindow) const
+{
+    for (int i = m_runControlTabs.size() - 1; i >= 0; i--)
+        if (m_runControlTabs.at(i).window == outputWindow)
+            return i;
+    return -1;
+}
+
+int AppOutputPane::tabWidgetIndexOf(int runControlIndex) const
+{
+    if (runControlIndex >= 0 && runControlIndex < m_runControlTabs.size())
+        return m_tabWidget->indexOf(m_runControlTabs.at(runControlIndex).window);
+    return -1;
+}
+
+bool AppOutputPane::aboutToClose() const
+{
+    foreach(const RunControlTab &rt, m_runControlTabs)
+        if (rt.runControl->isRunning() && !rt.runControl->promptToStop())
+            return false;
+    return true;
+}
+
+void AppOutputPane::aboutToUnloadSession()
+{
+    closeTabs(CloseTabWithPrompt);
+}
+
+QWidget *AppOutputPane::outputWidget(QWidget *)
+{
+    return m_mainWidget;
+}
+
+QList<QWidget*> AppOutputPane::toolBarWidgets() const
+{
+    return QList<QWidget*>() << m_reRunButton << m_stopButton;
+}
+
+QString AppOutputPane::displayName() const
+{
+    return tr("Application Output");
+}
+
+int AppOutputPane::priorityInStatusBar() const
+{
+    return 60;
+}
+
+void AppOutputPane::clearContents()
+{
+    OutputWindow *currentWindow = qobject_cast<OutputWindow *>(m_tabWidget->currentWidget());
+    if (currentWindow)
+        currentWindow->clear();
+}
+
+void AppOutputPane::visibilityChanged(bool /* b */)
+{
+}
+
+bool AppOutputPane::hasFocus()
+{
+    return m_tabWidget->currentWidget() && m_tabWidget->currentWidget()->hasFocus();
+}
+
+bool AppOutputPane::canFocus()
+{
+    return m_tabWidget->currentWidget();
+}
+
+void AppOutputPane::setFocus()
+{
+    if (m_tabWidget->currentWidget())
+        m_tabWidget->currentWidget()->setFocus();
+}
+
+void AppOutputPane::createNewOutputWindow(RunControl *rc)
+{
+    connect(rc, SIGNAL(started()),
+            this, SLOT(runControlStarted()));
+    connect(rc, SIGNAL(finished()),
+            this, SLOT(runControlFinished()));
+    connect(rc, SIGNAL(appendMessage(ProjectExplorer::RunControl*,QString,Utils::OutputFormat)),
+            this, SLOT(appendMessage(ProjectExplorer::RunControl*,QString,Utils::OutputFormat)));
+
+    Utils::OutputFormatter *formatter = rc->outputFormatter();
+    formatter->setFont(TextEditor::TextEditorSettings::instance()->fontSettings().font());
+
+    // First look if we can reuse a tab
+    const int size = m_runControlTabs.size();
+    for (int i = 0; i < size; i++) {
+        RunControlTab &tab =m_runControlTabs[i];
+        if (tab.runControl->sameRunConfiguration(rc) && !tab.runControl->isRunning()) {
+            // Reuse this tab
+            delete tab.runControl;
+            tab.runControl = rc;
+            handleOldOutput(tab.window);
+            tab.window->scrollToBottom();
+            tab.window->setFormatter(formatter);
+            if (debug)
+                qDebug() << "OutputPane::createNewOutputWindow: Reusing tab" << i << " for " << rc;
+            return;
+        }
+    }
+    // Create new
+    static uint counter = 0;
+    Core::Context context(Constants::C_APP_OUTPUT, counter++);
+    OutputWindow *ow = new OutputWindow(context, m_tabWidget);
+    ow->setWindowTitle(tr("Application Output Window"));
+    // TODO the following is a hidden impossible dependency of projectexplorer on qt4projectmanager
+    ow->setWindowIcon(QIcon(QLatin1String(Qt4ProjectManager::Constants::ICON_WINDOW)));
+    ow->setFormatter(formatter);
+    ow->setWordWrapEnabled(ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput);
+    Aggregation::Aggregate *agg = new Aggregation::Aggregate;
+    agg->add(ow);
+    agg->add(new Find::BaseTextFind(ow));
+    m_runControlTabs.push_back(RunControlTab(rc, ow));
+    m_tabWidget->addTab(ow, rc->displayName());
+    if (debug)
+        qDebug() << "OutputPane::createNewOutputWindow: Adding tab for " << rc;
+}
+
+void AppOutputPane::handleOldOutput(OutputWindow *window) const
+{
+    if (ProjectExplorerPlugin::instance()->projectExplorerSettings().cleanOldAppOutput)
+        window->clear();
+    else
+        window->grayOutOldContent();
+}
+
+void AppOutputPane::updateWordWrapMode()
+{
+    const int size = m_runControlTabs.size();
+    for (int i = 0; i < size; i++) {
+        RunControlTab &tab =m_runControlTabs[i];
+        tab.window->setWordWrapEnabled(ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput);
+    }
+}
+
+void AppOutputPane::appendMessage(RunControl *rc, const QString &out, Utils::OutputFormat format)
+{
+    const int index = indexOf(rc);
+    if (index != -1)
+        m_runControlTabs.at(index).window->appendMessage(out, format);
+}
+
+void AppOutputPane::showTabFor(RunControl *rc)
+{
+    m_tabWidget->setCurrentIndex(tabWidgetIndexOf(indexOf(rc)));
+}
+
+void AppOutputPane::reRunRunControl()
+{
+    const int index = currentIndex();
+    QTC_ASSERT(index != -1 && !m_runControlTabs.at(index).runControl->isRunning(), return;)
+
+    RunControlTab &tab = m_runControlTabs[index];
+
+    handleOldOutput(tab.window);
+    tab.window->scrollToBottom();
+    tab.runControl->start();
+}
+
+void AppOutputPane::stopRunControl()
+{
+    const int index = currentIndex();
+    QTC_ASSERT(index != -1 && m_runControlTabs.at(index).runControl->isRunning(), return;)
+
+    RunControl *rc = m_runControlTabs.at(index).runControl;
+    if (rc->isRunning() && optionallyPromptToStop(rc))
+        rc->stop();
+
+    if (debug)
+        qDebug() << "OutputPane::stopRunControl " << rc;
+}
+
+bool AppOutputPane::closeTabs(CloseTabMode mode)
+{
+    bool allClosed = true;
+    for (int t = m_tabWidget->count() - 1; t >= 0; t--)
+        if (!closeTab(t, mode))
+            allClosed = false;
+    if (debug)
+        qDebug() << "OutputPane::closeTabs() returns " << allClosed;
+    return allClosed;
+}
+
+bool AppOutputPane::closeTab(int index)
+{
+    return closeTab(index, CloseTabWithPrompt);
+}
+
+bool AppOutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode)
+{
+    const int index = indexOf(m_tabWidget->widget(tabIndex));
+    QTC_ASSERT(index != -1, return true;)
+
+    RunControlTab &tab = m_runControlTabs[index];
+
+    if (debug)
+            qDebug() << "OutputPane::closeTab tab " << tabIndex << tab.runControl
+                        << tab.window << tab.asyncClosing;
+    // Prompt user to stop
+    if (tab.runControl->isRunning()) {
+        switch (closeTabMode) {
+        case CloseTabNoPrompt:
+            break;
+        case CloseTabWithPrompt:
+            if (!tab.runControl->promptToStop())
+                return false;
+            break;
+        }
+        if (tab.runControl->stop() == RunControl::AsynchronousStop) {
+            tab.asyncClosing = true;
+            return false;
+        }
+    }
+
+    m_tabWidget->removeTab(tabIndex);
+    if (tab.asyncClosing) { // We were invoked from its finished() signal.
+        tab.runControl->deleteLater();
+    } else {
+        delete tab.runControl;
+    }
+    delete tab.window;
+    m_runControlTabs.removeAt(index);
+    return true;
+}
+
+bool AppOutputPane::optionallyPromptToStop(RunControl *runControl)
+{
+    ProjectExplorerPlugin *pe = ProjectExplorerPlugin::instance();
+    ProjectExplorerSettings settings = pe->projectExplorerSettings();
+    if (!runControl->promptToStop(&settings.prompToStopRunControl))
+        return false;
+    pe->setProjectExplorerSettings(settings);
+    return true;
+}
+
+void AppOutputPane::projectRemoved()
+{
+    tabChanged(m_tabWidget->currentIndex());
+}
+
+void AppOutputPane::tabChanged(int i)
+{
+    if (i == -1) {
+        m_stopAction->setEnabled(false);
+        m_reRunButton->setEnabled(false);
+    } else {
+        const int index = indexOf(m_tabWidget->widget(i));
+        QTC_ASSERT(index != -1, return; )
+
+        RunControl *rc = m_runControlTabs.at(index).runControl;
+        m_stopAction->setEnabled(rc->isRunning());
+        m_reRunButton->setEnabled(!rc->isRunning());
+        m_reRunButton->setIcon(rc->icon());
+    }
+}
+
+void AppOutputPane::runControlStarted()
+{
+    RunControl *current = currentRunControl();
+    if (current && current == sender()) {
+        m_reRunButton->setEnabled(false);
+        m_stopAction->setEnabled(true);
+        m_reRunButton->setIcon(current->icon());
+    }
+}
+
+void AppOutputPane::runControlFinished()
+{
+    RunControl *senderRunControl = qobject_cast<RunControl *>(sender());
+    const int senderIndex = indexOf(senderRunControl);
+
+    QTC_ASSERT(senderIndex != -1, return; )
+
+    // Enable buttons for current
+    RunControl *current = currentRunControl();
+
+    if (debug)
+        qDebug() << "OutputPane::runControlFinished"  << senderRunControl << senderIndex
+                    << " current " << current << m_runControlTabs.size();
+
+    if (current && current == sender()) {
+        m_reRunButton->setEnabled(true);
+        m_stopAction->setEnabled(false);
+        m_reRunButton->setIcon(current->icon());
+    }
+    // Check for asynchronous close. Close the tab.
+    if (m_runControlTabs.at(senderIndex).asyncClosing)
+        closeTab(tabWidgetIndexOf(senderIndex), CloseTabNoPrompt);
+
+    if (!isRunning())
+        emit allRunControlsFinished();
+}
+
+bool AppOutputPane::isRunning() const
+{
+    foreach(const RunControlTab &rt, m_runControlTabs)
+        if (rt.runControl->isRunning())
+            return true;
+    return false;
+}
+
+bool AppOutputPane::canNext()
+{
+    return false;
+}
+
+bool AppOutputPane::canPrevious()
+{
+    return false;
+}
+
+void AppOutputPane::goToNext()
+{
+
+}
+
+void AppOutputPane::goToPrev()
+{
+
+}
+
+bool AppOutputPane::canNavigate()
+{
+    return false;
+}
similarity index 55%
rename from src/plugins/projectexplorer/outputwindow.h
rename to src/plugins/projectexplorer/appoutputpane.h
index 962dc8b..75e6948 100644 (file)
@@ -4,41 +4,39 @@
 **
 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
 **
-** Contact: Nokia Corporation (info@qt.nokia.com)
+** Contact: Nokia Corporation (qt-info@nokia.com)
 **
+** No Commercial Usage
+**
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
 **
 ** GNU Lesser General Public License Usage
 **
-** 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.
+** 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.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
+** rights.  These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
-** Other Usage
-**
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
 ** If you have questions regarding the use of this file, please contact
 ** Nokia at qt-info@nokia.com.
 **
 **************************************************************************/
 
-#ifndef OUTPUTWINDOW_H
-#define OUTPUTWINDOW_H
+#ifndef APPOUTPUTPANE_H
+#define APPOUTPUTPANE_H
 
-#include "outputformat.h"
-#include <coreplugin/ioutputpane.h>
-#include <utils/outputformatter.h>
+#include "outputwindow.h"
 
-#include <QtGui/QPlainTextEdit>
-#include <QtGui/QIcon>
+#include <coreplugin/ioutputpane.h>
 
 QT_BEGIN_NAMESPACE
 class QTabWidget;
@@ -46,25 +44,14 @@ class QToolButton;
 class QAction;
 QT_END_NAMESPACE
 
-namespace Core {
-    class IContext;
-}
-
 namespace ProjectExplorer {
+
 class RunControl;
 class Project;
 
-namespace Constants {
-    const char * const C_APP_OUTPUT = "Application Output";
-}
-
 namespace Internal {
 
-class OutputWindow;
-
-struct OutputPanePrivate;
-
-class OutputPane : public Core::IOutputPane
+class AppOutputPane : public Core::IOutputPane
 {
     Q_OBJECT
 
@@ -74,8 +61,8 @@ public:
         CloseTabWithPrompt
     };
 
-    OutputPane();
-    virtual ~OutputPane();
+    AppOutputPane();
+    virtual ~AppOutputPane();
 
     QWidget *outputWidget(QWidget *);
     QList<QWidget*> toolBarWidgets() const;
@@ -118,6 +105,7 @@ private slots:
     void runControlFinished();
 
     void aboutToUnloadSession();
+    void updateWordWrapMode();
 
 private:
     struct RunControlTab {
@@ -138,6 +126,7 @@ private:
     int currentIndex() const;
     RunControl *currentRunControl() const;
     int tabWidgetIndexOf(int runControlIndex) const;
+    void handleOldOutput(OutputWindow *window) const;
 
     QWidget *m_mainWidget;
     QTabWidget *m_tabWidget;
@@ -147,57 +136,7 @@ private:
     QToolButton *m_stopButton;
 };
 
-
-class OutputWindow : public QPlainTextEdit
-{
-    Q_OBJECT
-
-public:
-    OutputWindow(QWidget *parent = 0);
-    ~OutputWindow();
-
-    Utils::OutputFormatter* formatter() const;
-    void setFormatter(Utils::OutputFormatter *formatter);
-
-    void appendMessage(const QString &out, Utils::OutputFormat format);
-    /// appends a \p text using \p format without using formater
-    void appendText(const QString &text, const QTextCharFormat &format, int maxLineCount);
-
-    void grayOutOldContent();
-
-    void showEvent(QShowEvent *);
-
-    void clear();
-    void handleOldOutput();
-
-    void scrollToBottom();
-
-protected:
-    bool isScrollbarAtBottom() const;
-
-    virtual void mousePressEvent(QMouseEvent *e);
-    virtual void mouseReleaseEvent(QMouseEvent *e);
-    virtual void mouseMoveEvent(QMouseEvent *e);
-    virtual void resizeEvent(QResizeEvent *e);
-    virtual void keyPressEvent(QKeyEvent *ev);
-
-private slots:
-    void updateWordWrapMode();
-
-private:
-    void enableUndoRedo();
-    QString doNewlineEnfocement(const QString &out);
-
-    Core::IContext *m_outputWindowContext;
-    Utils::OutputFormatter *m_formatter;
-
-    bool m_enforceNewline;
-    bool m_scrollToBottom;
-    bool m_linksActive;
-    bool m_mousePressed;
-};
-
 } // namespace Internal
 } // namespace ProjectExplorer
 
-#endif // OUTPUTWINDOW_H
+#endif // APPOUTPUTPANE_H
index ecfecc5..21c6c83 100644 (file)
 #include "buildmanager.h"
 #include "showoutputtaskhandler.h"
 #include "task.h"
+#include "projectexplorerconstants.h"
+#include "projectexplorer.h"
+#include "projectexplorersettings.h"
 
+#include <coreplugin/icontext.h>
 #include <find/basetextfind.h>
 #include <aggregation/aggregate.h>
 #include <extensionsystem/pluginmanager.h>
@@ -58,7 +62,8 @@ const int MAX_LINECOUNT = 50000;
 
 CompileOutputWindow::CompileOutputWindow(BuildManager * /*bm*/)
 {
-    m_outputWindow = new OutputWindow();
+    Core::Context context(Constants::C_COMPILE_OUTPUT);
+    m_outputWindow = new OutputWindow(context);
     m_outputWindow->setWindowTitle(tr("Compile Output"));
     m_outputWindow->setWindowIcon(QIcon(QLatin1String(Qt4ProjectManager::Constants::ICON_WINDOW)));
     m_outputWindow->setReadOnly(true);
@@ -72,6 +77,9 @@ CompileOutputWindow::CompileOutputWindow(BuildManager * /*bm*/)
 
     m_handler = new ShowOutputTaskHandler(this);
     ExtensionSystem::PluginManager::instance()->addObject(m_handler);
+    connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
+            this, SLOT(updateWordWrapMode()));
+    updateWordWrapMode();
 }
 
 CompileOutputWindow::~CompileOutputWindow()
@@ -80,6 +88,11 @@ CompileOutputWindow::~CompileOutputWindow()
     delete m_handler;
 }
 
+void CompileOutputWindow::updateWordWrapMode()
+{
+    m_outputWindow->setWordWrapEnabled(ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput);
+}
+
 bool CompileOutputWindow::hasFocus()
 {
     return m_outputWindow->hasFocus();
index 96d99fb..86a812d 100644 (file)
@@ -82,6 +82,9 @@ public:
     bool knowsPositionOf(const Task &task);
     void showPositionOf(const Task &task);
 
+private slots:
+    void updateWordWrapMode();
+
 private:
     OutputWindow *m_outputWindow;
     QHash<unsigned int, int> m_taskPositions;
index 66a4300..5c60eb6 100644 (file)
@@ -33,8 +33,8 @@
 #include "localapplicationruncontrol.h"
 #include "applicationrunconfiguration.h"
 #include "projectexplorerconstants.h"
-#include "outputformat.h"
 
+#include <utils/outputformat.h>
 #include <utils/qtcassert.h>
 #include <utils/environment.h>
 
diff --git a/src/plugins/projectexplorer/outputwindow.cpp b/src/plugins/projectexplorer/outputwindow.cpp
deleted file mode 100644 (file)
index 8c8d473..0000000
+++ /dev/null
@@ -1,773 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (info@qt.nokia.com)
-**
-**
-** GNU Lesser General Public License Usage
-**
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** Other Usage
-**
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**************************************************************************/
-
-#include "outputwindow.h"
-#include "projectexplorerconstants.h"
-#include "projectexplorer.h"
-#include "projectexplorersettings.h"
-#include "runconfiguration.h"
-#include "session.h"
-
-#include <coreplugin/actionmanager/actionmanager.h>
-#include <coreplugin/actionmanager/actioncontainer.h>
-#include <coreplugin/actionmanager/command.h>
-#include <coreplugin/coreconstants.h>
-#include <coreplugin/icore.h>
-#include <coreplugin/uniqueidmanager.h>
-#include <coreplugin/icontext.h>
-#include <find/basetextfind.h>
-#include <aggregation/aggregate.h>
-
-#include <texteditor/basetexteditor.h>
-#include <texteditor/fontsettings.h>
-#include <texteditor/texteditorsettings.h>
-
-#include <projectexplorer/project.h>
-#include <qt4projectmanager/qt4projectmanagerconstants.h>
-#include <utils/qtcassert.h>
-#include <utils/outputformatter.h>
-
-#include <QtGui/QIcon>
-#include <QtGui/QScrollBar>
-#include <QtGui/QTextLayout>
-#include <QtGui/QTextBlock>
-#include <QtGui/QPainter>
-#include <QtGui/QApplication>
-#include <QtGui/QClipboard>
-#include <QtGui/QMenu>
-#include <QtGui/QMessageBox>
-#include <QtGui/QVBoxLayout>
-#include <QtGui/QTabWidget>
-#include <QtGui/QToolButton>
-#include <QtGui/QShowEvent>
-
-#include <QtCore/QDebug>
-
-static const int MaxBlockCount = 100000;
-
-enum { debug = 0 };
-
-using namespace Utils;
-
-namespace ProjectExplorer {
-namespace Internal {
-
-OutputPane::RunControlTab::RunControlTab(RunControl *rc, OutputWindow *w) :
-    runControl(rc), window(w), asyncClosing(false)
-{
-}
-
-OutputPane::OutputPane() :
-    m_mainWidget(new QWidget),
-    m_tabWidget(new QTabWidget),
-    m_stopAction(new QAction(QIcon(QLatin1String(Constants::ICON_STOP)), tr("Stop"), this)),
-    m_reRunButton(new QToolButton),
-    m_stopButton(new QToolButton)
-{
-    // Rerun
-    m_reRunButton->setIcon(QIcon(ProjectExplorer::Constants::ICON_RUN_SMALL));
-    m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
-    m_reRunButton->setAutoRaise(true);
-    m_reRunButton->setEnabled(false);
-    connect(m_reRunButton, SIGNAL(clicked()),
-            this, SLOT(reRunRunControl()));
-
-    // Stop
-    Core::ActionManager *am = Core::ICore::instance()->actionManager();
-    Core::Context globalcontext(Core::Constants::C_GLOBAL);
-
-    m_stopAction->setToolTip(tr("Stop"));
-    m_stopAction->setEnabled(false);
-
-    Core::Command *cmd = am->registerAction(m_stopAction, Constants::STOP, globalcontext);
-
-    m_stopButton->setDefaultAction(cmd->action());
-    m_stopButton->setAutoRaise(true);
-
-    connect(m_stopAction, SIGNAL(triggered()),
-            this, SLOT(stopRunControl()));
-
-    // Spacer (?)
-
-    QVBoxLayout *layout = new QVBoxLayout;
-    layout->setMargin(0);
-    m_tabWidget->setDocumentMode(true);
-    m_tabWidget->setTabsClosable(true);
-    m_tabWidget->setMovable(true);
-    connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
-    layout->addWidget(m_tabWidget);
-
-    connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
-
-    m_mainWidget->setLayout(layout);
-
-    connect(ProjectExplorer::ProjectExplorerPlugin::instance()->session(), SIGNAL(aboutToUnloadSession()),
-            this, SLOT(aboutToUnloadSession()));
-}
-
-OutputPane::~OutputPane()
-{
-    if (debug)
-        qDebug() << "OutputPane::~OutputPane: Entries left" << m_runControlTabs.size();
-
-    foreach(const RunControlTab &rt, m_runControlTabs)
-        delete rt.runControl;
-    delete m_mainWidget;
-}
-
-int OutputPane::currentIndex() const
-{
-    if (const QWidget *w = m_tabWidget->currentWidget())
-        return indexOf(w);
-    return -1;
-}
-
-RunControl *OutputPane::currentRunControl() const
-{
-    const int index = currentIndex();
-    if (index != -1)
-        return m_runControlTabs.at(index).runControl;
-    return 0;
-}
-
-int OutputPane::indexOf(const RunControl *rc) const
-{
-    for (int i = m_runControlTabs.size() - 1; i >= 0; i--)
-        if (m_runControlTabs.at(i).runControl == rc)
-            return i;
-    return -1;
-}
-
-int OutputPane::indexOf(const QWidget *outputWindow) const
-{
-    for (int i = m_runControlTabs.size() - 1; i >= 0; i--)
-        if (m_runControlTabs.at(i).window == outputWindow)
-            return i;
-    return -1;
-}
-
-int OutputPane::tabWidgetIndexOf(int runControlIndex) const
-{
-    if (runControlIndex >= 0 && runControlIndex < m_runControlTabs.size())
-        return m_tabWidget->indexOf(m_runControlTabs.at(runControlIndex).window);
-    return -1;
-}
-
-bool OutputPane::aboutToClose() const
-{
-    foreach(const RunControlTab &rt, m_runControlTabs)
-        if (rt.runControl->isRunning() && !rt.runControl->promptToStop())
-            return false;
-    return true;
-}
-
-void OutputPane::aboutToUnloadSession()
-{
-    closeTabs(CloseTabWithPrompt);
-}
-
-QWidget *OutputPane::outputWidget(QWidget *)
-{
-    return m_mainWidget;
-}
-
-QList<QWidget*> OutputPane::toolBarWidgets() const
-{
-    return QList<QWidget*>() << m_reRunButton << m_stopButton;
-}
-
-QString OutputPane::displayName() const
-{
-    return tr("Application Output");
-}
-
-int OutputPane::priorityInStatusBar() const
-{
-    return 60;
-}
-
-void OutputPane::clearContents()
-{
-    OutputWindow *currentWindow = qobject_cast<OutputWindow *>(m_tabWidget->currentWidget());
-    if (currentWindow)
-        currentWindow->clear();
-}
-
-void OutputPane::visibilityChanged(bool /* b */)
-{
-}
-
-bool OutputPane::hasFocus()
-{
-    return m_tabWidget->currentWidget() && m_tabWidget->currentWidget()->hasFocus();
-}
-
-bool OutputPane::canFocus()
-{
-    return m_tabWidget->currentWidget();
-}
-
-void OutputPane::setFocus()
-{
-    if (m_tabWidget->currentWidget())
-        m_tabWidget->currentWidget()->setFocus();
-}
-
-void OutputPane::createNewOutputWindow(RunControl *rc)
-{
-    connect(rc, SIGNAL(started()),
-            this, SLOT(runControlStarted()));
-    connect(rc, SIGNAL(finished()),
-            this, SLOT(runControlFinished()));
-    connect(rc, SIGNAL(appendMessage(ProjectExplorer::RunControl*,QString,Utils::OutputFormat)),
-            this, SLOT(appendMessage(ProjectExplorer::RunControl*,QString,Utils::OutputFormat)));
-
-    // First look if we can reuse a tab
-    const int size = m_runControlTabs.size();
-    for (int i = 0; i < size; i++) {
-        RunControlTab &tab =m_runControlTabs[i];
-        if (tab.runControl->sameRunConfiguration(rc) && !tab.runControl->isRunning()) {
-            // Reuse this tab
-            delete tab.runControl;
-            tab.runControl = rc;
-            tab.window->handleOldOutput();
-            tab.window->scrollToBottom();
-            tab.window->setFormatter(rc->outputFormatter());
-            if (debug)
-                qDebug() << "OutputPane::createNewOutputWindow: Reusing tab" << i << " for " << rc;
-            return;
-        }
-    }
-    // Create new
-    OutputWindow *ow = new OutputWindow(m_tabWidget);
-    ow->setWindowTitle(tr("Application Output Window"));
-    ow->setWindowIcon(QIcon(QLatin1String(Qt4ProjectManager::Constants::ICON_WINDOW)));
-    ow->setFormatter(rc->outputFormatter());
-    Aggregation::Aggregate *agg = new Aggregation::Aggregate;
-    agg->add(ow);
-    agg->add(new Find::BaseTextFind(ow));
-    m_runControlTabs.push_back(RunControlTab(rc, ow));
-    m_tabWidget->addTab(ow, rc->displayName());
-    if (debug)
-        qDebug() << "OutputPane::createNewOutputWindow: Adding tab for " << rc;
-}
-
-void OutputPane::appendMessage(RunControl *rc, const QString &out, OutputFormat format)
-{
-    const int index = indexOf(rc);
-    if (index != -1)
-        m_runControlTabs.at(index).window->appendMessage(out, format);
-}
-
-void OutputPane::showTabFor(RunControl *rc)
-{
-    m_tabWidget->setCurrentIndex(tabWidgetIndexOf(indexOf(rc)));
-}
-
-void OutputPane::reRunRunControl()
-{
-    const int index = currentIndex();
-    QTC_ASSERT(index != -1 && !m_runControlTabs.at(index).runControl->isRunning(), return;)
-
-    RunControlTab &tab = m_runControlTabs[index];
-
-    tab.window->handleOldOutput();
-    tab.window->scrollToBottom();
-    tab.runControl->start();
-}
-
-void OutputPane::stopRunControl()
-{
-    const int index = currentIndex();
-    QTC_ASSERT(index != -1 && m_runControlTabs.at(index).runControl->isRunning(), return;)
-
-    RunControl *rc = m_runControlTabs.at(index).runControl;
-    if (rc->isRunning() && optionallyPromptToStop(rc))
-        rc->stop();
-
-    if (debug)
-        qDebug() << "OutputPane::stopRunControl " << rc;
-}
-
-bool OutputPane::closeTabs(CloseTabMode mode)
-{
-    bool allClosed = true;
-    for (int t = m_tabWidget->count() - 1; t >= 0; t--)
-        if (!closeTab(t, mode))
-            allClosed = false;
-    if (debug)
-        qDebug() << "OutputPane::closeTabs() returns " << allClosed;
-    return allClosed;
-}
-
-bool OutputPane::closeTab(int index)
-{
-    return closeTab(index, CloseTabWithPrompt);
-}
-
-bool OutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode)
-{
-    const int index = indexOf(m_tabWidget->widget(tabIndex));
-    QTC_ASSERT(index != -1, return true;)
-
-    RunControlTab &tab = m_runControlTabs[index];
-
-    if (debug)
-            qDebug() << "OutputPane::closeTab tab " << tabIndex << tab.runControl
-                        << tab.window << tab.asyncClosing;
-    // Prompt user to stop
-    if (tab.runControl->isRunning()) {
-        switch (closeTabMode) {
-        case CloseTabNoPrompt:
-            break;
-        case CloseTabWithPrompt:
-            if (!tab.runControl->promptToStop())
-                return false;
-            break;
-        }
-        if (tab.runControl->stop() == RunControl::AsynchronousStop) {
-            tab.asyncClosing = true;
-            return false;
-        }
-    }
-
-    m_tabWidget->removeTab(tabIndex);
-    if (tab.asyncClosing) { // We were invoked from its finished() signal.
-        tab.runControl->deleteLater();
-    } else {
-        delete tab.runControl;
-    }
-    delete tab.window;
-    m_runControlTabs.removeAt(index);
-    return true;
-}
-
-bool OutputPane::optionallyPromptToStop(RunControl *runControl)
-{
-    ProjectExplorerPlugin *pe = ProjectExplorerPlugin::instance();
-    ProjectExplorerSettings settings = pe->projectExplorerSettings();
-    if (!runControl->promptToStop(&settings.prompToStopRunControl))
-        return false;
-    pe->setProjectExplorerSettings(settings);
-    return true;
-}
-
-void OutputPane::projectRemoved()
-{
-    tabChanged(m_tabWidget->currentIndex());
-}
-
-void OutputPane::tabChanged(int i)
-{
-    if (i == -1) {
-        m_stopAction->setEnabled(false);
-        m_reRunButton->setEnabled(false);
-    } else {
-        const int index = indexOf(m_tabWidget->widget(i));
-        QTC_ASSERT(index != -1, return; )
-
-        RunControl *rc = m_runControlTabs.at(index).runControl;
-        m_stopAction->setEnabled(rc->isRunning());
-        m_reRunButton->setEnabled(!rc->isRunning());
-        m_reRunButton->setIcon(rc->icon());
-    }
-}
-
-void OutputPane::runControlStarted()
-{
-    RunControl *current = currentRunControl();
-    if (current && current == sender()) {
-        m_reRunButton->setEnabled(false);
-        m_stopAction->setEnabled(true);
-        m_reRunButton->setIcon(current->icon());
-    }
-}
-
-void OutputPane::runControlFinished()
-{
-    RunControl *senderRunControl = qobject_cast<RunControl *>(sender());
-    const int senderIndex = indexOf(senderRunControl);
-
-    QTC_ASSERT(senderIndex != -1, return; )
-
-    // Enable buttons for current
-    RunControl *current = currentRunControl();
-
-    if (debug)
-        qDebug() << "OutputPane::runControlFinished"  << senderRunControl << senderIndex
-                    << " current " << current << m_runControlTabs.size();
-
-    if (current && current == sender()) {
-        m_reRunButton->setEnabled(true);
-        m_stopAction->setEnabled(false);
-        m_reRunButton->setIcon(current->icon());
-    }
-    // Check for asynchronous close. Close the tab.
-    if (m_runControlTabs.at(senderIndex).asyncClosing)
-        closeTab(tabWidgetIndexOf(senderIndex), CloseTabNoPrompt);
-
-    if (!isRunning())
-        emit allRunControlsFinished();
-}
-
-bool OutputPane::isRunning() const
-{
-    foreach(const RunControlTab &rt, m_runControlTabs)
-        if (rt.runControl->isRunning())
-            return true;
-    return false;
-}
-
-bool OutputPane::canNext()
-{
-    return false;
-}
-
-bool OutputPane::canPrevious()
-{
-    return false;
-}
-
-void OutputPane::goToNext()
-{
-
-}
-
-void OutputPane::goToPrev()
-{
-
-}
-
-bool OutputPane::canNavigate()
-{
-    return false;
-}
-
-/*******************/
-
-OutputWindow::OutputWindow(QWidget *parent)
-    : QPlainTextEdit(parent)
-    , m_formatter(0)
-    , m_enforceNewline(false)
-    , m_scrollToBottom(false)
-    , m_linksActive(true)
-    , m_mousePressed(false)
-{
-    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
-    //setCenterOnScroll(false);
-    setFrameShape(QFrame::NoFrame);
-    setMouseTracking(true);
-    if (!ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput)
-        setWordWrapMode(QTextOption::NoWrap);
-
-    static uint usedIds = 0;
-    Core::Context context(Constants::C_APP_OUTPUT, usedIds++);
-    Core::ICore *core = Core::ICore::instance();
-
-    m_outputWindowContext = new Core::IContext;
-    m_outputWindowContext->setContext(context);
-    m_outputWindowContext->setWidget(this);
-    core->addContextObject(m_outputWindowContext);
-
-    QAction *undoAction = new QAction(this);
-    QAction *redoAction = new QAction(this);
-    QAction *cutAction = new QAction(this);
-    QAction *copyAction = new QAction(this);
-    QAction *pasteAction = new QAction(this);
-    QAction *selectAllAction = new QAction(this);
-
-    Core::ActionManager *am = core->actionManager();
-    am->registerAction(undoAction, Core::Constants::UNDO, context);
-    am->registerAction(redoAction, Core::Constants::REDO, context);
-    am->registerAction(cutAction, Core::Constants::CUT, context);
-    am->registerAction(copyAction, Core::Constants::COPY, context);
-    am->registerAction(pasteAction, Core::Constants::PASTE, context);
-    am->registerAction(selectAllAction, Core::Constants::SELECTALL, context);
-
-    connect(undoAction, SIGNAL(triggered()), this, SLOT(undo()));
-    connect(redoAction, SIGNAL(triggered()), this, SLOT(redo()));
-    connect(cutAction, SIGNAL(triggered()), this, SLOT(cut()));
-    connect(copyAction, SIGNAL(triggered()), this, SLOT(copy()));
-    connect(pasteAction, SIGNAL(triggered()), this, SLOT(paste()));
-    connect(selectAllAction, SIGNAL(triggered()), this, SLOT(selectAll()));
-
-    connect(this, SIGNAL(undoAvailable(bool)), undoAction, SLOT(setEnabled(bool)));
-    connect(this, SIGNAL(redoAvailable(bool)), redoAction, SLOT(setEnabled(bool)));
-    connect(this, SIGNAL(copyAvailable(bool)), cutAction, SLOT(setEnabled(bool)));  // OutputWindow never read-only
-    connect(this, SIGNAL(copyAvailable(bool)), copyAction, SLOT(setEnabled(bool)));
-
-    undoAction->setEnabled(false);
-    redoAction->setEnabled(false);
-    cutAction->setEnabled(false);
-    copyAction->setEnabled(false);
-
-    connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
-            this, SLOT(updateWordWrapMode()));
-}
-
-OutputWindow::~OutputWindow()
-{
-    Core::ICore::instance()->removeContextObject(m_outputWindowContext);
-    delete m_outputWindowContext;
-}
-
-void OutputWindow::mousePressEvent(QMouseEvent * e)
-{
-    m_mousePressed = true;
-    QPlainTextEdit::mousePressEvent(e);
-}
-
-void OutputWindow::mouseReleaseEvent(QMouseEvent *e)
-{
-    m_mousePressed = false;
-
-    if (m_linksActive) {
-        const QString href = anchorAt(e->pos());
-        if (m_formatter)
-            m_formatter->handleLink(href);
-    }
-
-    // Mouse was released, activate links again
-    m_linksActive = true;
-
-    QPlainTextEdit::mouseReleaseEvent(e);
-}
-
-void OutputWindow::mouseMoveEvent(QMouseEvent *e)
-{
-    // Cursor was dragged to make a selection, deactivate links
-    if (m_mousePressed && textCursor().hasSelection())
-        m_linksActive = false;
-
-    if (!m_linksActive || anchorAt(e->pos()).isEmpty())
-        viewport()->setCursor(Qt::IBeamCursor);
-    else
-        viewport()->setCursor(Qt::PointingHandCursor);
-    QPlainTextEdit::mouseMoveEvent(e);
-}
-
-void OutputWindow::resizeEvent(QResizeEvent *e)
-{
-    //Keep scrollbar at bottom of window while resizing, to ensure we keep scrolling
-    //This can happen if window is resized while building, or if the horizontal scrollbar appears
-    bool atBottom = isScrollbarAtBottom();
-    QPlainTextEdit::resizeEvent(e);
-    if (atBottom)
-        scrollToBottom();
-}
-
-void OutputWindow::keyPressEvent(QKeyEvent *ev)
-{
-    QPlainTextEdit::keyPressEvent(ev);
-
-    //Ensure we scroll also on Ctrl+Home or Ctrl+End
-    if (ev->matches(QKeySequence::MoveToStartOfDocument))
-        verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMinimum);
-    else if (ev->matches(QKeySequence::MoveToEndOfDocument))
-        verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
-}
-
-OutputFormatter *OutputWindow::formatter() const
-{
-    return m_formatter;
-}
-
-void OutputWindow::setFormatter(OutputFormatter *formatter)
-{
-    m_formatter = formatter;
-    m_formatter->setFont(TextEditor::TextEditorSettings::instance()->fontSettings().font());
-    m_formatter->setPlainTextEdit(this);
-}
-
-void OutputWindow::showEvent(QShowEvent *e)
-{
-    QPlainTextEdit::showEvent(e);
-    if (m_scrollToBottom) {
-        verticalScrollBar()->setValue(verticalScrollBar()->maximum());
-    }
-    m_scrollToBottom = false;
-}
-
-QString OutputWindow::doNewlineEnfocement(const QString &out)
-{
-    m_scrollToBottom = true;
-    QString s = out;
-    if (m_enforceNewline) {
-        s.prepend(QLatin1Char('\n'));
-        m_enforceNewline = false;
-    }
-
-    if (s.endsWith(QLatin1Char('\n'))) {
-        m_enforceNewline = true; // make appendOutputInline put in a newline next time
-        s.chop(1);
-    }
-
-    return s;
-}
-
-void OutputWindow::appendMessage(const QString &output, OutputFormat format)
-{
-    QString out = output;
-    out.remove(QLatin1Char('\r'));
-    setMaximumBlockCount(MaxBlockCount);
-    const bool atBottom = isScrollbarAtBottom();
-
-    if (format == ErrorMessageFormat || format == NormalMessageFormat) {
-
-        m_formatter->appendMessage(doNewlineEnfocement(out), format);
-
-    } else {
-
-        bool sameLine = format == StdOutFormatSameLine
-                     || format == StdErrFormatSameLine;
-
-        if (sameLine) {
-            m_scrollToBottom = true;
-
-            int newline = -1;
-            bool enforceNewline = m_enforceNewline;
-            m_enforceNewline = false;
-
-            if (!enforceNewline) {
-                newline = out.indexOf(QLatin1Char('\n'));
-                moveCursor(QTextCursor::End);
-                if (newline != -1)
-                    m_formatter->appendMessage(out.left(newline), format);// doesn't enforce new paragraph like appendPlainText
-            }
-
-            QString s = out.mid(newline+1);
-            if (s.isEmpty()) {
-                m_enforceNewline = true;
-            } else {
-                if (s.endsWith(QLatin1Char('\n'))) {
-                    m_enforceNewline = true;
-                    s.chop(1);
-                }
-                m_formatter->appendMessage(QLatin1Char('\n') + s, format);
-            }
-        } else {
-            m_formatter->appendMessage(doNewlineEnfocement(out), format);
-        }
-    }
-
-    if (atBottom)
-        scrollToBottom();
-    enableUndoRedo();
-}
-
-// TODO rename
-void OutputWindow::appendText(const QString &textIn, const QTextCharFormat &format, int maxLineCount)
-{
-    QString text = textIn;
-    text.remove(QLatin1Char('\r'));
-    if (document()->blockCount() > maxLineCount)
-        return;
-    const bool atBottom = isScrollbarAtBottom();
-    QTextCursor cursor = QTextCursor(document());
-    cursor.movePosition(QTextCursor::End);
-    cursor.beginEditBlock();
-    cursor.insertText(doNewlineEnfocement(text), format);
-
-    if (document()->blockCount() > maxLineCount) {
-        QTextCharFormat tmp;
-        tmp.setFontWeight(QFont::Bold);
-        cursor.insertText(tr("Additional output omitted\n"), tmp);
-    }
-
-    cursor.endEditBlock();
-    if (atBottom)
-        scrollToBottom();
-}
-
-bool OutputWindow::isScrollbarAtBottom() const
-{
-    return verticalScrollBar()->value() == verticalScrollBar()->maximum();
-}
-
-void OutputWindow::clear()
-{
-    m_enforceNewline = false;
-    QPlainTextEdit::clear();
-}
-
-void OutputWindow::handleOldOutput()
-{
-    if (ProjectExplorerPlugin::instance()->projectExplorerSettings().cleanOldAppOutput)
-        clear();
-    else
-        grayOutOldContent();
-}
-
-void OutputWindow::scrollToBottom()
-{
-    verticalScrollBar()->setValue(verticalScrollBar()->maximum());
-}
-
-void OutputWindow::grayOutOldContent()
-{
-    QTextCursor cursor = textCursor();
-    cursor.movePosition(QTextCursor::End);
-    QTextCharFormat endFormat = cursor.charFormat();
-
-    cursor.select(QTextCursor::Document);
-
-    QTextCharFormat format;
-    const QColor bkgColor = palette().base().color();
-    const QColor fgdColor = palette().text().color();
-    double bkgFactor = 0.50;
-    double fgdFactor = 1.-bkgFactor;
-    format.setForeground(QColor((bkgFactor * bkgColor.red() + fgdFactor * fgdColor.red()),
-                             (bkgFactor * bkgColor.green() + fgdFactor * fgdColor.green()),
-                             (bkgFactor * bkgColor.blue() + fgdFactor * fgdColor.blue()) ));
-    cursor.mergeCharFormat(format);
-
-    cursor.movePosition(QTextCursor::End);
-    cursor.setCharFormat(endFormat);
-    cursor.insertBlock(QTextBlockFormat());
-}
-
-void OutputWindow::enableUndoRedo()
-{
-    setMaximumBlockCount(0);
-    setUndoRedoEnabled(true);
-}
-
-void OutputWindow::updateWordWrapMode()
-{
-    if (ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput)
-        setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
-    else
-        setWordWrapMode(QTextOption::NoWrap);
-}
-
-} // namespace Internal
-} // namespace ProjectExplorer
index 459e9a3..6d44216 100644 (file)
@@ -59,6 +59,7 @@
 #include "metatypedeclarations.h"
 #include "nodesvisitor.h"
 #include "outputwindow.h"
+#include "appoutputpane.h"
 #include "persistentsettings.h"
 #include "pluginfilefactory.h"
 #include "processstep.h"
@@ -221,7 +222,7 @@ struct ProjectExplorerPluginPrivate {
 
     QList<Internal::ProjectFileFactory*> m_fileFactories;
     QStringList m_profileMimeTypes;
-    Internal::OutputPane *m_outputPane;
+    Internal::AppOutputPane *m_outputPane;
 
     QList<QPair<QString, QString> > m_recentProjects; // pair of filename, displayname
     static const int m_maxRecentProjects = 7;
@@ -375,7 +376,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
 
     addAutoReleasedObject(new CoreListener);
 
-    d->m_outputPane = new OutputPane;
+    d->m_outputPane = new AppOutputPane;
     addAutoReleasedObject(d->m_outputPane);
     connect(d->m_session, SIGNAL(projectRemoved(ProjectExplorer::Project *)),
             d->m_outputPane, SLOT(projectRemoved()));
@@ -1085,7 +1086,7 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
     // Attempt to synchronously shutdown all run controls.
     // If that fails, fall back to asynchronous shutdown (Debugger run controls
     // might shutdown asynchronously).
-    if (d->m_outputPane->closeTabs(OutputPane::CloseTabNoPrompt /* No prompt any more */))
+    if (d->m_outputPane->closeTabs(AppOutputPane::CloseTabNoPrompt /* No prompt any more */))
         return SynchronousShutdown;
     connect(d->m_outputPane, SIGNAL(allRunControlsFinished()),
             this, SIGNAL(asynchronousShutdownFinished()));
index 524532f..488a213 100644 (file)
@@ -101,7 +101,8 @@ HEADERS += projectexplorer.h \
     publishing/publishingwizardselectiondialog.h \
     publishing/ipublishingwizardfactory.h \
     headerpath.h \
-    gcctoolchainfactories.h
+    gcctoolchainfactories.h \
+    appoutputpane.h
 
 SOURCES += projectexplorer.cpp \
     abi.cpp \
@@ -185,7 +186,8 @@ SOURCES += projectexplorer.cpp \
     localapplicationruncontrol.cpp \
     customexecutableconfigurationwidget.cpp \
     sessionnodeimpl.cpp \
-    publishing/publishingwizardselectiondialog.cpp
+    publishing/publishingwizardselectiondialog.cpp \
+    appoutputpane.cpp
 
 FORMS += processstep.ui \
     toolchainoptionspage.ui \
index 574f16a..0f0e943 100644 (file)
@@ -98,6 +98,8 @@ const int          P_ACTION_BUILDPROJECT   = 80;
 // context
 const char * const C_PROJECTEXPLORER    = "Project Explorer";
 const char * const C_PROJECT_TREE       = "ProjectExplorer.ProjectTreeContext";
+const char * const C_APP_OUTPUT         = "ProjectExplorer.ApplicationOutput";
+const char * const C_COMPILE_OUTPUT     = "ProjectExplorer.CompileOutput";
 
 // languages
 const char * const LANG_CXX             = "CXX";