Commit 147396d7 authored by Aurindam Jana's avatar Aurindam Jana Committed by hjk
Browse files

ScriptConsole: Refactor to QtMessageLogWindow



Move QML/JS independent classes to common Debugger
code. A Debugger Engine needs to override
evaluateScriptExpression() to provide engine
specific script evaluation.

Change-Id: I02b23b380a3eb1b12003b30ded0b7d075e44dfed
Reviewed-by: default avatarhjk <qthjk@ovi.com>
parent a8ab1fd7
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@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 "consolewindow.h"
#include "logwindow.h"
#include "debuggeractions.h"
#include "debuggercore.h"
#include <QDebug>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QKeyEvent>
#include <QMenu>
#include <QSyntaxHighlighter>
#include <QPlainTextEdit>
#include <aggregation/aggregate.h>
#include <coreplugin/findplaceholder.h>
#include <find/basetextfind.h>
#include <utils/savedaction.h>
namespace Debugger {
namespace Internal {
/////////////////////////////////////////////////////////////////////
//
// ConsoleHighlighter
//
/////////////////////////////////////////////////////////////////////
class ConsoleHighlighter : public QSyntaxHighlighter
{
public:
ConsoleHighlighter(QPlainTextEdit *parent)
: QSyntaxHighlighter(parent->document()), m_parent(parent)
{}
private:
void highlightBlock(const QString &text)
{
QTextCharFormat format;
switch (LogWindow::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)
{
debuggerCore()->executeDebuggerCommand(textCursor().block().text());
QMenu *menu = createStandardContextMenu();
menu->addAction(m_clearContentsAction);
menu->addAction(m_saveContentsAction); // X11 clipboard is unreliable for long texts
menu->addAction(debuggerCore()->action(LogTimeStamps));
menu->addAction(debuggerCore()->action(VerboseLog));
menu->addSeparator();
menu->addAction(debuggerCore()->action(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()) {
debuggerCore()->executeDebuggerCommand(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) == QLatin1Char('['))
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()
{
LogWindow::writeLogContents(this, this);
}
/////////////////////////////////////////////////////////////////////
//
// ConsoleWindow
//
/////////////////////////////////////////////////////////////////////
ConsoleWindow::ConsoleWindow(QWidget *parent)
: QWidget(parent)
{
setWindowTitle(tr("Console"));
setObjectName(QLatin1String("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 Find::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(QLatin1Char('\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(LogWindow::charForChannel(channel) + line + QLatin1Char('\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"
......@@ -23,7 +23,6 @@ HEADERS += \
breakpointmarker.h \
breakwindow.h \
commonoptionspage.h \
consolewindow.h \
debugger_global.h \
debuggeractions.h \
debuggercore.h \
......@@ -67,7 +66,13 @@ HEADERS += \
debuggertooltipmanager.h \
debuggertoolchaincombobox.h \
debuggersourcepathmappingwidget.h \
memoryview.h
memoryview.h \
qtmessagelogwindow.h \
qtmessagelogeditor.h \
qtmessagelogview.h \
qtmessagelogproxymodel.h \
qtmessagelogitemdelegate.h \
qtmessageloghandler.h
SOURCES += \
basewindow.cpp \
......@@ -76,7 +81,6 @@ SOURCES += \
breakpointmarker.cpp \
breakwindow.cpp \
commonoptionspage.cpp \
consolewindow.cpp \
debuggeractions.cpp \
debuggerdialogs.cpp \
debuggerengine.cpp \
......@@ -113,7 +117,13 @@ SOURCES += \
debuggertooltipmanager.cpp \
debuggertoolchaincombobox.cpp \
debuggersourcepathmappingwidget.cpp \
memoryview.cpp
memoryview.cpp \
qtmessagelogwindow.cpp \
qtmessagelogproxymodel.cpp \
qtmessagelogview.cpp \
qtmessagelogitemdelegate.cpp \
qtmessageloghandler.cpp \
qtmessagelogeditor.cpp
FORMS += attachexternaldialog.ui \
attachcoredialog.ui \
......
......@@ -178,7 +178,8 @@ enum LogChannel
AppError, // stderr
AppStuff, // (possibly) windows debug channel
StatusBar, // LogStatus and also put to the status bar
ScriptConsoleOutput
QtMessageLogOutput,
QtMessageLogStatus
};
enum DebuggerEngineType
......
......@@ -119,6 +119,7 @@ public:
virtual void openMemoryEditor() = 0;
virtual void languagesChanged() = 0;
virtual void executeDebuggerCommand(const QString &command) = 0;
virtual bool evaluateScriptExpression(const QString &expression) = 0;
virtual Utils::SavedAction *action(int code) const = 0;
virtual bool boolSetting(int code) const = 0;
......
......@@ -50,6 +50,7 @@
#include "stackhandler.h"
#include "threadshandler.h"
#include "watchhandler.h"
#include "qtmessageloghandler.h"
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
......@@ -301,6 +302,7 @@ public:
StackHandler m_stackHandler;
ThreadsHandler m_threadsHandler;
WatchHandler m_watchHandler;
QtMessageLogHandler m_qtMessageHandler;
QFutureInterface<void> m_progress;
DisassemblerAgent m_disassemblerAgent;
......@@ -434,6 +436,11 @@ WatchHandler *DebuggerEngine::watchHandler() const
: &d->m_watchHandler;
}
QtMessageLogHandler *DebuggerEngine::qtMessageLogHandler() const
{
return &d->m_qtMessageHandler;
}
SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
return d->m_masterEngine
......@@ -513,6 +520,14 @@ QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
return model;
}
QAbstractItemModel *DebuggerEngine::qtMessageLogModel() const
{
QAbstractItemModel *model = qtMessageLogHandler()->model();
if (model->objectName().isEmpty()) // Make debugging easier.
model->setObjectName(objectName() + QLatin1String("QtMessageLogModel"));
return model;
}
void DebuggerEngine::fetchMemory(MemoryAgent *, QObject *,
quint64 addr, quint64 length)
{
......@@ -541,6 +556,9 @@ void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) c
}
//if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
// qDebug() << qPrintable(msg) << "IN STATE" << state();
if (channel == QtMessageLogOutput)
qtMessageLogHandler()->appendMessage(QtMessageLogHandler::UndefinedType, msg);
debuggerCore()->showMessage(msg, channel, timeout);
if (d->m_runControl) {
d->m_runControl->showMessage(msg, channel);
......@@ -1617,6 +1635,12 @@ void DebuggerEngine::executeDebuggerCommand(const QString &)
showStatusMessage(tr("This debugger cannot handle user input."));
}
bool DebuggerEngine::evaluateScriptExpression(const QString &)
{
showStatusMessage(tr("This debugger cannot handle user input."));
return false;
}
BreakHandler *DebuggerEngine::breakHandler() const
{
return debuggerCore()->breakHandler();
......
......@@ -82,6 +82,7 @@ class BreakpointParameters;
class QmlCppEngine;
class DebuggerToolTipContext;
class MemoryMarkup;
class QtMessageLogHandler;
struct WatchUpdateFlags
{
......@@ -224,6 +225,7 @@ public:
virtual Internal::WatchHandler *watchHandler() const;
virtual Internal::SourceFilesHandler *sourceFilesHandler() const;
virtual Internal::BreakHandler *breakHandler() const;
virtual Internal::QtMessageLogHandler *qtMessageLogHandler() const;
virtual QAbstractItemModel *modulesModel() const;
virtual QAbstractItemModel *registerModel() const;
......@@ -234,6 +236,7 @@ public:
virtual QAbstractItemModel *returnModel() const;
virtual QAbstractItemModel *toolTipsModel() const;
virtual QAbstractItemModel *sourceFilesModel() const;
virtual QAbstractItemModel *qtMessageLogModel() const;
void progressPing();
void handleFinished();
......@@ -361,6 +364,7 @@ protected:
virtual void executeRunToFunction(const QString &functionName);
virtual void executeJumpToLine(const Internal::ContextData &data);
virtual void executeDebuggerCommand(const QString &command);
virtual bool evaluateScriptExpression(const QString &expression);
virtual void frameUp();
virtual void frameDown();
......
......@@ -660,7 +660,7 @@ void DebuggerMainWindowPrivate::setSimpleDockWidgetArrangement()
QDockWidget *threadsDock = q->dockWidget(QLatin1String(DOCKWIDGET_THREADS));
QDockWidget *outputDock = q->dockWidget(QLatin1String(DOCKWIDGET_OUTPUT));
QDockWidget *qmlInspectorDock = q->dockWidget(QLatin1String(DOCKWIDGET_QML_INSPECTOR));
QDockWidget *scriptConsoleDock = q->dockWidget(QLatin1String(DOCKWIDGET_QML_SCRIPTCONSOLE));
QDockWidget *consoleDock = q->dockWidget(QLatin1String(DOCKWIDGET_QML_SCRIPTCONSOLE));
QDockWidget *modulesDock = q->dockWidget(QLatin1String(DOCKWIDGET_MODULES));
QDockWidget *registerDock = q->dockWidget(QLatin1String(DOCKWIDGET_REGISTER));
QDockWidget *sourceFilesDock = q->dockWidget(QLatin1String(DOCKWIDGET_SOURCE_FILES));
......@@ -671,7 +671,7 @@ void DebuggerMainWindowPrivate::setSimpleDockWidgetArrangement()
QTC_ASSERT(snapshotsDock, return);
QTC_ASSERT(threadsDock, return);
QTC_ASSERT(outputDock, return);
QTC_ASSERT(scriptConsoleDock, return);
QTC_ASSERT(consoleDock, return);
QTC_ASSERT(modulesDock, return);
QTC_ASSERT(registerDock, return);
QTC_ASSERT(sourceFilesDock, return);
......@@ -697,13 +697,13 @@ void DebuggerMainWindowPrivate::setSimpleDockWidgetArrangement()
q->tabifyDockWidget(breakDock, threadsDock);
q->tabifyDockWidget(breakDock, sourceFilesDock);
q->tabifyDockWidget(breakDock, snapshotsDock);
q->tabifyDockWidget(breakDock, scriptConsoleDock);
q->tabifyDockWidget(breakDock, consoleDock);
if (m_activeDebugLanguages.testFlag(Debugger::QmlLanguage)) {
if (qmlInspectorDock)
qmlInspectorDock->show();
if (scriptConsoleDock)
scriptConsoleDock->show();
if (consoleDock)
consoleDock->show();
} else {
// CPP only
threadsDock->show();
......
......@@ -47,7 +47,7 @@
#include "breakpoint.h"
#include "breakhandler.h"
#include "breakwindow.h"
#include "consolewindow.h"
#include "qtmessagelogwindow.h"
#include "disassemblerlines.h"
#include "logwindow.h"
#include "moduleswindow.h"
......@@ -114,8 +114,6 @@
#include <utils/statuslabel.h>
#include <utils/fileutils.h>
#include <qml/qmljsscriptconsole.h>
#include <QTimer>
#include <QtPlugin>
#include <QComboBox>
......@@ -849,7 +847,7 @@ public slots:
void aboutToSaveSession();
void executeDebuggerCommand(const QString &command);
void evaluateExpression(const QString &expression);
bool evaluateScriptExpression(const QString &expression);
void coreShutdown();
#ifdef WITH_TESTS
......@@ -1172,7 +1170,7 @@ public:
BreakWindow *m_breakWindow;
BreakHandler *m_breakHandler;
//ConsoleWindow *m_consoleWindow;
QtMessageLogWindow *m_qtMessageLogWindow;
QTreeView *m_returnWindow;
QTreeView *m_localsWindow;
QTreeView *m_watchersWindow;
......@@ -1183,7 +1181,6 @@ public:
QAbstractItemView *m_stackWindow;
QAbstractItemView *m_threadsWindow;
LogWindow *m_logWindow;
QmlJSScriptConsoleWidget *m_scriptConsoleWindow;
bool m_busy;
QString m_lastPermanentStatusMessage;
......@@ -1237,7 +1234,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) :
m_stackWindow = 0;
m_threadsWindow = 0;
m_logWindow = 0;
m_scriptConsoleWindow = 0;
m_qtMessageLogWindow = 0;
m_mainWindow = 0;
m_snapshotHandler = 0;
......@@ -2096,8 +2093,7 @@ void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine)
//m_threadBox->setModel(engine->threadsModel());
//m_threadBox->setModelColumn(ThreadData::ComboNameColumn);
m_watchersWindow->setModel(engine->watchersModel());
m_scriptConsoleWindow->setEngine(engine);
m_qtMessageLogWindow->setModel(engine->qtMessageLogModel());
engine->watchHandler()->rebuildModel();
......@@ -2219,7 +2215,7 @@ void DebuggerPluginPrivate::setInitialState()
action(AutoDerefPointers)->setEnabled(true);
action(ExpandStack)->setEnabled(false);
m_scriptConsoleWindow->setEnabled(false);
m_qtMessageLogWindow->setEnabled(true);
}
void DebuggerPluginPrivate::updateWatchersWindow()
......@@ -2519,9 +2515,9 @@ void DebuggerPluginPrivate::showStatusMessage(const QString &msg0, int timeout)
m_statusLabel->showStatusMessage(msg, timeout);
}
void DebuggerPluginPrivate::evaluateExpression(const QString &expression)
bool DebuggerPluginPrivate::evaluateScriptExpression(const QString &expression)
{
currentEngine()->executeDebuggerCommand(expression);
return currentEngine()->evaluateScriptExpression(expression);
}
void DebuggerPluginPrivate::openMemoryEditor()
......@@ -2595,9 +2591,6 @@ void DebuggerPluginPrivate::showMessage(const QString &msg, int channel, int tim
m_logWindow->showInput(LogInput, msg);
m_logWindow->showOutput(LogInput, msg);
break;
case ScriptConsoleOutput:
m_scriptConsoleWindow->appendResult(msg);