2010-07-20 12:54:15 +02:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
|
|
|
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
|
|
|
**
|
|
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
|
|
|
**
|
|
|
|
|
** Commercial Usage
|
|
|
|
|
**
|
|
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Nokia.
|
|
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
|
**
|
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
|
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
2010-07-08 11:34:51 +02:00
|
|
|
#include <typeinfo>
|
|
|
|
|
|
|
|
|
|
#include "qmljsclientproxy.h"
|
|
|
|
|
#include "qmljslivetextpreview.h"
|
|
|
|
|
#include "qmljsdelta.h"
|
|
|
|
|
#include "qmljsprivateapi.h"
|
|
|
|
|
|
|
|
|
|
#include <qmljseditor/qmljseditorconstants.h>
|
|
|
|
|
#include <qmljseditor/qmljseditor.h>
|
|
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/editormanager/ieditor.h>
|
|
|
|
|
#include <coreplugin/uniqueidmanager.h>
|
|
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
|
|
|
|
|
|
|
|
#include <debugger/debuggerconstants.h>
|
|
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
2010-07-21 13:11:45 +02:00
|
|
|
using namespace QmlJS;
|
2010-07-08 11:34:51 +02:00
|
|
|
using namespace QmlJS::AST;
|
|
|
|
|
|
|
|
|
|
namespace QmlJSInspector {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2010-07-14 17:38:04 +02:00
|
|
|
/*!
|
|
|
|
|
Associates the UiObjectMember* to their QDeclarativeDebugObjectReference.
|
|
|
|
|
*/
|
|
|
|
|
class MapObjectWithDebugReference : public Visitor
|
|
|
|
|
{
|
|
|
|
|
public:
|
2010-07-19 15:10:36 +02:00
|
|
|
MapObjectWithDebugReference() : activated(0) {}
|
2010-07-14 17:38:04 +02:00
|
|
|
virtual void endVisit(UiObjectDefinition *ast) ;
|
|
|
|
|
virtual void endVisit(UiObjectBinding *ast) ;
|
2010-07-19 15:10:36 +02:00
|
|
|
virtual bool visit(UiObjectDefinition *ast) ;
|
|
|
|
|
virtual bool visit(UiObjectBinding *ast) ;
|
2010-07-14 17:38:04 +02:00
|
|
|
|
|
|
|
|
QDeclarativeDebugObjectReference root;
|
|
|
|
|
QString filename;
|
|
|
|
|
QHash<UiObjectMember *, QList<QDeclarativeDebugObjectReference> > result;
|
2010-07-19 15:10:36 +02:00
|
|
|
QSet<QmlJS::AST::UiObjectMember *> lookupObjects;
|
|
|
|
|
Document::Ptr doc;
|
2010-07-14 17:38:04 +02:00
|
|
|
private:
|
2010-07-19 15:10:36 +02:00
|
|
|
int activated;
|
2010-07-14 17:38:04 +02:00
|
|
|
void processRecursive(const QDeclarativeDebugObjectReference &object, UiObjectMember *ast);
|
|
|
|
|
};
|
|
|
|
|
|
2010-07-19 15:10:36 +02:00
|
|
|
bool MapObjectWithDebugReference::visit(UiObjectDefinition* ast)
|
|
|
|
|
{
|
|
|
|
|
if (lookupObjects.contains(ast))
|
|
|
|
|
activated++;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MapObjectWithDebugReference::visit(UiObjectBinding* ast)
|
|
|
|
|
{
|
|
|
|
|
if (lookupObjects.contains(ast))
|
|
|
|
|
activated++;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:38:04 +02:00
|
|
|
void MapObjectWithDebugReference::endVisit(UiObjectDefinition* ast)
|
|
|
|
|
{
|
2010-07-19 15:10:36 +02:00
|
|
|
if (lookupObjects.isEmpty() || activated)
|
|
|
|
|
processRecursive(root, ast);
|
|
|
|
|
|
|
|
|
|
if (lookupObjects.contains(ast))
|
|
|
|
|
activated--;
|
2010-07-14 17:38:04 +02:00
|
|
|
}
|
|
|
|
|
void MapObjectWithDebugReference::endVisit(UiObjectBinding* ast)
|
|
|
|
|
{
|
2010-07-19 15:10:36 +02:00
|
|
|
if (lookupObjects.isEmpty() || activated)
|
|
|
|
|
processRecursive(root, ast);
|
|
|
|
|
|
|
|
|
|
if (lookupObjects.contains(ast))
|
|
|
|
|
activated--;
|
2010-07-14 17:38:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObjectReference& object, UiObjectMember* ast)
|
|
|
|
|
{
|
|
|
|
|
// If this is too slow, it can be speed up by indexing
|
|
|
|
|
// the QDeclarativeDebugObjectReference by filename/loc in a fist pass
|
|
|
|
|
|
|
|
|
|
SourceLocation loc = ast->firstSourceLocation();
|
2010-07-19 15:10:36 +02:00
|
|
|
if (object.source().columnNumber() == int(loc.startColumn)) {
|
|
|
|
|
QString objectFileName = object.source().url().toLocalFile();
|
|
|
|
|
if (object.source().lineNumber() == int(loc.startLine) && objectFileName == filename) {
|
|
|
|
|
result[ast] += object;
|
|
|
|
|
} else if (doc && objectFileName.startsWith(filename + QLatin1Char('_') + QString::number(doc->editorRevision()) + QLatin1Char(':'))) {
|
|
|
|
|
bool ok;
|
|
|
|
|
int line = objectFileName.mid(objectFileName.lastIndexOf(':') + 1).toInt(&ok);
|
|
|
|
|
if (ok && int(loc.startLine) == line + object.source().lineNumber() - 1)
|
|
|
|
|
result[ast] += object;
|
|
|
|
|
}
|
2010-07-14 17:38:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (const QDeclarativeDebugObjectReference &it, object.children()) {
|
|
|
|
|
processRecursive(it, ast);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
QmlJS::ModelManagerInterface *QmlJSLiveTextPreview::modelManager()
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 15:59:08 +02:00
|
|
|
return ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>();
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
void QmlJSLiveTextPreview::associateEditor(Core::IEditor *editor)
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 15:59:08 +02:00
|
|
|
if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
|
|
|
|
|
QmlJSEditor::Internal::QmlJSTextEditor* qmljsEditor = qobject_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(editor->widget());
|
|
|
|
|
if (qmljsEditor && !m_editors.contains(qmljsEditor)) {
|
|
|
|
|
m_editors << qmljsEditor;
|
|
|
|
|
connect(qmljsEditor,
|
|
|
|
|
SIGNAL(selectedElementsChanged(QList<int>,QString)),
|
|
|
|
|
SLOT(changeSelectedElements(QList<int>,QString)));
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
void QmlJSLiveTextPreview::unassociateEditor(Core::IEditor *oldEditor)
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 15:59:08 +02:00
|
|
|
if (oldEditor && oldEditor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
|
|
|
|
|
QmlJSEditor::Internal::QmlJSTextEditor* qmljsEditor = qobject_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(oldEditor->widget());
|
|
|
|
|
if (qmljsEditor && m_editors.contains(qmljsEditor)) {
|
|
|
|
|
m_editors.removeOne(qmljsEditor);
|
|
|
|
|
disconnect(qmljsEditor,
|
|
|
|
|
SIGNAL(selectedElementsChanged(QList<int>,QString)),
|
|
|
|
|
this,
|
|
|
|
|
SLOT(changeSelectedElements(QList<int>,QString)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-08 11:34:51 +02:00
|
|
|
|
2010-07-20 12:35:36 +02:00
|
|
|
QmlJSLiveTextPreview::QmlJSLiveTextPreview(const QmlJS::Document::Ptr &doc, const QmlJS::Document::Ptr &initDoc, QObject* parent) :
|
|
|
|
|
QObject(parent), m_previousDoc(doc), m_initialDoc(initDoc)
|
2010-07-16 15:59:08 +02:00
|
|
|
{
|
2010-07-20 12:35:36 +02:00
|
|
|
Q_ASSERT(doc->fileName() == initDoc->fileName());
|
2010-07-16 15:59:08 +02:00
|
|
|
ClientProxy *clientProxy = ClientProxy::instance();
|
|
|
|
|
m_filename = doc->fileName();
|
2010-07-08 11:34:51 +02:00
|
|
|
|
|
|
|
|
connect(modelManager(), SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)),
|
|
|
|
|
SLOT(documentChanged(QmlJS::Document::Ptr)));
|
2010-07-16 15:59:08 +02:00
|
|
|
|
|
|
|
|
connect(clientProxy,
|
|
|
|
|
SIGNAL(objectTreeUpdated(QDeclarativeDebugObjectReference)),
|
|
|
|
|
SLOT(updateDebugIds(QDeclarativeDebugObjectReference)));
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-20 12:35:36 +02:00
|
|
|
void QmlJSLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc)
|
|
|
|
|
{
|
|
|
|
|
m_initialDoc = doc;
|
|
|
|
|
m_previousDoc = doc;
|
|
|
|
|
m_createdObjects.clear();
|
|
|
|
|
m_debugIds.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-07-13 14:08:11 +02:00
|
|
|
QList<QDeclarativeDebugObjectReference > QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset) const
|
|
|
|
|
{
|
|
|
|
|
QList<QDeclarativeDebugObjectReference > result;
|
|
|
|
|
QHashIterator<QmlJS::AST::UiObjectMember*, QList<QDeclarativeDebugObjectReference > > iter(m_debugIds);
|
|
|
|
|
while(iter.hasNext()) {
|
|
|
|
|
iter.next();
|
|
|
|
|
QmlJS::AST::UiObjectMember *member = iter.key();
|
|
|
|
|
if (member->firstSourceLocation().offset == offset) {
|
|
|
|
|
result = iter.value();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 17:18:05 +02:00
|
|
|
void QmlJSLiveTextPreview::changeSelectedElements(QList<int> offsets, const QString &wordAtCursor)
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 15:59:08 +02:00
|
|
|
if (m_editors.isEmpty() || !m_previousDoc)
|
2010-07-08 11:34:51 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ClientProxy *clientProxy = ClientProxy::instance();
|
|
|
|
|
|
2010-07-12 17:18:05 +02:00
|
|
|
QDeclarativeDebugObjectReference objectRefUnderCursor;
|
2010-07-08 11:34:51 +02:00
|
|
|
|
|
|
|
|
QList<QDeclarativeDebugObjectReference> refs = clientProxy->objectReferences();
|
|
|
|
|
foreach (const QDeclarativeDebugObjectReference &ref, refs) {
|
|
|
|
|
if (ref.idString() == wordAtCursor) {
|
2010-07-12 17:18:05 +02:00
|
|
|
objectRefUnderCursor = ref;
|
2010-07-08 11:34:51 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 17:18:05 +02:00
|
|
|
QList<QDeclarativeDebugObjectReference> selectedReferences;
|
2010-07-13 14:08:11 +02:00
|
|
|
bool containsReference = false;
|
2010-07-08 11:34:51 +02:00
|
|
|
|
2010-07-12 17:18:05 +02:00
|
|
|
foreach(int offset, offsets) {
|
|
|
|
|
if (offset >= 0) {
|
2010-07-13 14:08:11 +02:00
|
|
|
QList<QDeclarativeDebugObjectReference> list = objectReferencesForOffset(offset);
|
|
|
|
|
|
2010-07-13 16:13:26 +02:00
|
|
|
if (!containsReference && objectRefUnderCursor.debugId() != -1) {
|
2010-07-13 14:08:11 +02:00
|
|
|
foreach(const QDeclarativeDebugObjectReference &ref, list) {
|
|
|
|
|
if (ref.debugId() == objectRefUnderCursor.debugId()) {
|
|
|
|
|
containsReference = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
selectedReferences << list;
|
2010-07-12 17:18:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!containsReference && objectRefUnderCursor.debugId() != -1)
|
|
|
|
|
selectedReferences << objectRefUnderCursor;
|
|
|
|
|
|
|
|
|
|
if (!selectedReferences.isEmpty())
|
|
|
|
|
emit selectedItemsChanged(selectedReferences);
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-19 11:24:44 +02:00
|
|
|
static QList<QDeclarativeDebugObjectReference> findRootObjectRecursive(const QDeclarativeDebugObjectReference &object, const Document::Ptr &doc)
|
|
|
|
|
{
|
|
|
|
|
QList<QDeclarativeDebugObjectReference> result;
|
|
|
|
|
if (object.className() == doc->componentName())
|
|
|
|
|
result += object;
|
|
|
|
|
|
|
|
|
|
foreach (const QDeclarativeDebugObjectReference &it, object.children()) {
|
|
|
|
|
result += findRootObjectRecursive(it, doc);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference &rootReference)
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-19 11:24:44 +02:00
|
|
|
if (!m_initialDoc->qmlProgram())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
{ // Map all the object that comes from the document as it has been loaded by the server.
|
|
|
|
|
const QmlJS::Document::Ptr &doc = m_initialDoc;
|
|
|
|
|
MapObjectWithDebugReference visitor;
|
|
|
|
|
visitor.root = rootReference;
|
|
|
|
|
visitor.filename = doc->fileName();
|
|
|
|
|
doc->qmlProgram()->accept(&visitor);
|
2010-07-13 14:08:11 +02:00
|
|
|
|
2010-07-19 11:24:44 +02:00
|
|
|
m_debugIds = visitor.result;
|
2010-07-20 12:35:36 +02:00
|
|
|
if (doc != m_previousDoc) {
|
|
|
|
|
Delta delta;
|
|
|
|
|
m_debugIds = delta(doc, m_previousDoc, m_debugIds);
|
|
|
|
|
}
|
2010-07-19 11:24:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QmlJS::Document::Ptr &doc = m_previousDoc;
|
2010-07-16 15:59:08 +02:00
|
|
|
if (!doc->qmlProgram())
|
|
|
|
|
return;
|
2010-07-08 11:34:51 +02:00
|
|
|
|
2010-07-19 11:24:44 +02:00
|
|
|
// Map the root nodes of the document.
|
|
|
|
|
if(doc->qmlProgram()->members && doc->qmlProgram()->members->member) {
|
|
|
|
|
UiObjectMember* root = doc->qmlProgram()->members->member;
|
|
|
|
|
QList< QDeclarativeDebugObjectReference > r = findRootObjectRecursive(rootReference, doc);
|
|
|
|
|
if (!r.isEmpty())
|
|
|
|
|
m_debugIds[root] += r;
|
|
|
|
|
}
|
2010-07-19 15:10:36 +02:00
|
|
|
|
|
|
|
|
// Map the node of the later created objects.
|
|
|
|
|
for(QHash<Document::Ptr,QSet<UiObjectMember*> >::const_iterator it = m_createdObjects.constBegin();
|
|
|
|
|
it != m_createdObjects.constEnd(); ++it) {
|
|
|
|
|
|
|
|
|
|
const QmlJS::Document::Ptr &doc = it.key();
|
|
|
|
|
MapObjectWithDebugReference visitor;
|
|
|
|
|
visitor.root = rootReference;
|
|
|
|
|
visitor.filename = doc->fileName();
|
|
|
|
|
visitor.lookupObjects = it.value();
|
|
|
|
|
visitor.doc = doc;
|
|
|
|
|
doc->qmlProgram()->accept(&visitor);
|
|
|
|
|
|
|
|
|
|
Delta::DebugIdMap debugIds = visitor.result;
|
2010-07-20 12:35:36 +02:00
|
|
|
if (doc != m_previousDoc) {
|
|
|
|
|
Delta delta;
|
|
|
|
|
debugIds = delta(doc, m_previousDoc, debugIds);
|
|
|
|
|
}
|
2010-07-19 15:10:36 +02:00
|
|
|
for(Delta::DebugIdMap::const_iterator it2 = debugIds.constBegin();
|
|
|
|
|
it2 != debugIds.constEnd(); ++it2) {
|
|
|
|
|
m_debugIds[it2.key()] += it2.value();
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-14 17:38:04 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-21 13:04:06 +02:00
|
|
|
|
|
|
|
|
class UpdateObserver : public Delta {
|
|
|
|
|
private:
|
|
|
|
|
static inline QString stripQuotes(const QString &str)
|
|
|
|
|
{
|
|
|
|
|
if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
|
|
|
|
|
|| (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
|
|
|
|
|
return str.mid(1, str.length() - 2);
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline QString deEscape(const QString &value)
|
|
|
|
|
{
|
|
|
|
|
QString result = value;
|
|
|
|
|
|
|
|
|
|
result.replace(QLatin1String("\\\\"), QLatin1String("\\"));
|
|
|
|
|
result.replace(QLatin1String("\\\""), QLatin1String("\""));
|
|
|
|
|
result.replace(QLatin1String("\\\t"), QLatin1String("\t"));
|
|
|
|
|
result.replace(QLatin1String("\\\r"), QLatin1String("\\\r"));
|
|
|
|
|
result.replace(QLatin1String("\\\n"), QLatin1String("\n"));
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QString cleanExpression(const QString &expression, UiScriptBinding *scriptBinding)
|
|
|
|
|
{
|
|
|
|
|
QString trimmedExpression = expression.trimmed();
|
|
|
|
|
|
|
|
|
|
if (ExpressionStatement *expStatement = cast<ExpressionStatement*>(scriptBinding->statement)) {
|
|
|
|
|
if (expStatement->semicolonToken.isValid())
|
|
|
|
|
trimmedExpression.chop(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return deEscape(stripQuotes(trimmedExpression));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isLiteralValue(ExpressionNode *expr)
|
|
|
|
|
{
|
|
|
|
|
if (cast<NumericLiteral*>(expr))
|
|
|
|
|
return true;
|
|
|
|
|
else if (cast<StringLiteral*>(expr))
|
|
|
|
|
return true;
|
|
|
|
|
else if (UnaryPlusExpression *plusExpr = cast<UnaryPlusExpression*>(expr))
|
|
|
|
|
return isLiteralValue(plusExpr->expression);
|
|
|
|
|
else if (UnaryMinusExpression *minusExpr = cast<UnaryMinusExpression*>(expr))
|
|
|
|
|
return isLiteralValue(minusExpr->expression);
|
|
|
|
|
else if (cast<TrueLiteral*>(expr))
|
|
|
|
|
return true;
|
|
|
|
|
else if (cast<FalseLiteral*>(expr))
|
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool isLiteralValue(UiScriptBinding *script)
|
|
|
|
|
{
|
|
|
|
|
if (!script || !script->statement)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
ExpressionStatement *exprStmt = cast<ExpressionStatement *>(script->statement);
|
|
|
|
|
if (exprStmt)
|
|
|
|
|
return isLiteralValue(exprStmt->expression);
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QVariant castToLiteral(const QString &expression, UiScriptBinding *scriptBinding)
|
|
|
|
|
{
|
|
|
|
|
const QString cleanedValue = cleanExpression(expression, scriptBinding);
|
|
|
|
|
QVariant castedExpression;
|
|
|
|
|
|
|
|
|
|
ExpressionStatement *expStatement = cast<ExpressionStatement*>(scriptBinding->statement);
|
|
|
|
|
|
|
|
|
|
switch(expStatement->expression->kind) {
|
|
|
|
|
case Node::Kind_NumericLiteral:
|
|
|
|
|
case Node::Kind_UnaryPlusExpression:
|
|
|
|
|
case Node::Kind_UnaryMinusExpression:
|
|
|
|
|
castedExpression = QVariant(cleanedValue).toReal();
|
|
|
|
|
break;
|
|
|
|
|
case Node::Kind_StringLiteral:
|
|
|
|
|
castedExpression = QVariant(cleanedValue).toString();
|
|
|
|
|
break;
|
|
|
|
|
case Node::Kind_TrueLiteral:
|
|
|
|
|
case Node::Kind_FalseLiteral:
|
|
|
|
|
castedExpression = QVariant(cleanedValue).toBool();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
castedExpression = cleanedValue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return castedExpression;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual void updateMethodBody(const QDeclarativeDebugObjectReference& objectReference,
|
|
|
|
|
UiScriptBinding* scriptBinding, const QString& methodName, const QString& methodBody)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(scriptBinding);
|
|
|
|
|
ClientProxy::instance()->setMethodBodyForObject(objectReference.debugId(), methodName, methodBody);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void updateScriptBinding(const QDeclarativeDebugObjectReference& objectReference,
|
|
|
|
|
UiScriptBinding* scriptBinding, const QString& propertyName, const QString& scriptCode)
|
|
|
|
|
{
|
|
|
|
|
QVariant expr = scriptCode;
|
|
|
|
|
const bool isLiteral = isLiteralValue(scriptBinding);
|
|
|
|
|
if (isLiteral)
|
|
|
|
|
expr = castToLiteral(scriptCode, scriptBinding);
|
|
|
|
|
ClientProxy::instance()->setBindingForObject(objectReference.debugId(), propertyName, expr, isLiteral);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void resetBindingForObject(int debugId, const QString &propertyName)
|
|
|
|
|
{
|
|
|
|
|
ClientProxy::instance()->resetBindingForObject(debugId, propertyName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void removeObject(int debugId)
|
|
|
|
|
{
|
|
|
|
|
ClientProxy::instance()->destroyQmlObject(debugId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void createObject(const QString& qmlText, const QDeclarativeDebugObjectReference& ref,
|
|
|
|
|
const QStringList& importList, const QString& filename)
|
|
|
|
|
{
|
|
|
|
|
referenceRefreshRequired = true;
|
|
|
|
|
ClientProxy::instance()->createQmlObject(qmlText, ref, importList, filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
UpdateObserver() : referenceRefreshRequired(false) {}
|
|
|
|
|
bool referenceRefreshRequired;
|
|
|
|
|
};
|
|
|
|
|
|
2010-07-08 11:34:51 +02:00
|
|
|
void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
|
2010-07-16 15:59:08 +02:00
|
|
|
{
|
|
|
|
|
if (doc->fileName() != m_previousDoc->fileName())
|
|
|
|
|
return;
|
|
|
|
|
|
2010-07-08 11:34:51 +02:00
|
|
|
Core::ICore *core = Core::ICore::instance();
|
|
|
|
|
const int dbgcontext = core->uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_DEBUGMODE);
|
|
|
|
|
|
2010-07-08 16:51:25 +02:00
|
|
|
if (!core->hasContext(dbgcontext))
|
2010-07-08 11:34:51 +02:00
|
|
|
return;
|
|
|
|
|
|
2010-07-14 17:38:04 +02:00
|
|
|
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
|
|
|
|
|
&& doc->qmlProgram() && m_previousDoc->qmlProgram())
|
|
|
|
|
{
|
2010-07-21 13:04:06 +02:00
|
|
|
UpdateObserver delta;
|
2010-07-16 15:59:08 +02:00
|
|
|
m_debugIds = delta(m_previousDoc, doc, m_debugIds);
|
|
|
|
|
|
2010-07-21 13:04:06 +02:00
|
|
|
if (delta.referenceRefreshRequired)
|
2010-07-16 15:59:08 +02:00
|
|
|
ClientProxy::instance()->refreshObjectTree();
|
2010-07-13 14:08:11 +02:00
|
|
|
|
2010-07-08 11:34:51 +02:00
|
|
|
m_previousDoc = doc;
|
2010-07-19 15:10:36 +02:00
|
|
|
if (!delta.newObjects.isEmpty())
|
|
|
|
|
m_createdObjects[doc] += delta.newObjects;
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace QmlJSInspector
|