outputwindow.cpp 13.2 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
5
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
** Commercial Usage
10
**
11
12
13
14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18
19
20
21
22
23
** 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.
24
**
25
** If you are unsure which license is appropriate for your use, please
26
** contact the sales department at http://www.qtsoftware.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
31
32
33
#include "outputwindow.h"
#include "projectexplorerconstants.h"
#include "runconfiguration.h"

34
#include <coreplugin/actionmanager/actionmanager.h>
35
36
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
37
#include <coreplugin/uniqueidmanager.h>
con's avatar
con committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <find/basetextfind.h>
#include <aggregation/aggregate.h>

#include <QtGui/QIcon>
#include <QtGui/QScrollBar>
#include <QtGui/QTextLayout>
#include <QtGui/QPainter>
#include <QtGui/QApplication>
#include <QtGui/QClipboard>
#include <QtGui/QMenu>
#include <QtGui/QMessageBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QTabWidget>

52
53
#include <QtGui/QApplication>

con's avatar
con committed
54
55
56
using namespace ProjectExplorer::Internal;
using namespace ProjectExplorer;

57
58
static const int MaxBlockCount = 100000;

hjk's avatar
hjk committed
59
OutputPane::OutputPane()
60
    : m_mainWidget(new QWidget)
con's avatar
con committed
61
62
63
64
65
66
67
68
69
70
71
{
//     m_insertLineButton = new QToolButton;
//     m_insertLineButton->setIcon(QIcon(ProjectExplorer::Constants::ICON_INSERT_LINE));
//     m_insertLineButton->setText(tr("Insert line"));
//     m_insertLineButton->setToolTip(tr("Insert line"));
//     m_insertLineButton->setAutoRaise(true);
//     connect(m_insertLineButton, SIGNAL(clicked()), this, SLOT(insertLine()));

    QIcon runIcon(Constants::ICON_RUN);
    runIcon.addFile(Constants::ICON_RUN_SMALL);

72
    // Rerun
con's avatar
con committed
73
74
    m_reRunButton = new QToolButton;
    m_reRunButton->setIcon(runIcon);
Friedemann Kleint's avatar
Friedemann Kleint committed
75
    m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
con's avatar
con committed
76
77
78
79
80
    m_reRunButton->setAutoRaise(true);
    m_reRunButton->setEnabled(false);
    connect(m_reRunButton, SIGNAL(clicked()),
            this, SLOT(reRunRunControl()));

81
    // Stop
hjk's avatar
hjk committed
82
    Core::ActionManager *am = Core::ICore::instance()->actionManager();
83
84
85
86
87
88
89
    QList<int> globalcontext;
    globalcontext.append(Core::Constants::C_GLOBAL_ID);

    m_stopAction = new QAction(QIcon(Constants::ICON_STOP), tr("Stop"), this);
    m_stopAction->setToolTip(tr("Stop"));
    m_stopAction->setEnabled(false);

con's avatar
con committed
90
    Core::Command *cmd = am->registerAction(m_stopAction, Constants::STOP, globalcontext);
91
92
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+R")));

con's avatar
con committed
93
    m_stopButton = new QToolButton;
94
    m_stopButton->setDefaultAction(cmd->action());
con's avatar
con committed
95
    m_stopButton->setAutoRaise(true);
96
97

    connect(m_stopAction, SIGNAL(triggered()),
con's avatar
con committed
98
99
100
101
102
103
104
105
106
107
108
109
110
            this, SLOT(stopRunControl()));

    // Spacer (?)

    QVBoxLayout *layout = new QVBoxLayout;
    layout->setMargin(0);
    m_tabWidget = new QTabWidget;
    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);

hjk's avatar
hjk committed
111
    connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
con's avatar
con committed
112
113

    m_mainWidget->setLayout(layout);
114
115
116

    connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()),
            this, SLOT(coreAboutToClose()));
con's avatar
con committed
117
118
}

119
void OutputPane::coreAboutToClose()
con's avatar
con committed
120
121
122
123
124
125
126
{
    while (m_tabWidget->count()) {
        RunControl *rc = runControlForTab(0);
        if (rc->isRunning())
            rc->stop();
        closeTab(0);
    }
127
128
129
130
}

OutputPane::~OutputPane()
{
con's avatar
con committed
131
132
133
    delete m_mainWidget;
}

134
QWidget *OutputPane::outputWidget(QWidget *)
con's avatar
con committed
135
{
136
    return m_mainWidget;
con's avatar
con committed
137
138
}

