forked from qt-creator/qt-creator
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: Roberto Raggi <roberto.raggi@nokia.com> Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
90
src/plugins/debugger/qml/interactiveinterpreter.cpp
Normal file
90
src/plugins/debugger/qml/interactiveinterpreter.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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);
|
||||
InteractiveInterpreter()
|
||||
: Lexer(&m_engine),
|
||||
m_stateStack(128)
|
||||
{
|
||||
|
||||
public slots:
|
||||
void appendResult(const QString &result);
|
||||
signals:
|
||||
void expressionEntered(const QString &expr);
|
||||
}
|
||||
|
||||
protected slots:
|
||||
void clearTextEditor();
|
||||
void executeExpression();
|
||||
void clearText() { m_code.clear(); }
|
||||
void appendText(const QString &text) { m_code += text; }
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
@@ -1,4 +1,5 @@
|
||||
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);
|
||||
|
||||
@@ -676,7 +676,7 @@ void QmlEngine::requestModuleSymbols(const QString &moduleName)
|
||||
bool QmlEngine::setToolTipExpression(const QPoint &mousePos,
|
||||
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.
|
||||
emit tooltipRequested(mousePos, editor, ctx.position);
|
||||
return true;
|
||||
@@ -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();
|
||||
|
||||
|
||||
552
src/plugins/debugger/qml/qmljsscriptconsole.cpp
Normal file
552
src/plugins/debugger/qml/qmljsscriptconsole.cpp
Normal file
@@ -0,0 +1,552 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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);
|
||||
|
||||
QWeakPointer<QmlAdapter> adapter;
|
||||
|
||||
QString prompt;
|
||||
int startOfEditableArea;
|
||||
int lastKnownPosition;
|
||||
|
||||
QStringList scriptHistory;
|
||||
int scriptHistoryIndex;
|
||||
|
||||
InteractiveInterpreter interpreter;
|
||||
|
||||
bool inferiorStopped;
|
||||
QList<QTextEdit::ExtraSelection> selections;
|
||||
};
|
||||
|
||||
void QmlJSScriptConsolePrivate::resetCache()
|
||||
{
|
||||
scriptHistory.clear();
|
||||
scriptHistory.append(QLatin1String(""));
|
||||
scriptHistoryIndex = scriptHistory.count();
|
||||
|
||||
selections.clear();
|
||||
}
|
||||
|
||||
void QmlJSScriptConsolePrivate::appendToHistory(const QString &script)
|
||||
{
|
||||
scriptHistoryIndex = scriptHistory.count();
|
||||
scriptHistory.replace(scriptHistoryIndex - 1,script);
|
||||
scriptHistory.append(QLatin1String(""));
|
||||
scriptHistoryIndex = scriptHistory.count();
|
||||
}
|
||||
|
||||
bool QmlJSScriptConsolePrivate::canEvaluateScript(const QString &script)
|
||||
{
|
||||
interpreter.clearText();
|
||||
interpreter.appendText(script);
|
||||
return interpreter.canEvaluate();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// QmlJSScriptConsoleWidget
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
QmlJSScriptConsoleWidget::QmlJSScriptConsoleWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *vbox = new QVBoxLayout(this);
|
||||
vbox->setMargin(0);
|
||||
vbox->setSpacing(0);
|
||||
|
||||
QWidget *statusbarContainer = new QWidget;
|
||||
|
||||
QHBoxLayout *hbox = new QHBoxLayout(statusbarContainer);
|
||||
hbox->setMargin(0);
|
||||
hbox->setSpacing(0);
|
||||
|
||||
//Clear Button
|
||||
QToolButton *clearButton = new QToolButton;
|
||||
QAction *clearAction = new QAction(tr("Clear Console"), this);
|
||||
clearAction->setIcon(QIcon(_(Core::Constants::ICON_CLEAN_PANE)));
|
||||
|
||||
clearButton->setDefaultAction(clearAction);
|
||||
|
||||
//Status Label
|
||||
m_statusLabel = new Utils::StatusLabel;
|
||||
|
||||
hbox->addWidget(m_statusLabel, 20, Qt::AlignLeft);
|
||||
hbox->addWidget(clearButton, 0, Qt::AlignRight);
|
||||
|
||||
m_console = new QmlJSScriptConsole;
|
||||
connect(m_console, SIGNAL(evaluateExpression(QString)), this,
|
||||
SIGNAL(evaluateExpression(QString)));
|
||||
connect(m_console, SIGNAL(updateStatusMessage(const QString &, int)), m_statusLabel,
|
||||
SLOT(showStatusMessage(const QString &, int)));
|
||||
connect(clearAction, SIGNAL(triggered()), m_console, SLOT(clear()));
|
||||
vbox->addWidget(statusbarContainer);
|
||||
vbox->addWidget(m_console);
|
||||
|
||||
}
|
||||
|
||||
void QmlJSScriptConsoleWidget::setQmlAdapter(QmlAdapter *adapter)
|
||||
{
|
||||
m_console->setQmlAdapter(adapter);
|
||||
}
|
||||
|
||||
void QmlJSScriptConsoleWidget::setInferiorStopped(bool inferiorStopped)
|
||||
{
|
||||
m_console->setInferiorStopped(inferiorStopped);
|
||||
}
|
||||
|
||||
void QmlJSScriptConsoleWidget::appendResult(const QString &result)
|
||||
{
|
||||
m_console->appendResult(result);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// QmlJSScriptConsole
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
QmlJSScriptConsole::QmlJSScriptConsole(QWidget *parent)
|
||||
: QPlainTextEdit(parent),
|
||||
d(new QmlJSScriptConsolePrivate())
|
||||
{
|
||||
connect(this, SIGNAL(cursorPositionChanged()), SLOT(onCursorPositionChanged()));
|
||||
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
setUndoRedoEnabled(false);
|
||||
setBackgroundVisible(false);
|
||||
const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::instance()->fontSettings();
|
||||
setFont(fs.font());
|
||||
|
||||
displayPrompt();
|
||||
}
|
||||
|
||||
QmlJSScriptConsole::~QmlJSScriptConsole()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::setPrompt(const QString &prompt)
|
||||
{
|
||||
d->prompt = prompt;
|
||||
}
|
||||
|
||||
QString QmlJSScriptConsole::prompt() const
|
||||
{
|
||||
return d->prompt;
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::setInferiorStopped(bool inferiorStopped)
|
||||
{
|
||||
d->inferiorStopped = inferiorStopped;
|
||||
onSelectionChanged();
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::setQmlAdapter(QmlAdapter *adapter)
|
||||
{
|
||||
d->adapter = adapter;
|
||||
clear();
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::appendResult(const QString &result)
|
||||
{
|
||||
QString currentScript = getCurrentScript();
|
||||
d->appendToHistory(currentScript);
|
||||
|
||||
QTextCursor cur = textCursor();
|
||||
cur.movePosition(QTextCursor::EndOfLine);
|
||||
cur.insertText(QLatin1String("\n"));
|
||||
cur.insertText(result);
|
||||
cur.movePosition(QTextCursor::EndOfLine);
|
||||
cur.insertText(QLatin1String("\n"));
|
||||
setTextCursor(cur);
|
||||
displayPrompt();
|
||||
|
||||
QTextEdit::ExtraSelection sel;
|
||||
|
||||
QTextCharFormat resultFormat;
|
||||
resultFormat.setForeground(QBrush(QColor(Qt::darkGray)));
|
||||
|
||||
QTextCursor c(document()->findBlockByNumber(cur.blockNumber()-1));
|
||||
c.movePosition(QTextCursor::StartOfBlock);
|
||||
c.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
|
||||
|
||||
sel.format = resultFormat;
|
||||
sel.cursor = c;
|
||||
|
||||
d->selections.append(sel);
|
||||
|
||||
setExtraSelections(d->selections);
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::clear()
|
||||
{
|
||||
d->resetCache();
|
||||
|
||||
QPlainTextEdit::clear();
|
||||
displayPrompt();
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::onStateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State state)
|
||||
{
|
||||
QDeclarativeDebugExpressionQuery *query = qobject_cast<QDeclarativeDebugExpressionQuery *>(sender());
|
||||
bool gotResult = false;
|
||||
if (query && state != QDeclarativeDebugQuery::Error) {
|
||||
QString result(query->result().toString());
|
||||
if (result != QLatin1String("<undefined>")) {
|
||||
appendResult(result);
|
||||
gotResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gotResult) {
|
||||
QString currentScript = getCurrentScript();
|
||||
if (d->canEvaluateScript(currentScript)) {
|
||||
emit evaluateExpression(currentScript);
|
||||
} else {
|
||||
QPlainTextEdit::appendPlainText(QLatin1String(""));
|
||||
moveCursor(QTextCursor::EndOfLine);
|
||||
}
|
||||
}
|
||||
delete query;
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::onSelectionChanged()
|
||||
{
|
||||
if (!d->adapter.isNull()) {
|
||||
QString status;
|
||||
if (!d->inferiorStopped) {
|
||||
status.append(tr("Current Selected Object: "));
|
||||
status.append(d->adapter.data()->currentSelectedDisplayName());
|
||||
}
|
||||
emit updateStatusMessage(status, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
bool keyConsumed = false;
|
||||
switch (e->key()) {
|
||||
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
if (isEditableArea()) {
|
||||
handleReturnKey();
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Backspace: {
|
||||
QTextCursor cursor = textCursor();
|
||||
bool hasSelection = cursor.hasSelection();
|
||||
int selectionStart = cursor.selectionStart();
|
||||
if ((hasSelection && selectionStart < d->startOfEditableArea)
|
||||
|| (!hasSelection && selectionStart == d->startOfEditableArea)) {
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_Delete:
|
||||
if (textCursor().selectionStart() < d->startOfEditableArea) {
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
keyConsumed = true;
|
||||
break;
|
||||
|
||||
case Qt::Key_Left:
|
||||
if (textCursor().position() == d->startOfEditableArea) {
|
||||
keyConsumed = true;
|
||||
} else if (e->modifiers() & Qt::ControlModifier && isEditableArea()) {
|
||||
handleHomeKey();
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
if (isEditableArea()) {
|
||||
handleUpKey();
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
if (isEditableArea()) {
|
||||
handleDownKey();
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Home:
|
||||
if (isEditableArea()) {
|
||||
handleHomeKey();
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_C:
|
||||
case Qt::Key_Insert: {
|
||||
//Fair to assume that for any selection beyond startOfEditableArea
|
||||
//only copy function is allowed.
|
||||
QTextCursor cursor = textCursor();
|
||||
bool hasSelection = cursor.hasSelection();
|
||||
int selectionStart = cursor.selectionStart();
|
||||
if (hasSelection && selectionStart < d->startOfEditableArea) {
|
||||
if (!(e->modifiers() & Qt::ControlModifier))
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
QTextCursor cursor = textCursor();
|
||||
bool hasSelection = cursor.hasSelection();
|
||||
int selectionStart = cursor.selectionStart();
|
||||
if (hasSelection && selectionStart < d->startOfEditableArea) {
|
||||
keyConsumed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keyConsumed)
|
||||
QPlainTextEdit::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
QTextCursor cursor = textCursor();
|
||||
Qt::TextInteractionFlags flags = textInteractionFlags();
|
||||
bool hasSelection = cursor.hasSelection();
|
||||
int selectionStart = cursor.selectionStart();
|
||||
bool canBeEdited = true;
|
||||
if (hasSelection && selectionStart < d->startOfEditableArea) {
|
||||
canBeEdited = false;
|
||||
}
|
||||
|
||||
QMenu *menu = new QMenu();
|
||||
QAction *a;
|
||||
|
||||
if ((flags & Qt::TextEditable) && canBeEdited) {
|
||||
a = menu->addAction(tr("Cut"), this, SLOT(cut()));
|
||||
a->setEnabled(cursor.hasSelection());
|
||||
}
|
||||
|
||||
a = menu->addAction(tr("Copy"), this, SLOT(copy()));
|
||||
a->setEnabled(cursor.hasSelection());
|
||||
|
||||
if ((flags & Qt::TextEditable) && canBeEdited) {
|
||||
a = menu->addAction(tr("Paste"), this, SLOT(paste()));
|
||||
a->setEnabled(canPaste());
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
a = menu->addAction(tr("Select All"), this, SLOT(selectAll()));
|
||||
a->setEnabled(!document()->isEmpty());
|
||||
|
||||
menu->addSeparator();
|
||||
menu->addAction(tr("Clear"), this, SLOT(clear()));
|
||||
|
||||
menu->exec(event->globalPos());
|
||||
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::mouseReleaseEvent(QMouseEvent *e)
|
||||
{
|
||||
QPlainTextEdit::mouseReleaseEvent(e);
|
||||
QTextCursor cursor = textCursor();
|
||||
if (e->button() == Qt::LeftButton && !cursor.hasSelection() && !isEditableArea()) {
|
||||
cursor.setPosition(d->lastKnownPosition);
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::onCursorPositionChanged()
|
||||
{
|
||||
if (!isEditableArea()) {
|
||||
setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
} else {
|
||||
d->lastKnownPosition = textCursor().position();
|
||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::displayPrompt()
|
||||
{
|
||||
d->startOfEditableArea = textCursor().position() + d->prompt.length();
|
||||
QTextCursor cur = textCursor();
|
||||
cur.insertText(d->prompt);
|
||||
cur.movePosition(QTextCursor::EndOfWord);
|
||||
setTextCursor(cur);
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::handleReturnKey()
|
||||
{
|
||||
QString currentScript = getCurrentScript();
|
||||
bool evaluateScript = false;
|
||||
|
||||
//Check if string is only white spaces
|
||||
if (currentScript.trimmed().isEmpty()) {
|
||||
QTextCursor cur = textCursor();
|
||||
cur.movePosition(QTextCursor::EndOfLine);
|
||||
cur.insertText(QLatin1String("\n"));
|
||||
setTextCursor(cur);
|
||||
displayPrompt();
|
||||
evaluateScript = true;
|
||||
}
|
||||
|
||||
if (!evaluateScript && !d->inferiorStopped) {
|
||||
if (!d->adapter.isNull()) {
|
||||
QDeclarativeEngineDebug *engineDebug = d->adapter.data()->engineDebugClient();
|
||||
int id = d->adapter.data()->currentSelectedDebugId();
|
||||
if (engineDebug && id != -1) {
|
||||
QDeclarativeDebugExpressionQuery *query =
|
||||
engineDebug->queryExpressionResult(id, currentScript, this);
|
||||
connect(query, SIGNAL(stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)),
|
||||
this, SLOT(onStateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)));
|
||||
evaluateScript = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!evaluateScript) {
|
||||
if (d->canEvaluateScript(currentScript)) {
|
||||
emit evaluateExpression(currentScript);
|
||||
} else {
|
||||
QPlainTextEdit::appendPlainText(QLatin1String(""));
|
||||
moveCursor(QTextCursor::EndOfLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::handleUpKey()
|
||||
{
|
||||
//get the current script and update in script history
|
||||
QString currentScript = getCurrentScript();
|
||||
d->scriptHistory.replace(d->scriptHistoryIndex - 1,currentScript);
|
||||
|
||||
if (d->scriptHistoryIndex > 1)
|
||||
d->scriptHistoryIndex--;
|
||||
|
||||
replaceCurrentScript(d->scriptHistory.at(d->scriptHistoryIndex - 1));
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::handleDownKey()
|
||||
{
|
||||
//get the current script and update in script history
|
||||
QString currentScript = getCurrentScript();
|
||||
d->scriptHistory.replace(d->scriptHistoryIndex - 1,currentScript);
|
||||
|
||||
if (d->scriptHistoryIndex < d->scriptHistory.count())
|
||||
d->scriptHistoryIndex++;
|
||||
|
||||
replaceCurrentScript(d->scriptHistory.at(d->scriptHistoryIndex - 1));
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::handleHomeKey()
|
||||
{
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.setPosition(d->startOfEditableArea);
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
|
||||
QString QmlJSScriptConsole::getCurrentScript() const
|
||||
{
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.setPosition(d->startOfEditableArea);
|
||||
while (cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor)) ;
|
||||
QString script = cursor.selectedText();
|
||||
cursor.clearSelection();
|
||||
//remove trailing white space
|
||||
int end = script.size() - 1;
|
||||
while (end > 0 && script[end].isSpace())
|
||||
end--;
|
||||
return script.left(end + 1);
|
||||
}
|
||||
|
||||
void QmlJSScriptConsole::replaceCurrentScript(const QString &script)
|
||||
{
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.setPosition(d->startOfEditableArea);
|
||||
while (cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor)) ;
|
||||
cursor.deleteChar();
|
||||
cursor.insertText(script);
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
|
||||
bool QmlJSScriptConsole::isEditableArea() const
|
||||
{
|
||||
return textCursor().position() >= d->startOfEditableArea;
|
||||
}
|
||||
|
||||
} //Internal
|
||||
} //Debugger
|
||||
130
src/plugins/debugger/qml/qmljsscriptconsole.h
Normal file
130
src/plugins/debugger/qml/qmljsscriptconsole.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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
|
||||
@@ -1,241 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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);
|
||||
|
||||
setFontSettings();
|
||||
}
|
||||
|
||||
|
||||
void ScriptConsole::setFontSettings()
|
||||
{
|
||||
const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::instance()->fontSettings();
|
||||
static QVector<QString> categories;
|
||||
if (categories.isEmpty()) {
|
||||
categories << QLatin1String(TextEditor::Constants::C_NUMBER)
|
||||
<< QLatin1String(TextEditor::Constants::C_STRING)
|
||||
<< QLatin1String(TextEditor::Constants::C_TYPE)
|
||||
<< QLatin1String(TextEditor::Constants::C_KEYWORD)
|
||||
<< QLatin1String(TextEditor::Constants::C_LABEL)
|
||||
<< QLatin1String(TextEditor::Constants::C_COMMENT)
|
||||
<< QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE);
|
||||
}
|
||||
|
||||
const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories);
|
||||
/* m_highlighter->setFormats(formats);
|
||||
m_highlighter->rehighlight();*/
|
||||
m_textEdit->setFont(fs.font());
|
||||
m_lineEdit->setFont(fs.font());
|
||||
}
|
||||
|
||||
|
||||
void ScriptConsole::clear()
|
||||
{
|
||||
clearTextEditor();
|
||||
|
||||
if (m_lineEdit)
|
||||
m_lineEdit->clear();
|
||||
// appendPrompt();
|
||||
}
|
||||
|
||||
void ScriptConsole::clearTextEditor()
|
||||
{
|
||||
m_textEdit->clear();
|
||||
m_textEdit->appendPlainText(tr("Script Console\n"));
|
||||
}
|
||||
|
||||
|
||||
/*void ExpressionQueryWidget::updateTitle()
|
||||
{
|
||||
if (m_currObject.debugId() < 0) {
|
||||
m_title = tr("Expression queries");
|
||||
} else {
|
||||
QString desc = QLatin1String("<")
|
||||
+ m_currObject.className() + QLatin1String(": ")
|
||||
+ (m_currObject.name().isEmpty() ? QLatin1String("<unnamed>") : m_currObject.name())
|
||||
+ QLatin1String(">");
|
||||
m_title = tr("Expression queries (using context for %1)" , "Selected object").arg(desc);
|
||||
}
|
||||
}*/
|
||||
/*
|
||||
void ExpressionQueryWidget::appendPrompt()
|
||||
{
|
||||
m_textEdit->moveCursor(QTextCursor::End);
|
||||
|
||||
if (m_mode == SeparateEntryMode) {
|
||||
m_textEdit->insertPlainText("\n");
|
||||
} else {
|
||||
m_textEdit->appendPlainText(m_prompt);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
bool ScriptConsole::eventFilter(QObject* obj, QEvent* event)
|
||||
{
|
||||
if (obj == m_textEdit) {
|
||||
switch (event->type()) {
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
||||
int key = keyEvent->key();
|
||||
if (key == Qt::Key_Return || key == Qt::Key_Enter) {
|
||||
executeExpression();
|
||||
return true;
|
||||
} else if (key == Qt::Key_Backspace) {
|
||||
// ensure m_expr doesn't contain backspace characters
|
||||
QTextCursor cursor = m_textEdit->textCursor();
|
||||
bool atLastLine = !(cursor.block().next().isValid());
|
||||
if (!atLastLine)
|
||||
return true;
|
||||
if (cursor.positionInBlock() <= m_prompt.count())
|
||||
return true;
|
||||
cursor.deletePreviousChar();
|
||||
m_expr = cursor.block().text().mid(m_prompt.count());
|
||||
return true;
|
||||
} else {
|
||||
m_textEdit->moveCursor(QTextCursor::End);
|
||||
m_expr += keyEvent->text();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::FocusIn:
|
||||
//checkCurrentContext();
|
||||
m_textEdit->moveCursor(QTextCursor::End);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (obj == m_lineEdit) {
|
||||
switch (event->type()) {
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
||||
int key = keyEvent->key();
|
||||
if (key == Qt::Key_Up && m_lineEdit->text() != m_lastExpr) {
|
||||
m_expr = m_lineEdit->text();
|
||||
if (!m_lastExpr.isEmpty())
|
||||
m_lineEdit->setText(m_lastExpr);
|
||||
} else if (key == Qt::Key_Down) {
|
||||
m_lineEdit->setText(m_expr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::FocusIn:
|
||||
// checkCurrentContext();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void ScriptConsole::executeExpression()
|
||||
{
|
||||
m_expr = m_lineEdit->text().trimmed();
|
||||
m_expr = m_expr.trimmed();
|
||||
if (!m_expr.isEmpty()) {
|
||||
emit expressionEntered(m_expr);
|
||||
m_lastExpr = m_expr;
|
||||
if (m_lineEdit)
|
||||
m_lineEdit->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptConsole::appendResult(const QString& result)
|
||||
{
|
||||
m_textEdit->moveCursor(QTextCursor::End);
|
||||
m_textEdit->insertPlainText(m_expr + " : ");
|
||||
m_textEdit->insertPlainText(result);
|
||||
m_textEdit->insertPlainText("\n");
|
||||
m_expr.clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,12 @@ ClientProxy::ClientProxy(Debugger::QmlAdapter *adapter, QObject *parent)
|
||||
connectToServer();
|
||||
}
|
||||
|
||||
ClientProxy::~ClientProxy()
|
||||
{
|
||||
m_adapter.data()->setEngineDebugClient(0);
|
||||
m_adapter.data()->setCurrentSelectedDebugInfo(-1);
|
||||
}
|
||||
|
||||
void ClientProxy::connectToServer()
|
||||
{
|
||||
m_engineClient = new QDeclarativeEngineDebug(m_adapter.data()->connection(), this);
|
||||
@@ -70,6 +76,8 @@ void ClientProxy::connectToServer()
|
||||
connect(m_engineClient, SIGNAL(newObjects()), this, SLOT(newObjects()));
|
||||
connect(m_engineClient, SIGNAL(statusChanged(QDeclarativeDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
|
||||
connect(m_engineClient, SIGNAL(statusChanged(QDeclarativeDebugClient::Status)),
|
||||
this, SLOT(engineClientStatusChanged(QDeclarativeDebugClient::Status)));
|
||||
|
||||
m_inspectorClient = new QmlJSInspectorClient(m_adapter.data()->connection(), this);
|
||||
|
||||
@@ -116,6 +124,13 @@ void ClientProxy::clientStatusChanged(QDeclarativeDebugClient::Status status)
|
||||
updateConnected();
|
||||
}
|
||||
|
||||
void ClientProxy::engineClientStatusChanged(QDeclarativeDebugClient::Status status)
|
||||
{
|
||||
if (status == QDeclarativeDebugClient::Enabled) {
|
||||
m_adapter.data()->setEngineDebugClient(qobject_cast<QDeclarativeEngineDebug *>(sender()));
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::refreshObjectTree()
|
||||
{
|
||||
if (!m_contextQuery) {
|
||||
@@ -434,7 +449,7 @@ void ClientProxy::queryEngineContext(int id)
|
||||
if (!m_contextQuery->isWaiting())
|
||||
contextChanged();
|
||||
else
|
||||
connect(m_contextQuery, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
|
||||
connect(m_contextQuery, SIGNAL(stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)),
|
||||
this, SLOT(contextChanged()));
|
||||
}
|
||||
|
||||
@@ -471,8 +486,8 @@ void ClientProxy::fetchContextObjectRecursive(const QDeclarativeDebugContextRefe
|
||||
} else {
|
||||
m_objectTreeQuery << query;
|
||||
connect(query,
|
||||
SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
|
||||
SLOT(objectTreeFetched(QDeclarativeDebugQuery::State)));
|
||||
SIGNAL(stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)),
|
||||
SLOT(objectTreeFetched(QmlJsDebugClient::QDeclarativeDebugQuery::State)));
|
||||
}
|
||||
}
|
||||
foreach (const QDeclarativeDebugContextReference& child, context.contexts()) {
|
||||
@@ -481,7 +496,7 @@ void ClientProxy::fetchContextObjectRecursive(const QDeclarativeDebugContextRefe
|
||||
}
|
||||
|
||||
|
||||
void ClientProxy::objectTreeFetched(QDeclarativeDebugQuery::State state)
|
||||
void ClientProxy::objectTreeFetched(QmlJsDebugClient::QDeclarativeDebugQuery::State state)
|
||||
{
|
||||
QDeclarativeDebugObjectQuery *query = qobject_cast<QDeclarativeDebugObjectQuery *>(sender());
|
||||
if (!query || state == QDeclarativeDebugQuery::Error) {
|
||||
@@ -646,7 +661,7 @@ void ClientProxy::reloadEngines()
|
||||
if (!m_engineQuery->isWaiting()) {
|
||||
updateEngineList();
|
||||
} else {
|
||||
connect(m_engineQuery, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
|
||||
connect(m_engineQuery, SIGNAL(stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)),
|
||||
this, SLOT(updateEngineList()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ class ClientProxy : public QObject
|
||||
|
||||
public:
|
||||
explicit ClientProxy(Debugger::QmlAdapter *adapter, QObject *parent = 0);
|
||||
~ClientProxy();
|
||||
|
||||
bool setBindingForObject(int objectDebugId,
|
||||
const QString &propertyName,
|
||||
@@ -137,12 +138,13 @@ public slots:
|
||||
private slots:
|
||||
void connectToServer();
|
||||
void clientStatusChanged(QDeclarativeDebugClient::Status status);
|
||||
void engineClientStatusChanged(QDeclarativeDebugClient::Status status);
|
||||
|
||||
void contextChanged();
|
||||
|
||||
void onCurrentObjectsChanged(const QList<int> &debugIds, bool requestIfNeeded = true);
|
||||
void updateEngineList();
|
||||
void objectTreeFetched(QDeclarativeDebugQuery::State state = QDeclarativeDebugQuery::Completed);
|
||||
void objectTreeFetched(QmlJsDebugClient::QDeclarativeDebugQuery::State state = QmlJsDebugClient::QDeclarativeDebugQuery::Completed);
|
||||
void fetchContextObjectRecursive(const QmlJsDebugClient::QDeclarativeDebugContextReference& context);
|
||||
void newObjects();
|
||||
void objectWatchTriggered(const QByteArray &propertyName, const QVariant &propertyValue);
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <debugger/debuggermainwindow.h>
|
||||
#include <debugger/debuggerplugin.h>
|
||||
#include <debugger/qml/qmladapter.h>
|
||||
|
||||
#include <utils/filterlineedit.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -272,13 +273,13 @@ void InspectorUi::showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextE
|
||||
|
||||
if (!query.isEmpty()) {
|
||||
m_debugQuery = m_clientProxy->queryExpressionResult(ref.debugId(), query);
|
||||
connect(m_debugQuery, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
|
||||
this, SLOT(debugQueryUpdated(QDeclarativeDebugQuery::State)));
|
||||
connect(m_debugQuery, SIGNAL(stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)),
|
||||
this, SLOT(debugQueryUpdated(QmlJsDebugClient::QDeclarativeDebugQuery::State)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorUi::debugQueryUpdated(QDeclarativeDebugQuery::State newState)
|
||||
void InspectorUi::debugQueryUpdated(QmlJsDebugClient::QDeclarativeDebugQuery::State newState)
|
||||
{
|
||||
if (newState != QDeclarativeDebugExpressionQuery::Completed)
|
||||
return;
|
||||
@@ -289,8 +290,8 @@ void InspectorUi::debugQueryUpdated(QDeclarativeDebugQuery::State newState)
|
||||
if (!text.isEmpty())
|
||||
QToolTip::showText(QCursor::pos(), text);
|
||||
|
||||
disconnect(m_debugQuery, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
|
||||
this, SLOT(debugQueryUpdated(QDeclarativeDebugQuery::State)));
|
||||
disconnect(m_debugQuery, SIGNAL(stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)),
|
||||
this, SLOT(debugQueryUpdated(QmlJsDebugClient::QDeclarativeDebugQuery::State)));
|
||||
}
|
||||
|
||||
bool InspectorUi::isConnected() const
|
||||
@@ -525,24 +526,6 @@ inline QDeclarativeDebugObjectReference findParentRecursive( int goalDebugId,
|
||||
return QDeclarativeDebugObjectReference();
|
||||
}
|
||||
|
||||
void InspectorUi::selectItems(const QList<QDeclarativeDebugObjectReference> &objectReferences)
|
||||
{
|
||||
foreach (const QDeclarativeDebugObjectReference &objref, objectReferences) {
|
||||
if (objref.debugId() != -1) {
|
||||
// select only the first valid element of the list
|
||||
|
||||
m_clientProxy->removeAllObjectWatches();
|
||||
m_clientProxy->addObjectWatch(objref.debugId());
|
||||
QList <QDeclarativeDebugObjectReference> selectionList;
|
||||
selectionList << objref;
|
||||
m_propertyInspector->setCurrentObjects(selectionList);
|
||||
populateCrumblePath(objref);
|
||||
gotoObjectReferenceDefinition(objref);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline QString displayName(const QDeclarativeDebugObjectReference &obj)
|
||||
{
|
||||
// special! state names
|
||||
@@ -566,6 +549,26 @@ inline QString displayName(const QDeclarativeDebugObjectReference &obj)
|
||||
return QString("<%1>").arg(objTypeName);
|
||||
}
|
||||
|
||||
void InspectorUi::selectItems(const QList<QDeclarativeDebugObjectReference> &objectReferences)
|
||||
{
|
||||
foreach (const QDeclarativeDebugObjectReference &objref, objectReferences) {
|
||||
int debugId = objref.debugId();
|
||||
if (debugId != -1) {
|
||||
// select only the first valid element of the list
|
||||
|
||||
m_clientProxy->removeAllObjectWatches();
|
||||
m_clientProxy->addObjectWatch(debugId);
|
||||
QList <QDeclarativeDebugObjectReference> selectionList;
|
||||
selectionList << objref;
|
||||
m_propertyInspector->setCurrentObjects(selectionList);
|
||||
populateCrumblePath(objref);
|
||||
gotoObjectReferenceDefinition(objref);
|
||||
m_clientProxy->qmlAdapter()->setCurrentSelectedDebugInfo(debugId, displayName(objref));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InspectorUi::isRoot(const QDeclarativeDebugObjectReference &obj) const
|
||||
{
|
||||
foreach (const QDeclarativeDebugObjectReference &rootObj, m_clientProxy->rootObjectReference())
|
||||
|
||||
@@ -133,7 +133,7 @@ private slots:
|
||||
|
||||
void updatePendingPreviewDocuments(QmlJS::Document::Ptr doc);
|
||||
void showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
|
||||
void debugQueryUpdated(QDeclarativeDebugQuery::State);
|
||||
void debugQueryUpdated(QmlJsDebugClient::QDeclarativeDebugQuery::State);
|
||||
|
||||
private:
|
||||
bool addQuotesForData(const QVariant &value) const;
|
||||
|
||||
Reference in New Issue
Block a user