From 3c7528d57275d4ee05ad9a9c11786e3ef1fc8edf Mon Sep 17 00:00:00 2001 From: Olivier Goffart <olivier.goffart@nokia.com> Date: Wed, 21 Jul 2010 13:04:06 +0200 Subject: [PATCH] QmlJsDelta: refactor to split the stuff specific to the QML Live Preview out --- src/plugins/qmljsinspector/qmljsdelta.cpp | 209 ++---------------- src/plugins/qmljsinspector/qmljsdelta.h | 36 +-- .../qmljsinspector/qmljslivetextpreview.cpp | 141 +++++++++++- 3 files changed, 166 insertions(+), 220 deletions(-) diff --git a/src/plugins/qmljsinspector/qmljsdelta.cpp b/src/plugins/qmljsinspector/qmljsdelta.cpp index cf3a69fa940..22918aa90e3 100644 --- a/src/plugins/qmljsinspector/qmljsdelta.cpp +++ b/src/plugins/qmljsinspector/qmljsdelta.cpp @@ -315,9 +315,6 @@ static QHash<QString, UiObjectMember*> extractProperties(UiObjectDefinition *obj void Delta::insert(UiObjectMember *member, UiObjectMember *parentMember, const QList<QDeclarativeDebugObjectReference > &debugReferences, const Document::Ptr &doc) { - if (doNotSendChanges) - return; - if (!member || !parentMember) return; @@ -341,8 +338,7 @@ void Delta::insert(UiObjectMember *member, UiObjectMember *parentMember, const Q + QLatin1Char(':') + QString::number(uiObjectDef->firstSourceLocation().startLine-importList.count()); foreach(const QDeclarativeDebugObjectReference &ref, debugReferences) { if (ref.debugId() != -1) { - _referenceRefreshRequired = true; - ClientProxy::instance()->createQmlObject(qmlText, ref, importList, filename); + createObject(qmlText, ref, importList, filename); } } newObjects += member; @@ -354,9 +350,6 @@ void Delta::update(UiObjectDefinition* oldObject, const QmlJS::Document::Ptr& ol UiObjectDefinition* newObject, const QmlJS::Document::Ptr& newDoc, const QList< QDeclarativeDebugObjectReference >& debugReferences) { - if (doNotSendChanges) - return; - Q_ASSERT (oldObject && newObject); QSet<QString> presentBinding; @@ -391,18 +384,15 @@ void Delta::update(UiObjectDefinition* oldObject, const QmlJS::Document::Ptr& ol } } - if (doNotSendChanges) - return; - //reset property that are not present in the new object. for (QHash<QString, UiObjectMember *>::const_iterator it2 = oldProperties.constBegin(); it2 != oldProperties.constEnd(); ++it2) { if (!newProperties.contains(it2.key())) { - if (UiScriptBinding *previousScript = cast<UiScriptBinding *>(*it2)) { + if (cast<UiScriptBinding *>(*it2)) { foreach (const QDeclarativeDebugObjectReference &ref, debugReferences) { if (ref.debugId() != -1) - ClientProxy::instance()->resetBindingForObject(ref.debugId(), it2.key()); // ### remove + resetBindingForObject(ref.debugId(), it2.key()); } } } @@ -413,7 +403,7 @@ void Delta::remove(const QList< QDeclarativeDebugObjectReference >& debugReferen { foreach (const QDeclarativeDebugObjectReference &ref, debugReferences) { if (ref.debugId() != -1) - ClientProxy::instance()->destroyQmlObject(ref.debugId()); // ### remove + removeObject(ref.debugId()); } } @@ -426,7 +416,6 @@ Delta::DebugIdMap Delta::operator()(const Document::Ptr &doc1, const Document::P QHash< UiObjectMember*, QList<QDeclarativeDebugObjectReference > > newDebuggIds; Map M = Mapping(doc1, doc2); - _referenceRefreshRequired = false; BuildParentHash parents2; doc2->qmlProgram()->accept(&parents2); @@ -486,186 +475,28 @@ Delta::DebugIdMap Delta::operator()(const Document::Ptr &doc1, const Document::P return newDebuggIds; } -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 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 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; -} - -void Delta::updateMethodBody(const QDeclarativeDebugObjectReference &objectReference, - UiScriptBinding *scriptBinding, - const QString &methodName, - const QString &methodBody) -{ - Change change; - change.script = scriptBinding; - change.ref = objectReference; - change.isLiteral = false; - _changes.append(change); - - ClientProxy::instance()->setMethodBodyForObject(objectReference.debugId(), methodName, methodBody); // ### remove -} - -void Delta::updateScriptBinding(const QDeclarativeDebugObjectReference &objectReference, - UiScriptBinding *scriptBinding, - const QString &propertyName, - const QString &scriptCode) -{ - if (doNotSendChanges) - return; - QVariant expr = scriptCode; - - const bool isLiteral = isLiteralValue(scriptBinding); - if (isLiteral) - expr = castToLiteral(scriptCode, scriptBinding); - - Change change; - change.script = scriptBinding; - change.ref = objectReference; - change.isLiteral = isLiteral; - _changes.append(change); - - ClientProxy::instance()->setBindingForObject(objectReference.debugId(), propertyName, expr, isLiteral); // ### remove -} - -bool Delta::compare(UiQualifiedId *id, UiQualifiedId *other) -{ - if (id == other) - return true; - - else if (id && other) { - if (id->name && other->name) { - if (id->name->asString() == other->name->asString()) - return compare(id->next, other->next); - } - } - - return false; -} - -bool Delta::compare(UiSourceElement *source, UiSourceElement *other) -{ - if (source == other) - return true; - - else if (source && other) { - if (source->sourceElement && other->sourceElement) { - FunctionDeclaration *decl = cast<FunctionDeclaration*>(source->sourceElement); - FunctionDeclaration *otherDecl = cast<FunctionDeclaration*>(other->sourceElement); - if (decl && otherDecl - && decl->name && otherDecl->name - && decl->name->asString() == otherDecl->name->asString()) - { - return true; - } - } - } - - return false; -} - Document::Ptr Delta::document() const { - return _doc; + return m_currentDoc; } Document::Ptr Delta::previousDocument() const { - return _previousDoc; + return m_previousDoc; } -QList<Delta::Change> Delta::changes() const -{ - return _changes; -} +void QmlJSInspector::Internal::Delta::createObject(const QString &, const QDeclarativeDebugObjectReference &, + const QStringList &, const QString&) +{} +void QmlJSInspector::Internal::Delta::removeObject(int) +{} +void QmlJSInspector::Internal::Delta::resetBindingForObject(int, const QString &) +{} +void QmlJSInspector::Internal::Delta::updateMethodBody(const QDeclarativeDebugObjectReference &, + UiScriptBinding *, const QString &, const QString &) +{} + +void QmlJSInspector::Internal::Delta::updateScriptBinding(const QDeclarativeDebugObjectReference &, + UiScriptBinding *, const QString &, const QString &) +{} -bool Delta::referenceRefreshRequired() const -{ - return _referenceRefreshRequired; -} diff --git a/src/plugins/qmljsinspector/qmljsdelta.h b/src/plugins/qmljsinspector/qmljsdelta.h index 7033b506916..4354e0da815 100644 --- a/src/plugins/qmljsinspector/qmljsdelta.h +++ b/src/plugins/qmljsinspector/qmljsdelta.h @@ -46,34 +46,15 @@ namespace Internal { class Delta { public: - Delta() : doNotSendChanges(false) {} - - bool doNotSendChanges; QSet<UiObjectMember *> newObjects; - struct Change { - Change(): script(0), isLiteral(false) {} - - QmlJS::AST::UiScriptBinding *script; - bool isLiteral; - QDeclarativeDebugObjectReference ref; - }; - typedef QHash< UiObjectMember*, QList<QDeclarativeDebugObjectReference > > DebugIdMap; DebugIdMap operator()(const QmlJS::Document::Ptr &doc1, const QmlJS::Document::Ptr &doc2, const DebugIdMap &debugIds); - QList<Change> changes() const; QmlJS::Document::Ptr document() const; QmlJS::Document::Ptr previousDocument() const; -public: - bool referenceRefreshRequired() const; - static bool compare(UiSourceElement *source, UiSourceElement *other); - static bool compare(QmlJS::AST::UiQualifiedId *id, QmlJS::AST::UiQualifiedId *other); - static QmlJS::AST::UiObjectMemberList *objectMembers(QmlJS::AST::UiObjectMember *object); - - private: void insert(UiObjectMember *member, UiObjectMember *parentMember, const QList<QDeclarativeDebugObjectReference> &debugReferences, const Document::Ptr &doc); @@ -82,22 +63,23 @@ private: const QList<QDeclarativeDebugObjectReference >& debugReferences); void remove(const QList< QDeclarativeDebugObjectReference > &debugReferences); - void updateScriptBinding(const QDeclarativeDebugObjectReference &objectReference, +protected: + virtual void updateScriptBinding(const QDeclarativeDebugObjectReference &objectReference, QmlJS::AST::UiScriptBinding *scriptBinding, const QString &propertyName, const QString &scriptCode); - void updateMethodBody(const QDeclarativeDebugObjectReference &objectReference, + virtual void updateMethodBody(const QDeclarativeDebugObjectReference &objectReference, UiScriptBinding *scriptBinding, const QString &methodName, const QString &methodBody); - + virtual void resetBindingForObject(int debugId, const QString &propertyName); + virtual void removeObject(int debugId); + virtual void createObject(const QString &qmlText, const QDeclarativeDebugObjectReference &ref, + const QStringList &importList, const QString &filename); private: - QmlJS::Document::Ptr _doc; - QmlJS::Document::Ptr _previousDoc; - QList<Change> _changes; - QUrl _url; - bool _referenceRefreshRequired; + QmlJS::Document::Ptr m_currentDoc; + QmlJS::Document::Ptr m_previousDoc; }; } // namespace Internal diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp index 176c4cfb2a8..db71a515f0d 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp @@ -269,7 +269,6 @@ void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference m_debugIds = visitor.result; if (doc != m_previousDoc) { Delta delta; - delta.doNotSendChanges = true; m_debugIds = delta(doc, m_previousDoc, m_debugIds); } } @@ -301,7 +300,6 @@ void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference Delta::DebugIdMap debugIds = visitor.result; if (doc != m_previousDoc) { Delta delta; - delta.doNotSendChanges = true; debugIds = delta(doc, m_previousDoc, debugIds); } for(Delta::DebugIdMap::const_iterator it2 = debugIds.constBegin(); @@ -311,6 +309,141 @@ void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference } } + +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; +}; + void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) { if (doc->fileName() != m_previousDoc->fileName()) @@ -325,10 +458,10 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName() && doc->qmlProgram() && m_previousDoc->qmlProgram()) { - Delta delta; + UpdateObserver delta; m_debugIds = delta(m_previousDoc, doc, m_debugIds); - if (delta.referenceRefreshRequired()) + if (delta.referenceRefreshRequired) ClientProxy::instance()->refreshObjectTree(); m_previousDoc = doc; -- GitLab