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: ...@@ -170,7 +170,7 @@ public:
bool isWaiting() const; bool isWaiting() const;
Q_SIGNALS: Q_SIGNALS:
void stateChanged(QDeclarativeDebugQuery::State); void stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State);
protected: protected:
QDeclarativeDebugQuery(QObject *); QDeclarativeDebugQuery(QObject *);
......
...@@ -6,3 +6,4 @@ include(../../plugins/texteditor/texteditor.pri) ...@@ -6,3 +6,4 @@ include(../../plugins/texteditor/texteditor.pri)
include(../../libs/cplusplus/cplusplus.pri) include(../../libs/cplusplus/cplusplus.pri)
include(../../libs/utils/utils.pri) include(../../libs/utils/utils.pri)
include(../../libs/symbianutils/symbianutils.pri) include(../../libs/symbianutils/symbianutils.pri)
include(../../libs/qmljs/qmljs.pri)
...@@ -112,7 +112,7 @@ ...@@ -112,7 +112,7 @@
#include <utils/statuslabel.h> #include <utils/statuslabel.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <qml/scriptconsole.h> #include <qml/qmljsscriptconsole.h>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QtPlugin> #include <QtCore/QtPlugin>
...@@ -785,7 +785,7 @@ public slots: ...@@ -785,7 +785,7 @@ public slots:
void aboutToSaveSession(); void aboutToSaveSession();
void executeDebuggerCommand(const QString &command); void executeDebuggerCommand(const QString &command);
void scriptExpressionEntered(const QString &expression); void evaluateExpression(const QString &expression);
void coreShutdown(); void coreShutdown();
public slots: public slots:
...@@ -1079,7 +1079,7 @@ public: ...@@ -1079,7 +1079,7 @@ public:
QAbstractItemView *m_stackWindow; QAbstractItemView *m_stackWindow;
QAbstractItemView *m_threadsWindow; QAbstractItemView *m_threadsWindow;
LogWindow *m_logWindow; LogWindow *m_logWindow;
ScriptConsole *m_scriptConsoleWindow; QmlJSScriptConsoleWidget *m_scriptConsoleWindow;
bool m_busy; bool m_busy;
QString m_lastPermanentStatusMessage; QString m_lastPermanentStatusMessage;
...@@ -1972,6 +1972,16 @@ void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine) ...@@ -1972,6 +1972,16 @@ void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine)
//m_threadBox->setModel(engine->threadsModel()); //m_threadBox->setModel(engine->threadsModel());
//m_threadBox->setModelColumn(ThreadData::ComboNameColumn); //m_threadBox->setModelColumn(ThreadData::ComboNameColumn);
m_watchersWindow->setModel(engine->watchersModel()); 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(); engine->watchHandler()->rebuildModel();
} }
...@@ -2047,7 +2057,6 @@ void DebuggerPluginPrivate::setBusyCursor(bool busy) ...@@ -2047,7 +2057,6 @@ void DebuggerPluginPrivate::setBusyCursor(bool busy)
m_threadsWindow->setCursor(cursor); m_threadsWindow->setCursor(cursor);
m_watchersWindow->setCursor(cursor); m_watchersWindow->setCursor(cursor);
m_snapshotWindow->setCursor(cursor); m_snapshotWindow->setCursor(cursor);
m_scriptConsoleWindow->setCursor(cursor);
} }
void DebuggerPluginPrivate::setInitialState() void DebuggerPluginPrivate::setInitialState()
...@@ -2239,8 +2248,11 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) ...@@ -2239,8 +2248,11 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
if (qmlCppEngine) if (qmlCppEngine)
qmlEngine = qobject_cast<QmlEngine *>(qmlCppEngine->qmlEngine()); qmlEngine = qobject_cast<QmlEngine *>(qmlCppEngine->qmlEngine());
if (qmlEngine) { if (qmlEngine && (state == InferiorRunOk || state == InferiorStopOk)) {
m_scriptConsoleWindow->setEnabled(stopped); 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) ...@@ -2387,7 +2399,7 @@ void DebuggerPluginPrivate::showStatusMessage(const QString &msg0, int timeout)
m_statusLabel->showStatusMessage(msg, timeout); m_statusLabel->showStatusMessage(msg, timeout);
} }
void DebuggerPluginPrivate::scriptExpressionEntered(const QString &expression) void DebuggerPluginPrivate::evaluateExpression(const QString &expression)
{ {
currentEngine()->executeDebuggerCommand(expression); currentEngine()->executeDebuggerCommand(expression);
} }
...@@ -2757,11 +2769,11 @@ void DebuggerPluginPrivate::extensionsInitialized() ...@@ -2757,11 +2769,11 @@ void DebuggerPluginPrivate::extensionsInitialized()
m_localsWindow->setObjectName(QLatin1String("CppDebugLocals")); m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
m_watchersWindow = new WatchWindow(WatchWindow::WatchersType); m_watchersWindow = new WatchWindow(WatchWindow::WatchersType);
m_watchersWindow->setObjectName(QLatin1String("CppDebugWatchers")); m_watchersWindow->setObjectName(QLatin1String("CppDebugWatchers"));
m_scriptConsoleWindow = new ScriptConsole; m_scriptConsoleWindow = new QmlJSScriptConsoleWidget;
m_scriptConsoleWindow->setWindowTitle(tr("QML Script Console")); m_scriptConsoleWindow->setWindowTitle(tr("QML Script Console"));
m_scriptConsoleWindow->setObjectName(DOCKWIDGET_QML_SCRIPTCONSOLE); m_scriptConsoleWindow->setObjectName(DOCKWIDGET_QML_SCRIPTCONSOLE);
connect(m_scriptConsoleWindow, SIGNAL(expressionEntered(QString)), connect(m_scriptConsoleWindow, SIGNAL(evaluateExpression(QString)),
SLOT(scriptExpressionEntered(QString))); SLOT(evaluateExpression(QString)));
// Snapshot // Snapshot
m_snapshotHandler = new SnapshotHandler; 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 @@ ...@@ -30,57 +30,42 @@
** **
**************************************************************************/ **************************************************************************/
#ifndef QMLJSSCRIPTCONSOLE_H #ifndef INTERACTIVEINTERPRETER_H
#define QMLJSSCRIPTCONSOLE_H #define INTERACTIVEINTERPRETER_H
#include <QtGui/QWidget> #include <qmljs/parser/qmljslexer_p.h>
#include <QtGui/QToolButton> #include <qmljs/parser/qmljsengine_p.h>
#include <QtGui/QPlainTextEdit>
#include <utils/fancylineedit.h> #include <QtCore/QVector>
#include <QtCore/QString>
namespace QmlJSEditor { #include <QtCore/QList>
class Highlighter;
}
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class ScriptConsole : public QWidget class InteractiveInterpreter: QmlJS::Lexer
{ {
Q_OBJECT
public: public:
ScriptConsole(QWidget *parent = 0); InteractiveInterpreter()
: Lexer(&m_engine),
public slots: m_stateStack(128)
void appendResult(const QString &result); {
signals:
void expressionEntered(const QString &expr);
protected slots:
void clearTextEditor();
void executeExpression();
protected: }
bool eventFilter(QObject *obj, QEvent *event);
void setFontSettings();
void clear();
// QToolButton *m_clearButton; void clearText() { m_code.clear(); }
QPlainTextEdit *m_textEdit; void appendText(const QString &text) { m_code += text; }
Utils::FancyLineEdit *m_lineEdit;
QString m_prompt;
QString m_expr;
QString m_lastExpr;
QString m_title; QString code() const { return m_code; }
QmlJSEditor::Highlighter *m_highlighter; bool canEvaluate();
private:
QmlJS::Engine m_engine;
QVector<int> m_stateStack;
QList<int> m_tokens;
QString m_code;
}; };
} }
} //end namespaces }
#endif // INTERACTIVEINTERPRETER_H
#endif
include($$PWD/../../../libs/qmljsdebugclient/qmljsdebugclient.pri) include($$PWD/../../../libs/qmljsdebugclient/qmljsdebugclient.pri)
include($$PWD/../../../libs/qmljs/parser/parser.pri)
include($$PWD/../../../shared/json/json.pri) include($$PWD/../../../shared/json/json.pri)
DEFINES += JSON_INCLUDE_PRI DEFINES += JSON_INCLUDE_PRI
...@@ -8,15 +9,18 @@ HEADERS += \ ...@@ -8,15 +9,18 @@ HEADERS += \
$$PWD/qmldebuggerclient.h \ $$PWD/qmldebuggerclient.h \
$$PWD/qmljsprivateapi.h \ $$PWD/qmljsprivateapi.h \
$$PWD/qmlcppengine.h \ $$PWD/qmlcppengine.h \
$$PWD/scriptconsole.h \ $$PWD/qmljsscriptconsole.h \
$$PWD/qscriptdebuggerclient.h \ $$PWD/qscriptdebuggerclient.h \
$$PWD/qmlv8debuggerclient.h $$PWD/qmlv8debuggerclient.h \
$$PWD/interactiveinterpreter.h
SOURCES += \ SOURCES += \
$$PWD/qmlengine.cpp \ $$PWD/qmlengine.cpp \
$$PWD/qmladapter.cpp \ $$PWD/qmladapter.cpp \
$$PWD/qmldebuggerclient.cpp \ $$PWD/qmldebuggerclient.cpp \
$$PWD/qmlcppengine.cpp \ $$PWD/qmlcppengine.cpp \
$$PWD/scriptconsole.cpp \ $$PWD/qmljsscriptconsole.cpp \
$$PWD/qscriptdebuggerclient.cpp \ $$PWD/qscriptdebuggerclient.cpp \
$$PWD/qmlv8debuggerclient.cpp $$PWD/qmlv8debuggerclient.cpp \
$$PWD/interactiveinterpreter.cpp
...@@ -54,7 +54,9 @@ public: ...@@ -54,7 +54,9 @@ public:
explicit QmlAdapterPrivate(DebuggerEngine *engine) explicit QmlAdapterPrivate(DebuggerEngine *engine)
: m_engine(engine) : m_engine(engine)
, m_qmlClient(0) , m_qmlClient(0)
, m_engineDebugClient(0)
, m_conn(0) , m_conn(0)
, m_currentSelectedDebugId(-1)
{ {
m_connectionTimer.setInterval(4000); m_connectionTimer.setInterval(4000);
m_connectionTimer.setSingleShot(true); m_connectionTimer.setSingleShot(true);
...@@ -62,9 +64,12 @@ public: ...@@ -62,9 +64,12 @@ public:
QWeakPointer<DebuggerEngine> m_engine; QWeakPointer<DebuggerEngine> m_engine;
QmlDebuggerClient *m_qmlClient; QmlDebuggerClient *m_qmlClient;
QmlJsDebugClient::QDeclarativeEngineDebug *m_engineDebugClient;
QTimer m_connectionTimer; QTimer m_connectionTimer;
QDeclarativeDebugConnection *m_conn; QDeclarativeDebugConnection *m_conn;
QHash<QString, QmlDebuggerClient*> debugClients; QHash<QString, QmlDebuggerClient*> debugClients;
int m_currentSelectedDebugId;
QString m_currentSelectedDebugName;
}; };
} // namespace Internal } // namespace Internal
...@@ -272,6 +277,34 @@ QHash<QString, Internal::QmlDebuggerClient*> QmlAdapter::debuggerClients() ...@@ -272,6 +277,34 @@ QHash<QString, Internal::QmlDebuggerClient*> QmlAdapter::debuggerClients()
{ {
return d->debugClients; 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, void QmlAdapter::logServiceStatusChange(const QString &service,
QDeclarativeDebugClient::Status newStatus) QDeclarativeDebugClient::Status newStatus)
{ {
......
...@@ -73,6 +73,13 @@ public: ...@@ -73,6 +73,13 @@ public:
Internal::QmlDebuggerClient *activeDebuggerClient(); Internal::QmlDebuggerClient *activeDebuggerClient();
QHash<QString, Internal::QmlDebuggerClient*> debuggerClients(); 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: public slots:
void logServiceStatusChange(const QString &service, QDeclarativeDebugClient::Status newStatus); void logServiceStatusChange(const QString &service, QDeclarativeDebugClient::Status newStatus);
void logServiceActivity(const QString &service, const QString &logMessage); void logServiceActivity(const QString &service, const QString &logMessage);
...@@ -83,6 +90,7 @@ signals: ...@@ -83,6 +90,7 @@ signals:
void connectionStartupFailed(); void connectionStartupFailed();
void connectionError(QAbstractSocket::SocketError socketError); void connectionError(QAbstractSocket::SocketError socketError);
void serviceConnectionError(const QString serviceName); void serviceConnectionError(const QString serviceName);
void selectionChanged();
private slots: private slots:
void connectionErrorOccurred(QAbstractSocket::SocketError socketError); void connectionErrorOccurred(QAbstractSocket::SocketError socketError);
......
...@@ -676,7 +676,7 @@ void QmlEngine::requestModuleSymbols(const QString &moduleName) ...@@ -676,7 +676,7 @@ void QmlEngine::requestModuleSymbols(const QString &moduleName)
bool QmlEngine::setToolTipExpression(const QPoint &mousePos, bool QmlEngine::setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor *editor, const DebuggerToolTipContext &ctx) TextEditor::ITextEditor *editor, const DebuggerToolTipContext &ctx)
{ {
// This is processed by QML inspector, which has dependencies to // This is processed by QML inspector, which has dependencies to
// the qml js editor. Makes life easier. // the qml js editor. Makes life easier.
emit tooltipRequested(mousePos, editor, ctx.position); emit tooltipRequested(mousePos, editor, ctx.position);
return true; return true;
...@@ -811,6 +811,11 @@ void QmlEngine::logMessage(LogDirection direction, const QString &message) ...@@ -811,6 +811,11 @@ void QmlEngine::logMessage(LogDirection direction, const QString &message)
showMessage(msg, LogDebug); showMessage(msg, LogDebug);
} }
QmlAdapter *QmlEngine::adapter() const
{
return &d->m_adapter;
}
QmlEngine *createQmlEngine(const DebuggerStartParameters &sp, QmlEngine *createQmlEngine(const DebuggerStartParameters &sp,
DebuggerEngine *masterEngine) DebuggerEngine *masterEngine)
{ {
......
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
#include <QtNetwork/QAbstractSocket> #include <QtNetwork/QAbstractSocket>
namespace Debugger { namespace Debugger {
class QmlAdapter;
namespace Internal { namespace Internal {
class QmlEnginePrivate; class QmlEnginePrivate;
...@@ -71,6 +74,8 @@ public: ...@@ -71,6 +74,8 @@ public:
void logMessage(LogDirection direction, const QString &str); void logMessage(LogDirection direction, const QString &str);
QmlAdapter *adapter() const;
public slots: public slots:
void disconnected(); void disconnected();
......
/**************************************************************************
**
** 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 "qmljsscriptconsole.h"
#include "interactiveinterpreter.h"
#include "qmladapter.h"
#include "debuggerstringutils.h"
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorsettings.h>
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/coreconstants.h>
#include <utils/statuslabel.h>
#include <QtGui/QMenu>
#include <QtGui/QTextBlock>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QToolButton>
namespace Debugger {
namespace Internal {
class QmlJSScriptConsolePrivate
{
public:
QmlJSScriptConsolePrivate()
: prompt(QLatin1String("> ")),
startOfEditableArea(-1),
lastKnownPosition(0),
inferiorStopped(false)
{
resetCache();
}
void resetCache();
void appendToHistory(const QString &script);
bool canEvaluateScript(const QString &script);