Commit cb0b3424 authored by Aurindam Jana's avatar Aurindam Jana

QmlJSScriptConsole: Refactored ScriptConsole, added functionality.

The ScriptConsole is renamed to QmlJSScriptConsole. The console can be used
to evaluate expressions during a QML application debug session.
Changes:
* Console can be used even when application is not on a debug break
* The object context is the currently selected object in Inspector
* ContextMenu has a Clear option
* Multiple line expressions are supported
* Traverse Command History using up and down arrow keys

Change-Id: I4e1cd8763d60be43dbba395ead2a9a086d6bab7d
Reviewed-by: default avatarRoberto Raggi <roberto.raggi@nokia.com>
Reviewed-by: default avatarKai Koehne <kai.koehne@nokia.com>
parent 87943ca6
......@@ -170,7 +170,7 @@ public:
bool isWaiting() const;
Q_SIGNALS:
void stateChanged(QDeclarativeDebugQuery::State);
void stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State);
protected:
QDeclarativeDebugQuery(QObject *);
......
......@@ -6,3 +6,4 @@ include(../../plugins/texteditor/texteditor.pri)
include(../../libs/cplusplus/cplusplus.pri)
include(../../libs/utils/utils.pri)
include(../../libs/symbianutils/symbianutils.pri)
include(../../libs/qmljs/qmljs.pri)
......@@ -112,7 +112,7 @@
#include <utils/statuslabel.h>
#include <utils/fileutils.h>
#include <qml/scriptconsole.h>
#include <qml/qmljsscriptconsole.h>
#include <QtCore/QTimer>
#include <QtCore/QtPlugin>
......@@ -785,7 +785,7 @@ public slots:
void aboutToSaveSession();
void executeDebuggerCommand(const QString &command);
void scriptExpressionEntered(const QString &expression);
void evaluateExpression(const QString &expression);
void coreShutdown();
public slots:
......@@ -1079,7 +1079,7 @@ public:
QAbstractItemView *m_stackWindow;
QAbstractItemView *m_threadsWindow;
LogWindow *m_logWindow;
ScriptConsole *m_scriptConsoleWindow;
QmlJSScriptConsoleWidget *m_scriptConsoleWindow;
bool m_busy;
QString m_lastPermanentStatusMessage;
......@@ -1972,6 +1972,16 @@ void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine)
//m_threadBox->setModel(engine->threadsModel());
//m_threadBox->setModelColumn(ThreadData::ComboNameColumn);
m_watchersWindow->setModel(engine->watchersModel());
//Initialize QmlJSConsole
QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(engine);
QmlCppEngine *qmlCppEngine = qobject_cast<QmlCppEngine *>(engine);
if (qmlCppEngine)
qmlEngine = qobject_cast<QmlEngine *>(qmlCppEngine->qmlEngine());
if (qmlEngine) {
m_scriptConsoleWindow->setQmlAdapter(qmlEngine->adapter());
}
engine->watchHandler()->rebuildModel();
}
......@@ -2047,7 +2057,6 @@ void DebuggerPluginPrivate::setBusyCursor(bool busy)
m_threadsWindow->setCursor(cursor);
m_watchersWindow->setCursor(cursor);
m_snapshotWindow->setCursor(cursor);
m_scriptConsoleWindow->setCursor(cursor);
}
void DebuggerPluginPrivate::setInitialState()
......@@ -2239,8 +2248,11 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
if (qmlCppEngine)
qmlEngine = qobject_cast<QmlEngine *>(qmlCppEngine->qmlEngine());
if (qmlEngine) {
m_scriptConsoleWindow->setEnabled(stopped);
if (qmlEngine && (state == InferiorRunOk || state == InferiorStopOk)) {
m_scriptConsoleWindow->setEnabled(true);
m_scriptConsoleWindow->setInferiorStopped(state == InferiorStopOk);
} else {
m_scriptConsoleWindow->setEnabled(false);
}
}
......@@ -2387,7 +2399,7 @@ void DebuggerPluginPrivate::showStatusMessage(const QString &msg0, int timeout)
m_statusLabel->showStatusMessage(msg, timeout);
}
void DebuggerPluginPrivate::scriptExpressionEntered(const QString &expression)
void DebuggerPluginPrivate::evaluateExpression(const QString &expression)
{
currentEngine()->executeDebuggerCommand(expression);
}
......@@ -2757,11 +2769,11 @@ void DebuggerPluginPrivate::extensionsInitialized()
m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
m_watchersWindow = new WatchWindow(WatchWindow::WatchersType);
m_watchersWindow->setObjectName(QLatin1String("CppDebugWatchers"));
m_scriptConsoleWindow = new ScriptConsole;
m_scriptConsoleWindow = new QmlJSScriptConsoleWidget;
m_scriptConsoleWindow->setWindowTitle(tr("QML Script Console"));
m_scriptConsoleWindow->setObjectName(DOCKWIDGET_QML_SCRIPTCONSOLE);
connect(m_scriptConsoleWindow, SIGNAL(expressionEntered(QString)),
SLOT(scriptExpressionEntered(QString)));
connect(m_scriptConsoleWindow, SIGNAL(evaluateExpression(QString)),
SLOT(evaluateExpression(QString)));
// Snapshot
m_snapshotHandler = new SnapshotHandler;
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.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 info@qt.nokia.com.
**
**************************************************************************/
#include "interactiveinterpreter.h"
namespace Debugger {
namespace Internal {
bool InteractiveInterpreter::canEvaluate()
{
int yyaction = 0;
int yytoken = -1;
int yytos = -1;
setCode(m_code, 1);
m_tokens.append(T_FEED_JS_PROGRAM);
do {
if (++yytos == m_stateStack.size())
m_stateStack.resize(m_stateStack.size() * 2);
m_stateStack[yytos] = yyaction;
again:
if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT) {
if (m_tokens.isEmpty())
yytoken = lex();
else
yytoken = m_tokens.takeFirst();
}
yyaction = t_action(yyaction, yytoken);
if (yyaction > 0) {
if (yyaction == ACCEPT_STATE) {
--yytos;
return true;
}
yytoken = -1;
} else if (yyaction < 0) {
const int ruleno = -yyaction - 1;
yytos -= rhs[ruleno];
yyaction = nt_action(m_stateStack[yytos], lhs[ruleno] - TERMINAL_COUNT);
}
} while (yyaction);
const int errorState = m_stateStack[yytos];
if (t_action(errorState, T_AUTOMATIC_SEMICOLON) && canInsertAutomaticSemicolon(yytoken)) {
yyaction = errorState;
m_tokens.prepend(yytoken);
yytoken = T_SEMICOLON;
goto again;
}
if (yytoken != EOF_SYMBOL)
return true;
return false;
}
}
}
......@@ -30,57 +30,42 @@
**
**************************************************************************/
#ifndef QMLJSSCRIPTCONSOLE_H
#define QMLJSSCRIPTCONSOLE_H
#ifndef INTERACTIVEINTERPRETER_H
#define INTERACTIVEINTERPRETER_H
#include <QtGui/QWidget>
#include <QtGui/QToolButton>
#include <QtGui/QPlainTextEdit>
#include <qmljs/parser/qmljslexer_p.h>
#include <qmljs/parser/qmljsengine_p.h>
#include <utils/fancylineedit.h>
namespace QmlJSEditor {
class Highlighter;
}
#include <QtCore/QVector>
#include <QtCore/QString>
#include <QtCore/QList>
namespace Debugger {
namespace Internal {
class ScriptConsole : public QWidget
class InteractiveInterpreter: QmlJS::Lexer
{
Q_OBJECT
public:
ScriptConsole(QWidget *parent = 0);
public slots:
void appendResult(const QString &result);
signals:
void expressionEntered(const QString &expr);
protected slots:
void clearTextEditor();
void executeExpression();
InteractiveInterpreter()
: Lexer(&m_engine),
m_stateStack(128)
{
protected:
bool eventFilter(QObject *obj, QEvent *event);
void setFontSettings();
void clear();
}
// QToolButton *m_clearButton;
QPlainTextEdit *m_textEdit;
Utils::FancyLineEdit *m_lineEdit;
QString m_prompt;
QString m_expr;
QString m_lastExpr;
void clearText() { m_code.clear(); }
void appendText(const QString &text) { m_code += text; }
QString m_title;
QmlJSEditor::Highlighter *m_highlighter;
QString code() const { return m_code; }
bool canEvaluate();
private:
QmlJS::Engine m_engine;
QVector<int> m_stateStack;
QList<int> m_tokens;
QString m_code;
};
}
} //end namespaces
#endif
}
#endif // INTERACTIVEINTERPRETER_H
include($$PWD/../../../libs/qmljsdebugclient/qmljsdebugclient.pri)
include($$PWD/../../../libs/qmljs/parser/parser.pri)
include($$PWD/../../../shared/json/json.pri)
DEFINES += JSON_INCLUDE_PRI
......@@ -8,15 +9,18 @@ HEADERS += \
$$PWD/qmldebuggerclient.h \
$$PWD/qmljsprivateapi.h \
$$PWD/qmlcppengine.h \
$$PWD/scriptconsole.h \
$$PWD/qmljsscriptconsole.h \
$$PWD/qscriptdebuggerclient.h \
$$PWD/qmlv8debuggerclient.h
$$PWD/qmlv8debuggerclient.h \
$$PWD/interactiveinterpreter.h
SOURCES += \
$$PWD/qmlengine.cpp \
$$PWD/qmladapter.cpp \
$$PWD/qmldebuggerclient.cpp \
$$PWD/qmlcppengine.cpp \
$$PWD/scriptconsole.cpp \
$$PWD/qmljsscriptconsole.cpp \
$$PWD/qscriptdebuggerclient.cpp \
$$PWD/qmlv8debuggerclient.cpp
$$PWD/qmlv8debuggerclient.cpp \
$$PWD/interactiveinterpreter.cpp
......@@ -54,7 +54,9 @@ public:
explicit QmlAdapterPrivate(DebuggerEngine *engine)
: m_engine(engine)
, m_qmlClient(0)
, m_engineDebugClient(0)
, m_conn(0)
, m_currentSelectedDebugId(-1)
{
m_connectionTimer.setInterval(4000);
m_connectionTimer.setSingleShot(true);
......@@ -62,9 +64,12 @@ public:
QWeakPointer<DebuggerEngine> m_engine;
QmlDebuggerClient *m_qmlClient;
QmlJsDebugClient::QDeclarativeEngineDebug *m_engineDebugClient;
QTimer m_connectionTimer;
QDeclarativeDebugConnection *m_conn;
QHash<QString, QmlDebuggerClient*> debugClients;
int m_currentSelectedDebugId;
QString m_currentSelectedDebugName;
};
} // namespace Internal
......@@ -272,6 +277,34 @@ QHash<QString, Internal::QmlDebuggerClient*> QmlAdapter::debuggerClients()
{
return d->debugClients;
}
QmlJsDebugClient::QDeclarativeEngineDebug *QmlAdapter::engineDebugClient() const
{
return d->m_engineDebugClient;
}
void QmlAdapter::setEngineDebugClient(QmlJsDebugClient::QDeclarativeEngineDebug *client)
{
d->m_engineDebugClient = client;
}
int QmlAdapter::currentSelectedDebugId() const
{
return d->m_currentSelectedDebugId;
}
QString QmlAdapter::currentSelectedDisplayName() const
{
return d->m_currentSelectedDebugName;
}
void QmlAdapter::setCurrentSelectedDebugInfo(int currentDebugId, const QString &displayName)
{
d->m_currentSelectedDebugId = currentDebugId;
d->m_currentSelectedDebugName = displayName;
emit selectionChanged();
}
void QmlAdapter::logServiceStatusChange(const QString &service,
QDeclarativeDebugClient::Status newStatus)
{
......
......@@ -73,6 +73,13 @@ public:
Internal::QmlDebuggerClient *activeDebuggerClient();
QHash<QString, Internal::QmlDebuggerClient*> debuggerClients();
QmlJsDebugClient::QDeclarativeEngineDebug *engineDebugClient() const;
void setEngineDebugClient(QmlJsDebugClient::QDeclarativeEngineDebug *client);
int currentSelectedDebugId() const;
QString currentSelectedDisplayName() const;
void setCurrentSelectedDebugInfo(int debugId, const QString &displayName = QString());
public slots:
void logServiceStatusChange(const QString &service, QDeclarativeDebugClient::Status newStatus);
void logServiceActivity(const QString &service, const QString &logMessage);
......@@ -83,6 +90,7 @@ signals:
void connectionStartupFailed();
void connectionError(QAbstractSocket::SocketError socketError);
void serviceConnectionError(const QString serviceName);
void selectionChanged();
private slots:
void connectionErrorOccurred(QAbstractSocket::SocketError socketError);
......
......@@ -811,6 +811,11 @@ void QmlEngine::logMessage(LogDirection direction, const QString &message)
showMessage(msg, LogDebug);
}
QmlAdapter *QmlEngine::adapter() const
{
return &d->m_adapter;
}
QmlEngine *createQmlEngine(const DebuggerStartParameters &sp,
DebuggerEngine *masterEngine)
{
......
......@@ -40,6 +40,9 @@
#include <QtNetwork/QAbstractSocket>
namespace Debugger {
class QmlAdapter;
namespace Internal {
class QmlEnginePrivate;
......@@ -71,6 +74,8 @@ public:
void logMessage(LogDirection direction, const QString &str);
QmlAdapter *adapter() const;
public slots:
void disconnected();
......
This diff is collapsed.
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.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 info@qt.nokia.com.
**
**************************************************************************/
#ifndef QMLJSSCRIPTCONSOLE_H
#define QMLJSSCRIPTCONSOLE_H
#include <qmljsdebugclient/qdeclarativeenginedebug.h>
#include <QtGui/QPlainTextEdit>
namespace Utils {
class StatusLabel;
}
namespace Debugger {
class QmlAdapter;
namespace Internal {
class QmlJSScriptConsolePrivate;
class QmlJSScriptConsole;
class QmlJSScriptConsoleWidget : public QWidget
{
Q_OBJECT
public:
QmlJSScriptConsoleWidget(QWidget *parent = 0);
void setQmlAdapter(QmlAdapter *adapter);
void setInferiorStopped(bool inferiorStopped);
public slots:
void appendResult(const QString &result);
signals:
void evaluateExpression(const QString &expr);
private:
QmlJSScriptConsole *m_console;
Utils::StatusLabel *m_statusLabel;
};
class QmlJSScriptConsole : public QPlainTextEdit
{
Q_OBJECT
public:
explicit QmlJSScriptConsole(QWidget *parent = 0);
~QmlJSScriptConsole();
inline void setTitle(const QString &title)
{ setDocumentTitle(title); }
inline QString title() const
{ return documentTitle(); }
void setPrompt(const QString &prompt);
QString prompt() const;
void setInferiorStopped(bool inferiorStopped);
void setQmlAdapter(QmlAdapter *adapter);
void appendResult(const QString &result);
public slots:
void clear();
void onStateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State);
void onSelectionChanged();
protected:
void keyPressEvent(QKeyEvent *e);
void contextMenuEvent(QContextMenuEvent *event);
void mouseReleaseEvent(QMouseEvent *e);
signals:
void evaluateExpression(const QString &expr);
void updateStatusMessage(const QString &message, int timeoutMS);
private slots:
void onCursorPositionChanged();
private:
void displayPrompt();
void handleReturnKey();
void handleUpKey();
void handleDownKey();
void handleHomeKey();
QString getCurrentScript() const;
void replaceCurrentScript(const QString &script);
bool isEditableArea() const;
private:
QmlJSScriptConsolePrivate *d;
};
} //Internal
} //Debugger
#endif
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.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 info@qt.nokia.com.
**
**************************************************************************/
#include "scriptconsole.h"
#include <QtCore/QDebug>
#include <QtGui/QVBoxLayout>
#include <QtGui/QDockWidget>
#include <qmljseditor/qmljshighlighter.h>
#include <utils/styledbar.h>
#include <utils/filterlineedit.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/texteditorsettings.h>
namespace Debugger {
namespace Internal {
ScriptConsole::ScriptConsole(QWidget *parent)
: QWidget(parent),
m_textEdit(new QPlainTextEdit),
m_lineEdit(0)
{
// m_prompt = QLatin1String(">");
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(m_textEdit);
m_textEdit->setFrameStyle(QFrame::NoFrame);
//updateTitle();
/*m_highlighter = new QmlJSEditor::Highlighter(m_textEdit->document());
m_highlighter->setParent(m_textEdit->document());*/
Utils::StyledBar *bar = new Utils::StyledBar;
m_lineEdit = new Utils::FilterLineEdit;
m_lineEdit->setPlaceholderText(tr("<Type expression to evaluate>"));
m_lineEdit->setToolTip(tr("Write and evaluate QtScript expressions."));
/*m_clearButton = new QToolButton();
m_clearButton->setToolTip(tr("Clear Output"));
m_clearButton->setIcon(QIcon(Core::Constants::ICON_CLEAN_PANE));
connect(m_clearButton, SIGNAL(clicked()), this, SLOT(clearTextEditor()));*/
//connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(changeContextHelpId(QString)));
connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression()));
QHBoxLayout *hbox = new QHBoxLayout(bar);
hbox->setMargin(1);
hbox->setSpacing(1);
hbox->addWidget(m_lineEdit);
//hbox->addWidget(m_clearButton);
layout->addWidget(bar);
m_textEdit->setReadOnly(true);
m_lineEdit->installEventFilter(this);