1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
28 **************************************************************************/
30 #include "outputwindow.h"
31 #include "projectexplorerconstants.h"
32 #include "runconfiguration.h"
34 #include <coreplugin/actionmanager/actionmanager.h>
35 #include <coreplugin/coreconstants.h>
36 #include <coreplugin/icore.h>
37 #include <coreplugin/uniqueidmanager.h>
38 #include <find/basetextfind.h>
39 #include <aggregation/aggregate.h>
41 #include <QtGui/QIcon>
42 #include <QtGui/QScrollBar>
43 #include <QtGui/QTextLayout>
44 #include <QtGui/QPainter>
45 #include <QtGui/QApplication>
46 #include <QtGui/QClipboard>
47 #include <QtGui/QMenu>
48 #include <QtGui/QMessageBox>
49 #include <QtGui/QVBoxLayout>
50 #include <QtGui/QTabWidget>
52 #include <QtGui/QApplication>
54 using namespace ProjectExplorer::Internal;
55 using namespace ProjectExplorer;
57 static const int MaxBlockCount = 100000;
59 OutputPane::OutputPane()
60 : m_mainWidget(new QWidget)
62 // m_insertLineButton = new QToolButton;
63 // m_insertLineButton->setIcon(QIcon(ProjectExplorer::Constants::ICON_INSERT_LINE));
64 // m_insertLineButton->setText(tr("Insert line"));
65 // m_insertLineButton->setToolTip(tr("Insert line"));
66 // m_insertLineButton->setAutoRaise(true);
67 // connect(m_insertLineButton, SIGNAL(clicked()), this, SLOT(insertLine()));
69 QIcon runIcon(Constants::ICON_RUN);
70 runIcon.addFile(Constants::ICON_RUN_SMALL);
73 m_reRunButton = new QToolButton;
74 m_reRunButton->setIcon(runIcon);
75 m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
76 m_reRunButton->setAutoRaise(true);
77 m_reRunButton->setEnabled(false);
78 connect(m_reRunButton, SIGNAL(clicked()),
79 this, SLOT(reRunRunControl()));
82 Core::ActionManager *am = Core::ICore::instance()->actionManager();
83 QList<int> globalcontext;
84 globalcontext.append(Core::Constants::C_GLOBAL_ID);
86 m_stopAction = new QAction(QIcon(Constants::ICON_STOP), tr("Stop"), this);
87 m_stopAction->setToolTip(tr("Stop"));
88 m_stopAction->setEnabled(false);
90 Core::Command *cmd = am->registerAction(m_stopAction, Constants::STOP, globalcontext);
91 cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+R")));
93 m_stopButton = new QToolButton;
94 m_stopButton->setDefaultAction(cmd->action());
95 m_stopButton->setAutoRaise(true);
97 connect(m_stopAction, SIGNAL(triggered()),
98 this, SLOT(stopRunControl()));
102 QVBoxLayout *layout = new QVBoxLayout;
103 layout->setMargin(0);
104 m_tabWidget = new QTabWidget;
105 m_tabWidget->setDocumentMode(true);
106 m_tabWidget->setTabsClosable(true);
107 m_tabWidget->setMovable(true);
108 connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
109 layout->addWidget(m_tabWidget);
111 connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
113 m_mainWidget->setLayout(layout);
115 connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()),
116 this, SLOT(coreAboutToClose()));
119 void OutputPane::coreAboutToClose()
121 while (m_tabWidget->count()) {
122 RunControl *rc = runControlForTab(0);
129 OutputPane::~OutputPane()
134 QWidget *OutputPane::outputWidget(QWidget *)
139 QList<QWidget*> OutputPane::toolBarWidgets() const
141 return QList<QWidget*>() << m_reRunButton << m_stopButton
142 ; // << m_insertLineButton;
145 QString OutputPane::name() const
147 return tr("Application Output");
150 int OutputPane::priorityInStatusBar() const
155 void OutputPane::clearContents()
157 OutputWindow *currentWindow = qobject_cast<OutputWindow *>(m_tabWidget->currentWidget());
159 currentWindow->clear();
162 void OutputPane::visibilityChanged(bool /* b */)
166 bool OutputPane::hasFocus()
168 return m_tabWidget->currentWidget() && m_tabWidget->currentWidget()->hasFocus();
171 bool OutputPane::canFocus()
173 return m_tabWidget->currentWidget();
176 void OutputPane::setFocus()
178 if (m_tabWidget->currentWidget())
179 m_tabWidget->currentWidget()->setFocus();
182 void OutputPane::appendOutput(const QString &/*out*/)
184 // This function is in the interface, since we can't do anything sensible here, we don't do anything here.
187 void OutputPane::createNewOutputWindow(RunControl *rc)
189 connect(rc, SIGNAL(started()),
190 this, SLOT(runControlStarted()));
191 connect(rc, SIGNAL(finished()),
192 this, SLOT(runControlFinished()));
194 // First look if we can reuse a tab
196 for (int i = 0; i < m_tabWidget->count(); ++i) {
197 RunControl *old = runControlForTab(i);
198 if (old->sameRunConfiguration(rc) && !old->isRunning()) {
201 m_outputWindows.remove(old);
202 OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(i));
203 ow->grayOutOldContent();
204 ow->verticalScrollBar()->setValue(ow->verticalScrollBar()->maximum());
205 m_outputWindows.insert(rc, ow);
211 OutputWindow *ow = new OutputWindow(m_tabWidget);
212 Aggregation::Aggregate *agg = new Aggregation::Aggregate;
214 agg->add(new Find::BaseTextFind(ow));
215 m_outputWindows.insert(rc, ow);
216 m_tabWidget->addTab(ow, rc->displayName());
220 void OutputPane::appendOutput(RunControl *rc, const QString &out)
222 OutputWindow *ow = m_outputWindows.value(rc);
223 ow->appendOutput(out);
226 void OutputPane::appendOutputInline(RunControl *rc, const QString &out)
228 OutputWindow *ow = m_outputWindows.value(rc);
229 ow->appendOutputInline(out);
232 void OutputPane::showTabFor(RunControl *rc)
234 OutputWindow *ow = m_outputWindows.value(rc);
235 m_tabWidget->setCurrentWidget(ow);
238 void OutputPane::insertLine()
240 OutputWindow *currentWindow = qobject_cast<OutputWindow *>(m_tabWidget->currentWidget());
242 currentWindow->clear();
245 void OutputPane::reRunRunControl()
247 int index = m_tabWidget->currentIndex();
248 RunControl *rc = runControlForTab(index);
249 OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(index));
250 ow->grayOutOldContent();
251 ow->verticalScrollBar()->setValue(ow->verticalScrollBar()->maximum());
255 void OutputPane::stopRunControl()
257 RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
261 void OutputPane::closeTab(int index)
263 OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(index));
264 RunControl *rc = m_outputWindows.key(ow);
266 if (rc->isRunning()) {
267 QString msg = tr("The application is still running. Close it first.");
268 QMessageBox::critical(0, tr("Unable to close"), msg);
272 m_tabWidget->removeTab(index);
277 void OutputPane::projectRemoved()
279 tabChanged(m_tabWidget->currentIndex());
282 void OutputPane::tabChanged(int i)
285 m_stopAction->setEnabled(false);
286 m_reRunButton->setEnabled(false);
288 RunControl *rc = runControlForTab(i);
289 m_stopAction->setEnabled(rc->isRunning());
290 m_reRunButton->setEnabled(!rc->isRunning());
294 void OutputPane::runControlStarted()
296 RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
297 if (rc == qobject_cast<RunControl *>(sender())) {
298 m_reRunButton->setEnabled(false);
299 m_stopAction->setEnabled(true);
303 void OutputPane::runControlFinished()
305 RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
306 if (rc == qobject_cast<RunControl *>(sender())) {
307 m_reRunButton->setEnabled(rc);
308 m_stopAction->setEnabled(false);
312 RunControl* OutputPane::runControlForTab(int index) const
314 return m_outputWindows.key(qobject_cast<OutputWindow *>(m_tabWidget->widget(index)));
317 bool OutputPane::canNext()
322 bool OutputPane::canPrevious()
327 void OutputPane::goToNext()
332 void OutputPane::goToPrev()
337 bool OutputPane::canNavigate()
342 /*******************/
344 OutputWindow::OutputWindow(QWidget *parent)
345 : QPlainTextEdit(parent)
347 m_enforceNewline = false;
348 m_scrollToBottom = false;
350 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
351 //setCenterOnScroll(false);
352 setWindowTitle(tr("Application Output Window"));
353 setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
354 setFrameShape(QFrame::NoFrame);
356 static uint usedIds = 0;
357 Core::ICore *core = Core::ICore::instance();
359 context << core->uniqueIDManager()->uniqueIdentifier(QString(Constants::C_APP_OUTPUT) + QString().setNum(usedIds++));
360 m_outputWindowContext = new Core::BaseContext(this, context);
361 core->addContextObject(m_outputWindowContext);
363 QAction *undoAction = new QAction(this);
364 QAction *redoAction = new QAction(this);
365 QAction *cutAction = new QAction(this);
366 QAction *copyAction = new QAction(this);
367 QAction *pasteAction = new QAction(this);
368 QAction *selectAllAction = new QAction(this);
370 core->actionManager()->registerAction(undoAction, Core::Constants::UNDO, context);
371 core->actionManager()->registerAction(redoAction, Core::Constants::REDO, context);
372 core->actionManager()->registerAction(cutAction, Core::Constants::CUT, context);
373 core->actionManager()->registerAction(copyAction, Core::Constants::COPY, context);
374 core->actionManager()->registerAction(pasteAction, Core::Constants::PASTE, context);
375 core->actionManager()->registerAction(selectAllAction, Core::Constants::SELECTALL, context);
377 connect(undoAction, SIGNAL(triggered()), this, SLOT(undo()));
378 connect(redoAction, SIGNAL(triggered()), this, SLOT(redo()));
379 connect(cutAction, SIGNAL(triggered()), this, SLOT(cut()));
380 connect(copyAction, SIGNAL(triggered()), this, SLOT(copy()));
381 connect(pasteAction, SIGNAL(triggered()), this, SLOT(paste()));
382 connect(selectAllAction, SIGNAL(triggered()), this, SLOT(selectAll()));
384 connect(this, SIGNAL(undoAvailable(bool)), undoAction, SLOT(setEnabled(bool)));
385 connect(this, SIGNAL(redoAvailable(bool)), redoAction, SLOT(setEnabled(bool)));
386 connect(this, SIGNAL(copyAvailable(bool)), cutAction, SLOT(setEnabled(bool))); // OutputWindow never read-only
387 connect(this, SIGNAL(copyAvailable(bool)), copyAction, SLOT(setEnabled(bool)));
389 undoAction->setEnabled(false);
390 redoAction->setEnabled(false);
391 cutAction->setEnabled(false);
392 copyAction->setEnabled(false);
395 OutputWindow::~OutputWindow()
397 Core::ICore::instance()->removeContextObject(m_outputWindowContext);
398 delete m_outputWindowContext;
401 void OutputWindow::showEvent(QShowEvent *e)
403 QPlainTextEdit::showEvent(e);
404 if (m_scrollToBottom) {
405 verticalScrollBar()->setValue(verticalScrollBar()->maximum());
407 m_scrollToBottom = false;
410 void OutputWindow::appendOutput(const QString &out)
412 m_scrollToBottom = true;
414 m_enforceNewline = true; // make appendOutputInline put in a newline next time
415 if (s.endsWith(QLatin1Char('\n'))) {
418 setMaximumBlockCount(MaxBlockCount);
419 appendPlainText(out);
424 void OutputWindow::appendOutputInline(const QString &out)
426 m_scrollToBottom = true;
427 setMaximumBlockCount(MaxBlockCount);
430 bool enforceNewline = m_enforceNewline;
431 m_enforceNewline = false;
433 if (!enforceNewline) {
434 newline = out.indexOf(QLatin1Char('\n'));
435 moveCursor(QTextCursor::End);
436 bool atBottom = (blockBoundingRect(document()->lastBlock()).bottom() + contentOffset().y()
437 <= viewport()->rect().bottom());
438 insertPlainText(newline < 0 ? out : out.left(newline)); // doesn't enforce new paragraph like appendPlainText
440 verticalScrollBar()->setValue(verticalScrollBar()->maximum());
443 QString s = out.mid(newline+1);
445 m_enforceNewline = true;
447 if (s.endsWith(QLatin1Char('\n'))) {
448 m_enforceNewline = true;
457 void OutputWindow::insertLine()
459 m_scrollToBottom = true;
460 setMaximumBlockCount(MaxBlockCount);
461 appendPlainText(QString());
465 void OutputWindow::grayOutOldContent()
467 QTextCursor cursor = textCursor();
468 cursor.select(QTextCursor::Document);
469 QTextBlockFormat tbf;
470 const QColor bkgColor = palette().window().color();
471 const QColor fgdColor = palette().windowText().color();
472 tbf.setBackground(QColor((0.5 * bkgColor.red() + 0.5* fgdColor.red()),\
473 (0.5 * bkgColor.green() + 0.5* fgdColor.green()),\
474 (0.5 * bkgColor.blue() + 0.5* fgdColor.blue()) ));
475 cursor.mergeBlockFormat(tbf);
477 cursor.movePosition(QTextCursor::End);
478 cursor.insertBlock(QTextBlockFormat());
481 void OutputWindow::enableUndoRedo()
483 setMaximumBlockCount(0);
484 setUndoRedoEnabled(true);