diff options
author | hjk <qtc-committer@nokia.com> | 2010-09-22 12:25:42 +0200 |
---|---|---|
committer | hjk <qtc-committer@nokia.com> | 2010-09-22 16:02:15 +0200 |
commit | cf1ffdbc454384d487c7355c72e626f3ddab5fb5 (patch) | |
tree | c410b65ce69dd503001a322ce9381deb52207688 /src/plugins/debugger/consolewindow.cpp | |
parent | d9f4cb417073ecaeb7386b4189351c28b0ec4ad1 (diff) | |
download | qt-creator-cf1ffdbc454384d487c7355c72e626f3ddab5fb5.tar.gz |
debugger: start implementing a debugger console
Diffstat (limited to 'src/plugins/debugger/consolewindow.cpp')
-rw-r--r-- | src/plugins/debugger/consolewindow.cpp | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/src/plugins/debugger/consolewindow.cpp b/src/plugins/debugger/consolewindow.cpp new file mode 100644 index 0000000000..8169e7ba2b --- /dev/null +++ b/src/plugins/debugger/consolewindow.cpp @@ -0,0 +1,381 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "consolewindow.h" + +#include "debuggeractions.h" +#include "debuggerconstants.h" + +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QTime> + +#include <QtGui/QAction> +#include <QtGui/QHBoxLayout> +#include <QtGui/QVBoxLayout> +#include <QtGui/QKeyEvent> +#include <QtGui/QLabel> +#include <QtGui/QLineEdit> +#include <QtGui/QMenu> +#include <QtGui/QSpacerItem> +#include <QtGui/QSplitter> +#include <QtGui/QSyntaxHighlighter> +#include <QtGui/QTextBlock> +#include <QtGui/QPlainTextEdit> +#include <QtGui/QFileDialog> +#include <QtGui/QMessageBox> + +#include <aggregation/aggregate.h> +#include <coreplugin/findplaceholder.h> +#include <coreplugin/minisplitter.h> +#include <find/basetextfind.h> + +#include <utils/savedaction.h> + +using namespace Find; + +namespace Debugger { +namespace Internal { + +static QChar charForChannel(int channel) +{ + switch (channel) { + case LogDebug: return 'd'; + case LogWarning: return 'w'; + case LogError: return 'e'; + case LogInput: return '<'; + case LogOutput: return '>'; + case LogStatus: return 's'; + case LogTime: return 't'; + case LogMisc: + default: return ' '; + } +} + +static LogChannel channelForChar(QChar c) +{ + switch (c.unicode()) { + case 'd': return LogDebug; + case 'w': return LogWarning; + case 'e': return LogError; + case '<': return LogInput; + case '>': return LogOutput; + case 's': return LogStatus; + case 't': return LogTime; + default: return LogMisc; + } +} + + +///////////////////////////////////////////////////////////////////// +// +// ConsoleHighlighter +// +///////////////////////////////////////////////////////////////////// + +class ConsoleHighlighter : public QSyntaxHighlighter +{ +public: + ConsoleHighlighter(QPlainTextEdit *parent) + : QSyntaxHighlighter(parent->document()), m_parent(parent) + {} + +private: + void highlightBlock(const QString &text) + { + QTextCharFormat format; + switch (channelForChar(text.isEmpty() ? QChar() : text.at(0))) { + case LogInput: + format.setForeground(Qt::blue); + setFormat(1, text.size(), format); + break; + case LogStatus: + format.setForeground(Qt::darkGreen); + setFormat(1, text.size(), format); + break; + case LogWarning: + format.setForeground(Qt::darkYellow); + setFormat(1, text.size(), format); + break; + case LogError: + format.setForeground(Qt::red); + setFormat(1, text.size(), format); + break; + case LogTime: + format.setForeground(Qt::darkRed); + setFormat(1, text.size(), format); + break; + default: + break; + } + QColor base = m_parent->palette().color(QPalette::Base); + format.setForeground(base); + format.setFontPointSize(1); + setFormat(0, 1, format); +/* + if (text.size() > 3 && text.at(2) == QLatin1Char(':')) { + QTextCharFormat format; + format.setForeground(Qt::darkRed); + setFormat(1, text.size(), format); + } +*/ + } + + QPlainTextEdit *m_parent; +}; + +///////////////////////////////////////////////////////////////////// +// +// DebbuggerPane base class +// +///////////////////////////////////////////////////////////////////// + +// FIXME: Code duplication with FakeVim +class History +{ +public: + History() : m_index(0) {} + void append(const QString &item) { + m_items.removeAll(item); + m_items.append(item); m_index = m_items.size() - 1; + } + void down() { m_index = qMin(m_index + 1, m_items.size()); } + void up() { m_index = qMax(m_index - 1, 0); } + //void clear() { m_items.clear(); m_index = 0; } + void restart() { m_index = m_items.size(); } + QString current() const { return m_items.value(m_index, QString()); } + QStringList items() const { return m_items; } +private: + QStringList m_items; + int m_index; +}; + +class Console : public QPlainTextEdit +{ + Q_OBJECT + +public: + Console(QWidget *parent) + : QPlainTextEdit(parent) + { + setMaximumBlockCount(100000); + setFrameStyle(QFrame::NoFrame); + m_clearContentsAction = new QAction(this); + m_clearContentsAction->setText(tr("Clear Contents")); + m_clearContentsAction->setEnabled(true); + connect(m_clearContentsAction, SIGNAL(triggered(bool)), + parent, SLOT(clearContents())); + + m_saveContentsAction = new QAction(this); + m_saveContentsAction->setText(tr("Save Contents")); + m_saveContentsAction->setEnabled(true); + connect(m_saveContentsAction, SIGNAL(triggered()), this, SLOT(saveContents())); + } + + void contextMenuEvent(QContextMenuEvent *ev) + { + theDebuggerAction(ExecuteCommand)->setData(textCursor().block().text()); + QMenu *menu = createStandardContextMenu(); + menu->addAction(m_clearContentsAction); + menu->addAction(m_saveContentsAction); // X11 clipboard is unreliable for long texts + menu->addAction(theDebuggerAction(ExecuteCommand)); + menu->addAction(theDebuggerAction(LogTimeStamps)); + menu->addAction(theDebuggerAction(VerboseLog)); + menu->addSeparator(); + menu->addAction(theDebuggerAction(SettingsDialog)); + menu->exec(ev->globalPos()); + delete menu; + } + + void keyPressEvent(QKeyEvent *ev) + { + if (ev->key() == Qt::Key_Return) { + if (ev->modifiers() == 0) { + QString cmd = textCursor().block().text(); + if (cmd.isEmpty()) + cmd = m_history.current(); + QString cleanCmd; + foreach (QChar c, cmd) + if (c.unicode() >= 32 && c.unicode() < 128) + cleanCmd.append(c); + if (!cleanCmd.isEmpty()) { + theDebuggerAction(ExecuteCommand)->trigger(cleanCmd); + m_history.append(cleanCmd); + } + } + QPlainTextEdit::keyPressEvent(ev); + } else if (ev->key() == Qt::Key_Up) { + m_history.up(); + } else if (ev->key() == Qt::Key_Down) { + m_history.down(); + } else { + QPlainTextEdit::keyPressEvent(ev); + } + } + + void mouseDoubleClickEvent(QMouseEvent *ev) + { + QString line = cursorForPosition(ev->pos()).block().text(); + int n = 0; + + // cut time string + if (line.size() > 18 && line.at(0) == '[') + line = line.mid(18); + //qDebug() << line; + + for (int i = 0; i != line.size(); ++i) { + QChar c = line.at(i); + if (!c.isDigit()) + break; + n = 10 * n + c.unicode() - '0'; + } + //emit commandSelected(n); + } + + +private slots: + void saveContents(); + +private: + QAction *m_clearContentsAction; + QAction *m_saveContentsAction; + History m_history; +}; + +void Console::saveContents() +{ + while (true) { + const QString fileName = QFileDialog::getSaveFileName(this, tr("Log File")); + if (fileName.isEmpty()) + break; + QFile file(fileName); + if (file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate)) { + file.write(toPlainText().toUtf8()); + file.close(); + break; + } else { + QMessageBox::warning(this, tr("Write Failure"), + tr("Unable to write log contents to '%1': %2"). + arg(fileName, file.errorString())); + } + } +} + + + +///////////////////////////////////////////////////////////////////// +// +// ConsoleWindow +// +///////////////////////////////////////////////////////////////////// + +ConsoleWindow::ConsoleWindow(QWidget *parent) + : QWidget(parent) +{ + setWindowTitle(tr("Console")); + + m_console = new Console(this); + m_console->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(m_console); + layout->addWidget(new Core::FindToolBarPlaceHolder(this)); + setLayout(layout); + + Aggregation::Aggregate *aggregate = new Aggregation::Aggregate; + aggregate->add(m_console); + aggregate->add(new BaseTextFind(m_console)); + + //connect(m_console, SIGNAL(statusMessageRequested(QString,int)), + // this, SIGNAL(statusMessageRequested(QString,int))); +}; + +void ConsoleWindow::showOutput(int channel, const QString &output) +{ + if (output.isEmpty()) + return; + //QTextCursor oldCursor = m_console->textCursor(); + //QTextCursor cursor = oldCursor; + //cursor.movePosition(QTextCursor::End); + //bool atEnd = oldCursor.position() == cursor.position(); + + foreach (QString line, output.split('\n')) { + // FIXME: QTextEdit asserts on really long lines... + const int n = 30000; + if (line.size() > n) { + line.truncate(n); + line += QLatin1String(" [...] <cut off>"); + } + m_console->appendPlainText(charForChannel(channel) + line + "\n"); + } + QTextCursor cursor = m_console->textCursor(); + cursor.movePosition(QTextCursor::End); + //if (atEnd) { + m_console->setTextCursor(cursor); + m_console->ensureCursorVisible(); + //} +} + +void ConsoleWindow::showInput(int channel, const QString &input) +{ + Q_UNUSED(channel) + m_console->appendPlainText(input); + QTextCursor cursor = m_console->textCursor(); + cursor.movePosition(QTextCursor::End); + m_console->setTextCursor(cursor); + m_console->ensureCursorVisible(); +} + +void ConsoleWindow::clearContents() +{ + m_console->clear(); +} + +void ConsoleWindow::setCursor(const QCursor &cursor) +{ + m_console->viewport()->setCursor(cursor); + QWidget::setCursor(cursor); +} + +QString ConsoleWindow::combinedContents() const +{ + return m_console->toPlainText(); +} + +QString ConsoleWindow::inputContents() const +{ + return m_console->toPlainText(); +} + +} // namespace Internal +} // namespace Debugger + +#include "consolewindow.moc" |