OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / projectexplorer / outputwindow.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "outputwindow.h"
35 #include "projectexplorerconstants.h"
36 #include "projectexplorer.h"
37 #include "projectexplorersettings.h"
38 #include "runconfiguration.h"
39 #include "session.h"
40 #include "outputformatter.h"
41
42 #include <coreplugin/actionmanager/actionmanager.h>
43 #include <coreplugin/actionmanager/actioncontainer.h>
44 #include <coreplugin/actionmanager/command.h>
45 #include <coreplugin/coreconstants.h>
46 #include <coreplugin/icore.h>
47 #include <coreplugin/uniqueidmanager.h>
48 #include <coreplugin/icontext.h>
49 #include <find/basetextfind.h>
50 #include <aggregation/aggregate.h>
51 #include <texteditor/basetexteditor.h>
52 #include <projectexplorer/project.h>
53 #include <qt4projectmanager/qt4projectmanagerconstants.h>
54 #include <utils/qtcassert.h>
55
56 #include <QtGui/QIcon>
57 #include <QtGui/QScrollBar>
58 #include <QtGui/QTextLayout>
59 #include <QtGui/QTextBlock>
60 #include <QtGui/QPainter>
61 #include <QtGui/QApplication>
62 #include <QtGui/QClipboard>
63 #include <QtGui/QMenu>
64 #include <QtGui/QMessageBox>
65 #include <QtGui/QVBoxLayout>
66 #include <QtGui/QTabWidget>
67 #include <QtGui/QToolButton>
68 #include <QtGui/QShowEvent>
69
70 #include <QtCore/QDebug>
71
72 static const int MaxBlockCount = 100000;
73
74 enum { debug = 0 };
75
76 namespace ProjectExplorer {
77 namespace Internal {
78
79 OutputPane::RunControlTab::RunControlTab(RunControl *rc, OutputWindow *w) :
80     runControl(rc), window(w), asyncClosing(false)
81 {
82 }
83
84 OutputPane::OutputPane() :
85     m_mainWidget(new QWidget),
86     m_tabWidget(new QTabWidget),
87     m_stopAction(new QAction(QIcon(QLatin1String(Constants::ICON_STOP)), tr("Stop"), this)),
88     m_reRunButton(new QToolButton),
89     m_stopButton(new QToolButton)
90 {
91     m_runIcon.addFile(Constants::ICON_RUN);
92     m_runIcon.addFile(Constants::ICON_RUN_SMALL);
93
94     // Rerun
95     m_reRunButton->setIcon(m_runIcon);
96     m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
97     m_reRunButton->setAutoRaise(true);
98     m_reRunButton->setEnabled(false);
99     connect(m_reRunButton, SIGNAL(clicked()),
100             this, SLOT(reRunRunControl()));
101
102     // Stop
103     Core::ActionManager *am = Core::ICore::instance()->actionManager();
104     Core::Context globalcontext(Core::Constants::C_GLOBAL);
105
106     m_stopAction->setToolTip(tr("Stop"));
107     m_stopAction->setEnabled(false);
108
109     Core::Command *cmd = am->registerAction(m_stopAction, Constants::STOP, globalcontext);
110
111     m_stopButton->setDefaultAction(cmd->action());
112     m_stopButton->setAutoRaise(true);
113
114     connect(m_stopAction, SIGNAL(triggered()),
115             this, SLOT(stopRunControl()));
116
117     // Spacer (?)
118
119     QVBoxLayout *layout = new QVBoxLayout;
120     layout->setMargin(0);
121     m_tabWidget->setDocumentMode(true);
122     m_tabWidget->setTabsClosable(true);
123     m_tabWidget->setMovable(true);
124     connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
125     layout->addWidget(m_tabWidget);
126
127     connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
128
129     m_mainWidget->setLayout(layout);
130
131     connect(ProjectExplorer::ProjectExplorerPlugin::instance()->session(), SIGNAL(aboutToUnloadSession()),
132             this, SLOT(aboutToUnloadSession()));
133 }
134
135 OutputPane::~OutputPane()
136 {
137     if (debug)
138         qDebug() << "OutputPane::~OutputPane: Entries left" << m_runControlTabs.size();
139
140     foreach(const RunControlTab &rt, m_runControlTabs)
141         delete rt.runControl;
142     delete m_mainWidget;
143 }
144
145 int OutputPane::currentIndex() const
146 {
147     if (const QWidget *w = m_tabWidget->currentWidget())
148         return indexOf(w);
149     return -1;
150 }
151
152 RunControl *OutputPane::currentRunControl() const
153 {
154     const int index = currentIndex();
155     if (index != -1)
156         return m_runControlTabs.at(index).runControl;
157     return 0;
158 }
159
160 int OutputPane::indexOf(const RunControl *rc) const
161 {
162     for (int i = m_runControlTabs.size() - 1; i >= 0; i--)
163         if (m_runControlTabs.at(i).runControl == rc)
164             return i;
165     return -1;
166 }
167
168 int OutputPane::indexOf(const QWidget *outputWindow) const
169 {
170     for (int i = m_runControlTabs.size() - 1; i >= 0; i--)
171         if (m_runControlTabs.at(i).window == outputWindow)
172             return i;
173     return -1;
174 }
175
176 int OutputPane::tabWidgetIndexOf(int runControlIndex) const
177 {
178     if (runControlIndex >= 0 && runControlIndex < m_runControlTabs.size())
179         return m_tabWidget->indexOf(m_runControlTabs.at(runControlIndex).window);
180     return -1;
181 }
182
183 bool OutputPane::aboutToClose() const
184 {
185     foreach(const RunControlTab &rt, m_runControlTabs)
186         if (rt.runControl->isRunning() && !rt.runControl->aboutToStop())
187             return false;
188     return true;
189 }
190
191 void OutputPane::aboutToUnloadSession()
192 {
193     closeTabs(true);
194 }
195
196 QWidget *OutputPane::outputWidget(QWidget *)
197 {
198     return m_mainWidget;
199 }
200
201 QList<QWidget*> OutputPane::toolBarWidgets() const
202 {
203     return QList<QWidget*>() << m_reRunButton << m_stopButton;
204 }
205
206 QString OutputPane::displayName() const
207 {
208     return tr("Application Output");
209 }
210
211 int OutputPane::priorityInStatusBar() const
212 {
213     return 60;
214 }
215
216 void OutputPane::clearContents()
217 {
218     OutputWindow *currentWindow = qobject_cast<OutputWindow *>(m_tabWidget->currentWidget());
219     if (currentWindow)
220         currentWindow->clear();
221 }
222
223 void OutputPane::visibilityChanged(bool /* b */)
224 {
225 }
226
227 bool OutputPane::hasFocus()
228 {
229     return m_tabWidget->currentWidget() && m_tabWidget->currentWidget()->hasFocus();
230 }
231
232 bool OutputPane::canFocus()
233 {
234     return m_tabWidget->currentWidget();
235 }
236
237 void OutputPane::setFocus()
238 {
239     if (m_tabWidget->currentWidget())
240         m_tabWidget->currentWidget()->setFocus();
241 }
242
243 void OutputPane::createNewOutputWindow(RunControl *rc)
244 {
245     connect(rc, SIGNAL(started()),
246             this, SLOT(runControlStarted()));
247     connect(rc, SIGNAL(finished()),
248             this, SLOT(runControlFinished()));
249     connect(rc, SIGNAL(appendMessage(ProjectExplorer::RunControl*,QString,ProjectExplorer::OutputFormat)),
250             this, SLOT(appendMessage(ProjectExplorer::RunControl*,QString,ProjectExplorer::OutputFormat)));
251
252     // First look if we can reuse a tab
253     const int size = m_runControlTabs.size();
254     for (int i = 0; i < size; i++) {
255         RunControlTab &tab =m_runControlTabs[i];
256         if (tab.runControl->sameRunConfiguration(rc) && !tab.runControl->isRunning()) {
257             // Reuse this tab
258             delete tab.runControl;
259             tab.runControl = rc;
260             tab.window->handleOldOutput();
261             tab.window->scrollToBottom();
262             tab.window->setFormatter(rc->outputFormatter());
263             if (debug)
264                 qDebug() << "OutputPane::createNewOutputWindow: Reusing tab" << i << " for " << rc;
265             return;
266         }
267     }
268     // Create new
269     OutputWindow *ow = new OutputWindow(m_tabWidget);
270     ow->setWindowTitle(tr("Application Output Window"));
271     ow->setWindowIcon(QIcon(QLatin1String(Qt4ProjectManager::Constants::ICON_WINDOW)));
272     ow->setFormatter(rc->outputFormatter());
273     Aggregation::Aggregate *agg = new Aggregation::Aggregate;
274     agg->add(ow);
275     agg->add(new Find::BaseTextFind(ow));
276     m_runControlTabs.push_back(RunControlTab(rc, ow));
277     m_tabWidget->addTab(ow, rc->displayName());
278     if (debug)
279         qDebug() << "OutputPane::createNewOutputWindow: Adding tab for " << rc;
280 }
281
282 void OutputPane::appendMessage(RunControl *rc, const QString &out, OutputFormat format)
283 {
284     const int index = indexOf(rc);
285     if (index != -1)
286         m_runControlTabs.at(index).window->appendMessage(out, format);
287 }
288
289 void OutputPane::showTabFor(RunControl *rc)
290 {
291     m_tabWidget->setCurrentIndex(tabWidgetIndexOf(indexOf(rc)));
292 }
293
294 void OutputPane::reRunRunControl()
295 {
296     const int index = currentIndex();
297     QTC_ASSERT(index != -1 && !m_runControlTabs.at(index).runControl->isRunning(), return;)
298
299     RunControlTab &tab = m_runControlTabs[index];
300
301     tab.window->handleOldOutput();
302     tab.window->scrollToBottom();
303     tab.runControl->start();
304 }
305
306 void OutputPane::stopRunControl()
307 {
308     const int index = currentIndex();
309     QTC_ASSERT(index != -1 && m_runControlTabs.at(index).runControl->isRunning(), return;)
310
311     RunControl *rc = m_runControlTabs.at(index).runControl;
312     if (rc->isRunning() && rc->aboutToStop())
313         rc->stop();
314
315     if (debug)
316         qDebug() << "OutputPane::stopRunControl " << rc;
317 }
318
319 bool OutputPane::closeTabs(bool prompt)
320 {
321     bool allClosed = true;
322     for (int t = m_tabWidget->count() - 1; t >= 0; t--)
323         if (!closeTab(t, prompt))
324             allClosed = false;
325     if (debug)
326         qDebug() << "OutputPane::closeTabs() returns " << allClosed;
327     return allClosed;
328 }
329
330 bool OutputPane::closeTab(int index)
331 {
332     return closeTab(index, true);
333 }
334
335 bool OutputPane::closeTab(int tabIndex, bool prompt)
336 {
337     const int index = indexOf(m_tabWidget->widget(tabIndex));
338     QTC_ASSERT(index != -1, return true;)
339
340     RunControlTab &tab = m_runControlTabs[index];
341
342     if (debug)
343             qDebug() << "OutputPane::closeTab tab " << tabIndex << tab.runControl
344                         << tab.window << tab.asyncClosing;
345     // Prompt user to stop
346     if (tab.runControl->isRunning()) {
347         if (prompt && !tab.runControl->aboutToStop())
348             return false;
349         if (tab.runControl->stop() == RunControl::AsynchronousStop) {
350             tab.asyncClosing = true;
351             return false;
352         }
353     }
354
355     m_tabWidget->removeTab(tabIndex);
356     if (tab.asyncClosing) { // We were invoked from its finished() signal.
357         tab.runControl->deleteLater();
358     } else {
359         delete tab.runControl;
360     }
361     delete tab.window;
362     m_runControlTabs.removeAt(index);
363     return true;
364 }
365
366 void OutputPane::projectRemoved()
367 {
368     tabChanged(m_tabWidget->currentIndex());
369 }
370
371 void OutputPane::tabChanged(int i)
372 {
373     if (i == -1) {
374         m_stopAction->setEnabled(false);
375         m_reRunButton->setEnabled(false);
376     } else {
377         const int index = indexOf(m_tabWidget->widget(i));
378         QTC_ASSERT(index != -1, return; )
379
380         RunControl *rc = m_runControlTabs.at(index).runControl;
381         m_stopAction->setEnabled(rc->isRunning());
382         m_reRunButton->setEnabled(!rc->isRunning());
383         m_reRunButton->setIcon(m_runIcon);
384     }
385 }
386
387 void OutputPane::runControlStarted()
388 {
389     RunControl *current = currentRunControl();
390     if (current && current == sender()) {
391         m_reRunButton->setEnabled(false);
392         m_stopAction->setEnabled(true);
393         m_reRunButton->setIcon(m_runIcon);
394     }
395 }
396
397 void OutputPane::runControlFinished()
398 {
399     RunControl *senderRunControl = qobject_cast<RunControl *>(sender());
400     const int senderIndex = indexOf(senderRunControl);
401
402     QTC_ASSERT(senderIndex != -1, return; )
403
404     // Enable buttons for current
405     RunControl *current = currentRunControl();
406
407     if (debug)
408         qDebug() << "OutputPane::runControlFinished"  << senderRunControl << senderIndex
409                     << " current " << current << m_runControlTabs.size();
410
411     if (current && current == sender()) {
412         m_reRunButton->setEnabled(true);
413         m_stopAction->setEnabled(false);
414         m_reRunButton->setIcon(m_runIcon);
415     }
416     // Check for asynchronous close. Close the tab.
417     if (m_runControlTabs.at(senderIndex).asyncClosing)
418         closeTab(tabWidgetIndexOf(senderIndex), false);
419
420     if (!isRunning())
421         emit allRunControlsFinished();
422 }
423
424 bool OutputPane::isRunning() const
425 {
426     foreach(const RunControlTab &rt, m_runControlTabs)
427         if (rt.runControl->isRunning())
428             return true;
429     return false;
430 }
431
432 bool OutputPane::canNext()
433 {
434     return false;
435 }
436
437 bool OutputPane::canPrevious()
438 {
439     return false;
440 }
441
442 void OutputPane::goToNext()
443 {
444
445 }
446
447 void OutputPane::goToPrev()
448 {
449
450 }
451
452 bool OutputPane::canNavigate()
453 {
454     return false;
455 }
456
457 /*******************/
458
459 OutputWindow::OutputWindow(QWidget *parent)
460     : QPlainTextEdit(parent)
461     , m_formatter(0)
462     , m_enforceNewline(false)
463     , m_scrollToBottom(false)
464     , m_linksActive(true)
465     , m_mousePressed(false)
466 {
467     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
468     //setCenterOnScroll(false);
469     setFrameShape(QFrame::NoFrame);
470     setMouseTracking(true);
471     if (!ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput)
472         setWordWrapMode(QTextOption::NoWrap);
473
474     static uint usedIds = 0;
475     Core::ICore *core = Core::ICore::instance();
476     Core::Context context(Constants::C_APP_OUTPUT, usedIds++);
477     m_outputWindowContext = new Core::BaseContext(this, context);
478     core->addContextObject(m_outputWindowContext);
479
480     QAction *undoAction = new QAction(this);
481     QAction *redoAction = new QAction(this);
482     QAction *cutAction = new QAction(this);
483     QAction *copyAction = new QAction(this);
484     QAction *pasteAction = new QAction(this);
485     QAction *selectAllAction = new QAction(this);
486
487     Core::ActionManager *am = core->actionManager();
488     am->registerAction(undoAction, Core::Constants::UNDO, context);
489     am->registerAction(redoAction, Core::Constants::REDO, context);
490     am->registerAction(cutAction, Core::Constants::CUT, context);
491     am->registerAction(copyAction, Core::Constants::COPY, context);
492     am->registerAction(pasteAction, Core::Constants::PASTE, context);
493     am->registerAction(selectAllAction, Core::Constants::SELECTALL, context);
494
495     connect(undoAction, SIGNAL(triggered()), this, SLOT(undo()));
496     connect(redoAction, SIGNAL(triggered()), this, SLOT(redo()));
497     connect(cutAction, SIGNAL(triggered()), this, SLOT(cut()));
498     connect(copyAction, SIGNAL(triggered()), this, SLOT(copy()));
499     connect(pasteAction, SIGNAL(triggered()), this, SLOT(paste()));
500     connect(selectAllAction, SIGNAL(triggered()), this, SLOT(selectAll()));
501
502     connect(this, SIGNAL(undoAvailable(bool)), undoAction, SLOT(setEnabled(bool)));
503     connect(this, SIGNAL(redoAvailable(bool)), redoAction, SLOT(setEnabled(bool)));
504     connect(this, SIGNAL(copyAvailable(bool)), cutAction, SLOT(setEnabled(bool)));  // OutputWindow never read-only
505     connect(this, SIGNAL(copyAvailable(bool)), copyAction, SLOT(setEnabled(bool)));
506
507     undoAction->setEnabled(false);
508     redoAction->setEnabled(false);
509     cutAction->setEnabled(false);
510     copyAction->setEnabled(false);
511
512     connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
513             this, SLOT(updateWordWrapMode()));
514 }
515
516 OutputWindow::~OutputWindow()
517 {
518     Core::ICore::instance()->removeContextObject(m_outputWindowContext);
519     delete m_outputWindowContext;
520 }
521
522 void OutputWindow::mousePressEvent(QMouseEvent * e)
523 {
524     m_mousePressed = true;
525     QPlainTextEdit::mousePressEvent(e);
526 }
527
528 void OutputWindow::mouseReleaseEvent(QMouseEvent *e)
529 {
530     m_mousePressed = false;
531
532     if (m_linksActive) {
533         const QString href = anchorAt(e->pos());
534         if (m_formatter)
535             m_formatter->handleLink(href);
536     }
537
538     // Mouse was released, activate links again
539     m_linksActive = true;
540
541     QPlainTextEdit::mouseReleaseEvent(e);
542 }
543
544 void OutputWindow::mouseMoveEvent(QMouseEvent *e)
545 {
546     // Cursor was dragged to make a selection, deactivate links
547     if (m_mousePressed && textCursor().hasSelection())
548         m_linksActive = false;
549
550     if (!m_linksActive || anchorAt(e->pos()).isEmpty())
551         viewport()->setCursor(Qt::IBeamCursor);
552     else
553         viewport()->setCursor(Qt::PointingHandCursor);
554     QPlainTextEdit::mouseMoveEvent(e);
555 }
556
557 void OutputWindow::resizeEvent(QResizeEvent *e)
558 {
559     //Keep scrollbar at bottom of window while resizing, to ensure we keep scrolling
560     //This can happen if window is resized while building, or if the horizontal scrollbar appears
561     bool atBottom = isScrollbarAtBottom();
562     QPlainTextEdit::resizeEvent(e);
563     if (atBottom)
564         scrollToBottom();
565 }
566
567 void OutputWindow::keyPressEvent(QKeyEvent *ev)
568 {
569     QPlainTextEdit::keyPressEvent(ev);
570
571     //Ensure we scroll also on Ctrl+Home or Ctrl+End
572     if (ev->matches(QKeySequence::MoveToStartOfDocument))
573         verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMinimum);
574     else if (ev->matches(QKeySequence::MoveToEndOfDocument))
575         verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
576 }
577
578 OutputFormatter *OutputWindow::formatter() const
579 {
580     return m_formatter;
581 }
582
583 void OutputWindow::setFormatter(OutputFormatter *formatter)
584 {
585     m_formatter = formatter;
586     m_formatter->setPlainTextEdit(this);
587 }
588
589 void OutputWindow::showEvent(QShowEvent *e)
590 {
591     QPlainTextEdit::showEvent(e);
592     if (m_scrollToBottom) {
593         verticalScrollBar()->setValue(verticalScrollBar()->maximum());
594     }
595     m_scrollToBottom = false;
596 }
597
598 QString OutputWindow::doNewlineEnfocement(const QString &out)
599 {
600     m_scrollToBottom = true;
601     QString s = out;
602     if (m_enforceNewline)
603         s.prepend(QLatin1Char('\n'));
604
605     m_enforceNewline = true; // make appendOutputInline put in a newline next time
606
607     if (s.endsWith(QLatin1Char('\n')))
608         s.chop(1);
609
610     return s;
611 }
612
613 void OutputWindow::appendMessage(const QString &output, OutputFormat format)
614 {
615     QString out = output;
616     out.remove(QLatin1Char('\r'));
617     setMaximumBlockCount(MaxBlockCount);
618     const bool atBottom = isScrollbarAtBottom();
619
620     if (format == ErrorMessageFormat || format == NormalMessageFormat) {
621
622         m_formatter->appendMessage(doNewlineEnfocement(out), format);
623
624     } else {
625
626         bool sameLine = format == StdOutFormatSameLine
627                      || format == StdErrFormatSameLine;
628
629         if (sameLine) {
630             m_scrollToBottom = true;
631
632             int newline = -1;
633             bool enforceNewline = m_enforceNewline;
634             m_enforceNewline = false;
635
636             if (!enforceNewline) {
637                 newline = out.indexOf(QLatin1Char('\n'));
638                 moveCursor(QTextCursor::End);
639                 if (newline != -1)
640                     m_formatter->appendMessage(out.left(newline), format);// doesn't enforce new paragraph like appendPlainText
641             }
642
643             QString s = out.mid(newline+1);
644             if (s.isEmpty()) {
645                 m_enforceNewline = true;
646             } else {
647                 if (s.endsWith(QLatin1Char('\n'))) {
648                     m_enforceNewline = true;
649                     s.chop(1);
650                 }
651                 m_formatter->appendMessage(QLatin1Char('\n') + s, format);
652             }
653         } else {
654             m_formatter->appendMessage(doNewlineEnfocement(out), format);
655         }
656     }
657
658     if (atBottom)
659         scrollToBottom();
660     enableUndoRedo();
661 }
662
663 // TODO rename
664 void OutputWindow::appendText(const QString &textIn, const QTextCharFormat &format, int maxLineCount)
665 {
666     QString text = textIn;
667     text.remove(QLatin1Char('\r'));
668     if (document()->blockCount() > maxLineCount)
669         return;
670     const bool atBottom = isScrollbarAtBottom();
671     QTextCursor cursor = QTextCursor(document());
672     cursor.movePosition(QTextCursor::End);
673     cursor.beginEditBlock();
674     cursor.insertText(doNewlineEnfocement(text), format);
675
676     if (document()->blockCount() > maxLineCount) {
677         QTextCharFormat tmp;
678         tmp.setFontWeight(QFont::Bold);
679         cursor.insertText(tr("Additional output omitted\n"), tmp);
680     }
681
682     cursor.endEditBlock();
683     if (atBottom)
684         scrollToBottom();
685 }
686
687 bool OutputWindow::isScrollbarAtBottom() const
688 {
689     return verticalScrollBar()->value() == verticalScrollBar()->maximum();
690 }
691
692 void OutputWindow::clear()
693 {
694     m_enforceNewline = false;
695     QPlainTextEdit::clear();
696 }
697
698 void OutputWindow::handleOldOutput()
699 {
700     if (ProjectExplorerPlugin::instance()->projectExplorerSettings().cleanOldAppOutput)
701         clear();
702     else
703         grayOutOldContent();
704 }
705
706 void OutputWindow::scrollToBottom()
707 {
708     verticalScrollBar()->setValue(verticalScrollBar()->maximum());
709 }
710
711 void OutputWindow::grayOutOldContent()
712 {
713     QTextCursor cursor = textCursor();
714     cursor.movePosition(QTextCursor::End);
715     QTextCharFormat endFormat = cursor.charFormat();
716
717     cursor.select(QTextCursor::Document);
718
719     QTextCharFormat format;
720     const QColor bkgColor = palette().base().color();
721     const QColor fgdColor = palette().text().color();
722     double bkgFactor = 0.50;
723     double fgdFactor = 1.-bkgFactor;
724     format.setForeground(QColor((bkgFactor * bkgColor.red() + fgdFactor * fgdColor.red()),
725                              (bkgFactor * bkgColor.green() + fgdFactor * fgdColor.green()),
726                              (bkgFactor * bkgColor.blue() + fgdFactor * fgdColor.blue()) ));
727     cursor.mergeCharFormat(format);
728
729     cursor.movePosition(QTextCursor::End);
730     cursor.setCharFormat(endFormat);
731     cursor.insertBlock(QTextBlockFormat());
732 }
733
734 void OutputWindow::enableUndoRedo()
735 {
736     setMaximumBlockCount(0);
737     setUndoRedoEnabled(true);
738 }
739
740 void OutputWindow::updateWordWrapMode()
741 {
742     if (ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput)
743         setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
744     else
745         setWordWrapMode(QTextOption::NoWrap);
746 }
747
748 } // namespace Internal
749 } // namespace ProjectExplorer