hjk's avatar
hjk committed
139
QList<QWidget*> OutputPane::toolBarWidgets() const
con's avatar
con committed
140
{
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    return QList<QWidget*>() << m_reRunButton << m_stopButton
            ; // << m_insertLineButton;
}

QString OutputPane::name() 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::appendOutput(const QString &/*out*/)
{
    // This function is in the interface, since we can't do anything sensible here, we don't do anything here.
con's avatar
con committed
185
186
187
188
189
190
191
}

void OutputPane::createNewOutputWindow(RunControl *rc)
{
    connect(rc, SIGNAL(started()),
            this, SLOT(runControlStarted()));
    connect(rc, SIGNAL(finished()),
192
193
            this, SLOT(runControlFinished()));

con's avatar
con committed
194
195
    // First look if we can reuse a tab
    bool found = false;
196
    for (int i = 0; i < m_tabWidget->count(); ++i) {
con's avatar
con committed
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
        RunControl *old = runControlForTab(i);
        if (old->runConfiguration() == rc->runConfiguration() && !old->isRunning()) {
            // Reuse this tab
            delete old;
            m_outputWindows.remove(old);
            OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(i));
            ow->appendOutput("");//New line
            m_outputWindows.insert(rc, ow);
            found = true;
            break;
        }
    }
    if (!found) {
        OutputWindow *ow = new OutputWindow(m_tabWidget);
        Aggregation::Aggregate *agg = new Aggregation::Aggregate;
        agg->add(ow);
        agg->add(new Find::BaseTextFind(ow));
        m_outputWindows.insert(rc, ow);
        m_tabWidget->addTab(ow, rc->runConfiguration()->name());
    }
}

219
void OutputPane::appendOutput(RunControl *rc, const QString &out)
con's avatar
con committed
220
{
221
222
    OutputWindow *ow = m_outputWindows.value(rc);
    ow->appendOutput(out);
con's avatar
con committed
223
224
}

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
225
226
227
228
229
230
void OutputPane::appendOutputInline(RunControl *rc, const QString &out)
{
    OutputWindow *ow = m_outputWindows.value(rc);
    ow->appendOutputInline(out);
}

231
void OutputPane::showTabFor(RunControl *rc)
con's avatar
con committed
232
{
233
234
    OutputWindow *ow = m_outputWindows.value(rc);
    m_tabWidget->setCurrentWidget(ow);
con's avatar
con committed
235
236
}

237
void OutputPane::insertLine()
con's avatar
con committed
238
{
239
240
241
    OutputWindow *currentWindow = qobject_cast<OutputWindow *>(m_tabWidget->currentWidget());
    if (currentWindow)
        currentWindow->clear();
con's avatar
con committed
242
243
}

244
void OutputPane::reRunRunControl()
con's avatar
con committed
245
{
246
247
248
    RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
    if (rc->runConfiguration()->project() != 0)
        rc->start();
con's avatar
con committed
249
250
}

251
void OutputPane::stopRunControl()
con's avatar
con committed
252
{
253
254
    RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
    rc->stop();
con's avatar
con committed
255
256
}

257
void OutputPane::closeTab(int index)
con's avatar
con committed
258
{
259
260
261
262
263
264
265
266
267
268
269
270
    OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(index));
    RunControl *rc = m_outputWindows.key(ow);

    if (rc->isRunning()) {
        QString msg = tr("The application is still running. Close it first.");
        QMessageBox::critical(0, tr("Unable to close"), msg);
        return;
    }

    m_tabWidget->removeTab(index);
    delete ow;
    delete rc;
con's avatar
con committed
271
272
}

273
void OutputPane::projectRemoved()
con's avatar
con committed
274
{
275
276
    tabChanged(m_tabWidget->currentIndex());
}
con's avatar
con committed
277

278
279
280
void OutputPane::tabChanged(int i)
{
    if (i == -1) {
281
        m_stopAction->setEnabled(false);
282
283
284
        m_reRunButton->setEnabled(false);
    } else {
        RunControl *rc = runControlForTab(i);
285
        m_stopAction->setEnabled(rc->isRunning());
286
287
        m_reRunButton->setEnabled(!rc->isRunning() && rc->runConfiguration()->project());
    }
con's avatar
con committed
288
289
}

290
void OutputPane::runControlStarted()
con's avatar
con committed
291
{
292
293
294
    RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
    if (rc == qobject_cast<RunControl *>(sender())) {
        m_reRunButton->setEnabled(false);
295
        m_stopAction->setEnabled(true);
296
    }
con's avatar
con committed
297
298
}

299
void OutputPane::runControlFinished()
con's avatar
con committed
300
{
301
302
303
    RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
    if (rc == qobject_cast<RunControl *>(sender())) {
        m_reRunButton->setEnabled(rc->runConfiguration()->project());
304
        m_stopAction->setEnabled(false);
305
    }
con's avatar
con committed
306
307
}

308
RunControl* OutputPane::runControlForTab(int index) const
con's avatar
con committed
309
{
310
    return m_outputWindows.key(qobject_cast<OutputWindow *>(m_tabWidget->widget(index)));
con's avatar
con committed
311
312
}

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
bool OutputPane::canNext()
{
    return false;
}

bool OutputPane::canPrevious()
{
    return false;
}

void OutputPane::goToNext()
{

}

void OutputPane::goToPrev()
{

}

bool OutputPane::canNavigate()
{
    return false;
}
con's avatar
con committed
337
338
339
340
341
342
343
344
345
346
347
348

/*******************/

OutputWindow::OutputWindow(QWidget *parent)
    : QPlainTextEdit(parent)
{
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    //setCenterOnScroll(false);
    setWindowTitle(tr("Application Output Window"));
    setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
    setFrameShape(QFrame::NoFrame);

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
    static uint usedIds = 0;
    Core::ICore *core = Core::ICore::instance();
    QList<int> context;
    context << core->uniqueIDManager()->uniqueIdentifier(QString(Constants::C_APP_OUTPUT) + QString().setNum(usedIds++));
    m_outputWindowContext = new Core::BaseContext(this, context);
    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()->registerAction(undoAction, Core::Constants::UNDO, context);
    core->actionManager()->registerAction(redoAction, Core::Constants::REDO, context);
    core->actionManager()->registerAction(cutAction, Core::Constants::CUT, context);
    core->actionManager()->registerAction(copyAction, Core::Constants::COPY, context);
    core->actionManager()->registerAction(pasteAction, Core::Constants::PASTE, context);
    core->actionManager()->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);
}
con's avatar
con committed
387
388
389

OutputWindow::~OutputWindow()
{
390
    Core::ICore::instance()->removeContextObject(m_outputWindowContext);
con's avatar
con committed
391
392
393
394
}

void OutputWindow::appendOutput(const QString &out)
{
395
    setMaximumBlockCount(MaxBlockCount);
396
    moveCursor(QTextCursor::End);
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
397
    if (out.endsWith('\n'))
398
        insertPlainText(out.right(out.length()-1));
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
399
    else
400
401
402
        insertPlainText(out);
    // insert newline and get automatic scroll behavior
    appendPlainText(""); // makes sure that there's an newline in front
403
    enableUndoRedo();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
404
405
}

406

Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
407
408
void OutputWindow::appendOutputInline(const QString &out)
{
409
410
    setMaximumBlockCount(MaxBlockCount);

411
412
    int newline = out.indexOf(QLatin1Char('\n'));
    if (newline < 0) {
413
414
        moveCursor(QTextCursor::End);
        insertPlainText(out); // doesn't insert additional '\n' like appendPlainText
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
    }else{
        int lastnewline = out.lastIndexOf(QLatin1Char('\n'));
        // make sure that we use appendPlainText to add the last newline
        // in the string, so we get automatic scrolling
        // and work around the fact that appendPlainText also ensures
        // a newline in front of the appended text
        if (lastnewline > 0) {
            moveCursor(QTextCursor::End);
            insertPlainText(out.left(lastnewline));
        }
        appendPlainText(""); // add the newline
        if (lastnewline < out.length()-1) { // newline is not last character
            moveCursor(QTextCursor::End);
            insertPlainText(out.mid(lastnewline+1));
        }
430
    }
431
    enableUndoRedo();
con's avatar
con committed
432
433
434
435
}

void OutputWindow::insertLine()
{
436
    setMaximumBlockCount(MaxBlockCount);
con's avatar
con committed
437
    appendPlainText(QString());
438
    enableUndoRedo();
con's avatar
con committed
439
440
}

441
442
443
444
445
void OutputWindow::enableUndoRedo()
{
    setMaximumBlockCount(0);
    setUndoRedoEnabled(true);
}