src/declarative/qml/qdeclarativeenginedebug.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "private/qdeclarativeenginedebug_p.h"
       
    43 
       
    44 #include "private/qdeclarativeboundsignal_p.h"
       
    45 #include "qdeclarativeengine.h"
       
    46 #include "private/qdeclarativemetatype_p.h"
       
    47 #include "qdeclarativeproperty.h"
       
    48 #include "private/qdeclarativeproperty_p.h"
       
    49 #include "private/qdeclarativebinding_p.h"
       
    50 #include "private/qdeclarativecontext_p.h"
       
    51 #include "private/qdeclarativewatcher_p.h"
       
    52 #include "private/qdeclarativevaluetype_p.h"
       
    53 
       
    54 #include <QtCore/qdebug.h>
       
    55 #include <QtCore/qmetaobject.h>
       
    56 
       
    57 QT_BEGIN_NAMESPACE
       
    58 
       
    59 QList<QDeclarativeEngine *> QDeclarativeEngineDebugServer::m_engines;
       
    60 QDeclarativeEngineDebugServer::QDeclarativeEngineDebugServer(QObject *parent)
       
    61 : QDeclarativeDebugService(QLatin1String("QDeclarativeEngine"), parent),
       
    62   m_watch(new QDeclarativeWatcher(this))
       
    63 {
       
    64     QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)),
       
    65                      this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant)));
       
    66 }
       
    67 
       
    68 QDataStream &operator<<(QDataStream &ds, 
       
    69                         const QDeclarativeEngineDebugServer::QDeclarativeObjectData &data)
       
    70 {
       
    71     ds << data.url << data.lineNumber << data.columnNumber << data.idString
       
    72        << data.objectName << data.objectType << data.objectId << data.contextId;
       
    73     return ds;
       
    74 }
       
    75 
       
    76 QDataStream &operator>>(QDataStream &ds, 
       
    77                         QDeclarativeEngineDebugServer::QDeclarativeObjectData &data)
       
    78 {
       
    79     ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
       
    80        >> data.objectName >> data.objectType >> data.objectId >> data.contextId;
       
    81     return ds;
       
    82 }
       
    83 
       
    84 QDataStream &operator<<(QDataStream &ds, 
       
    85                         const QDeclarativeEngineDebugServer::QDeclarativeObjectProperty &data)
       
    86 {
       
    87     ds << (int)data.type << data.name << data.value << data.valueTypeName
       
    88        << data.binding << data.hasNotifySignal;
       
    89     return ds;
       
    90 }
       
    91 
       
    92 QDataStream &operator>>(QDataStream &ds,  
       
    93                         QDeclarativeEngineDebugServer::QDeclarativeObjectProperty &data)
       
    94 {
       
    95     int type;
       
    96     ds >> type >> data.name >> data.value >> data.valueTypeName
       
    97        >> data.binding >> data.hasNotifySignal;
       
    98     data.type = (QDeclarativeEngineDebugServer::QDeclarativeObjectProperty::Type)type;
       
    99     return ds;
       
   100 }
       
   101 
       
   102 QDeclarativeEngineDebugServer::QDeclarativeObjectProperty 
       
   103 QDeclarativeEngineDebugServer::propertyData(QObject *obj, int propIdx)
       
   104 {
       
   105     QDeclarativeObjectProperty rv;
       
   106 
       
   107     QMetaProperty prop = obj->metaObject()->property(propIdx);
       
   108 
       
   109     rv.type = QDeclarativeObjectProperty::Unknown;
       
   110     rv.valueTypeName = QString::fromUtf8(prop.typeName());
       
   111     rv.name = QString::fromUtf8(prop.name());
       
   112     rv.hasNotifySignal = prop.hasNotifySignal();
       
   113     QDeclarativeAbstractBinding *binding = 
       
   114         QDeclarativePropertyPrivate::binding(QDeclarativeProperty(obj, rv.name));
       
   115     if (binding)
       
   116         rv.binding = binding->expression();
       
   117 
       
   118     QVariant value = prop.read(obj);
       
   119     rv.value = valueContents(value);
       
   120 
       
   121     if (QDeclarativeValueTypeFactory::isValueType(prop.userType())) {
       
   122         rv.type = QDeclarativeObjectProperty::Basic;
       
   123     } else if (QDeclarativeMetaType::isQObject(prop.userType()))  {
       
   124         rv.type = QDeclarativeObjectProperty::Object;
       
   125     } else if (QDeclarativeMetaType::isList(prop.userType())) {
       
   126         rv.type = QDeclarativeObjectProperty::List;
       
   127     }
       
   128 
       
   129     return rv;
       
   130 }
       
   131 
       
   132 QVariant QDeclarativeEngineDebugServer::valueContents(const QVariant &value) const
       
   133 {
       
   134     int userType = value.userType();
       
   135     if (QDeclarativeValueTypeFactory::isValueType(userType))
       
   136         return value;
       
   137 
       
   138     /*
       
   139     if (QDeclarativeMetaType::isList(userType)) {
       
   140         int count = QDeclarativeMetaType::listCount(value);
       
   141         QVariantList contents;
       
   142         for (int i=0; i<count; i++)
       
   143             contents << valueContents(QDeclarativeMetaType::listAt(value, i));
       
   144         return contents;
       
   145     } else */
       
   146     if (QDeclarativeMetaType::isQObject(userType)) {
       
   147         QObject *o = QDeclarativeMetaType::toQObject(value);
       
   148         if (o) {
       
   149             QString name = o->objectName();
       
   150             if (name.isEmpty())
       
   151                 name = QLatin1String("<unnamed object>");
       
   152             return name;
       
   153         }
       
   154     }
       
   155 
       
   156     return QLatin1String("<unknown value>");
       
   157 }
       
   158 
       
   159 void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message, 
       
   160                                            QObject *object, bool recur)
       
   161 {
       
   162     message << objectData(object);
       
   163 
       
   164     // Some children aren't added to an object until particular properties are read
       
   165     // - e.g. child state objects aren't added until the 'states' property is read -
       
   166     // but this should only affect internal objects that aren't shown by the
       
   167     // debugger anyway.
       
   168 
       
   169     QObjectList children = object->children();
       
   170     
       
   171     int childrenCount = children.count();
       
   172     for (int ii = 0; ii < children.count(); ++ii) {
       
   173         if (qobject_cast<QDeclarativeContext*>(children[ii]) || QDeclarativeBoundSignal::cast(children[ii]))
       
   174             --childrenCount;
       
   175     }
       
   176 
       
   177     message << childrenCount << recur;
       
   178 
       
   179     QList<QDeclarativeObjectProperty> fakeProperties;
       
   180 
       
   181     for (int ii = 0; ii < children.count(); ++ii) {
       
   182         QObject *child = children.at(ii);
       
   183         if (qobject_cast<QDeclarativeContext*>(child))
       
   184             continue;
       
   185         QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
       
   186         if (signal) {
       
   187             QDeclarativeObjectProperty prop;
       
   188             prop.type = QDeclarativeObjectProperty::SignalProperty;
       
   189             prop.hasNotifySignal = false;
       
   190             QDeclarativeExpression *expr = signal->expression();
       
   191             if (expr) {
       
   192                 prop.value = expr->expression();
       
   193                 QObject *scope = expr->scopeObject();
       
   194                 if (scope) {
       
   195                     QString sig = QLatin1String(scope->metaObject()->method(signal->index()).signature());
       
   196                     int lparen = sig.indexOf(QLatin1Char('('));
       
   197                     if (lparen >= 0) {
       
   198                         QString methodName = sig.mid(0, lparen);
       
   199                         prop.name = QLatin1String("on") + methodName[0].toUpper()
       
   200                                 + methodName.mid(1);
       
   201                     }
       
   202                 }
       
   203             }
       
   204             fakeProperties << prop;
       
   205         } else {
       
   206             if (recur)
       
   207                 buildObjectDump(message, child, recur);
       
   208             else
       
   209                 message << objectData(child);
       
   210         }
       
   211     }
       
   212 
       
   213     message << (object->metaObject()->propertyCount() + fakeProperties.count());
       
   214 
       
   215     for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) 
       
   216         message << propertyData(object, ii);
       
   217 
       
   218     for (int ii = 0; ii < fakeProperties.count(); ++ii)
       
   219         message << fakeProperties[ii];
       
   220 }
       
   221 
       
   222 void QDeclarativeEngineDebugServer::buildObjectList(QDataStream &message, QDeclarativeContext *ctxt)
       
   223 {
       
   224     QDeclarativeContextData *p = QDeclarativeContextData::get(ctxt);
       
   225 
       
   226     QString ctxtName = ctxt->objectName();
       
   227     int ctxtId = QDeclarativeDebugService::idForObject(ctxt);
       
   228 
       
   229     message << ctxtName << ctxtId; 
       
   230 
       
   231     int count = 0;
       
   232 
       
   233     QDeclarativeContextData *child = p->childContexts;
       
   234     while (child) {
       
   235         if (!child->isInternal)
       
   236             ++count;
       
   237         child = child->nextChild;
       
   238     }
       
   239 
       
   240     message << count;
       
   241 
       
   242     child = p->childContexts;
       
   243     while (child) {
       
   244         if (!child->isInternal) 
       
   245             buildObjectList(message, child->asQDeclarativeContext());
       
   246         child = child->nextChild;
       
   247     }
       
   248 
       
   249     // Clean deleted objects
       
   250     QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(ctxt);
       
   251     for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
       
   252         if (!ctxtPriv->instances.at(ii)) {
       
   253             ctxtPriv->instances.removeAt(ii);
       
   254             --ii;
       
   255         }
       
   256     }
       
   257 
       
   258     message << ctxtPriv->instances.count();
       
   259     for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
       
   260         message << objectData(ctxtPriv->instances.at(ii));
       
   261     }
       
   262 }
       
   263 
       
   264 QDeclarativeEngineDebugServer::QDeclarativeObjectData 
       
   265 QDeclarativeEngineDebugServer::objectData(QObject *object)
       
   266 {
       
   267     QDeclarativeData *ddata = QDeclarativeData::get(object);
       
   268     QDeclarativeObjectData rv;
       
   269     if (ddata && ddata->outerContext) {
       
   270         rv.url = ddata->outerContext->url;
       
   271         rv.lineNumber = ddata->lineNumber;
       
   272         rv.columnNumber = ddata->columnNumber;
       
   273     } else {
       
   274         rv.lineNumber = -1;
       
   275         rv.columnNumber = -1;
       
   276     }
       
   277 
       
   278     QDeclarativeContext *context = qmlContext(object);
       
   279     if (context) {
       
   280         QDeclarativeContextData *cdata = QDeclarativeContextData::get(context);
       
   281         if (cdata)
       
   282             rv.idString = cdata->findObjectId(object);
       
   283     }
       
   284 
       
   285     rv.objectName = object->objectName();
       
   286     rv.objectId = QDeclarativeDebugService::idForObject(object);
       
   287     rv.contextId = QDeclarativeDebugService::idForObject(qmlContext(object));
       
   288 
       
   289     QDeclarativeType *type = QDeclarativeMetaType::qmlType(object->metaObject());
       
   290     if (type) {
       
   291         QString typeName = QLatin1String(type->qmlTypeName());
       
   292         int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
       
   293         rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1);
       
   294     } else {
       
   295         rv.objectType = QString::fromUtf8(object->metaObject()->className());
       
   296         int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_"));
       
   297         if (marker != -1)
       
   298             rv.objectType = rv.objectType.left(marker);
       
   299     }
       
   300 
       
   301     return rv;
       
   302 }
       
   303 
       
   304 void QDeclarativeEngineDebugServer::messageReceived(const QByteArray &message)
       
   305 {
       
   306     QDataStream ds(message);
       
   307 
       
   308     QByteArray type;
       
   309     ds >> type;
       
   310 
       
   311     if (type == "LIST_ENGINES") {
       
   312         int queryId;
       
   313         ds >> queryId;
       
   314 
       
   315         QByteArray reply;
       
   316         QDataStream rs(&reply, QIODevice::WriteOnly);
       
   317         rs << QByteArray("LIST_ENGINES_R");
       
   318         rs << queryId << m_engines.count();
       
   319 
       
   320         for (int ii = 0; ii < m_engines.count(); ++ii) {
       
   321             QDeclarativeEngine *engine = m_engines.at(ii);
       
   322 
       
   323             QString engineName = engine->objectName();
       
   324             int engineId = QDeclarativeDebugService::idForObject(engine);
       
   325 
       
   326             rs << engineName << engineId;
       
   327         }
       
   328 
       
   329         sendMessage(reply);
       
   330     } else if (type == "LIST_OBJECTS") {
       
   331         int queryId;
       
   332         int engineId = -1;
       
   333         ds >> queryId >> engineId;
       
   334 
       
   335         QDeclarativeEngine *engine = 
       
   336             qobject_cast<QDeclarativeEngine *>(QDeclarativeDebugService::objectForId(engineId));
       
   337 
       
   338         QByteArray reply;
       
   339         QDataStream rs(&reply, QIODevice::WriteOnly);
       
   340         rs << QByteArray("LIST_OBJECTS_R") << queryId;
       
   341 
       
   342         if (engine)
       
   343             buildObjectList(rs, engine->rootContext());
       
   344 
       
   345         sendMessage(reply);
       
   346     } else if (type == "FETCH_OBJECT") {
       
   347         int queryId;
       
   348         int objectId;
       
   349         bool recurse;
       
   350 
       
   351         ds >> queryId >> objectId >> recurse;
       
   352 
       
   353         QObject *object = QDeclarativeDebugService::objectForId(objectId);
       
   354 
       
   355         QByteArray reply;
       
   356         QDataStream rs(&reply, QIODevice::WriteOnly);
       
   357         rs << QByteArray("FETCH_OBJECT_R") << queryId;
       
   358 
       
   359         if (object) 
       
   360             buildObjectDump(rs, object, recurse);
       
   361 
       
   362         sendMessage(reply);
       
   363     } else if (type == "WATCH_OBJECT") {
       
   364         int queryId;
       
   365         int objectId;
       
   366 
       
   367         ds >> queryId >> objectId;
       
   368         bool ok = m_watch->addWatch(queryId, objectId);
       
   369 
       
   370         QByteArray reply;
       
   371         QDataStream rs(&reply, QIODevice::WriteOnly);
       
   372         rs << QByteArray("WATCH_OBJECT_R") << queryId << ok;
       
   373 
       
   374         sendMessage(reply);
       
   375     } else if (type == "WATCH_PROPERTY") {
       
   376         int queryId;
       
   377         int objectId;
       
   378         QByteArray property;
       
   379 
       
   380         ds >> queryId >> objectId >> property;
       
   381         bool ok = m_watch->addWatch(queryId, objectId, property);
       
   382 
       
   383         QByteArray reply;
       
   384         QDataStream rs(&reply, QIODevice::WriteOnly);
       
   385         rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok;
       
   386 
       
   387         sendMessage(reply);
       
   388     } else if (type == "WATCH_EXPR_OBJECT") {
       
   389         int queryId;
       
   390         int debugId;
       
   391         QString expr;
       
   392 
       
   393         ds >> queryId >> debugId >> expr;
       
   394         bool ok = m_watch->addWatch(queryId, debugId, expr);
       
   395 
       
   396         QByteArray reply;
       
   397         QDataStream rs(&reply, QIODevice::WriteOnly);
       
   398         rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok;
       
   399 
       
   400         sendMessage(reply);
       
   401     } else if (type == "NO_WATCH") {
       
   402         int queryId;
       
   403 
       
   404         ds >> queryId;
       
   405         m_watch->removeWatch(queryId);
       
   406     } else if (type == "EVAL_EXPRESSION") {
       
   407         int queryId;
       
   408         int objectId;
       
   409         QString expr;
       
   410 
       
   411         ds >> queryId >> objectId >> expr;
       
   412 
       
   413         QObject *object = QDeclarativeDebugService::objectForId(objectId);
       
   414         QDeclarativeContext *context = qmlContext(object);
       
   415         QVariant result;
       
   416         if (object && context) {
       
   417             QDeclarativeExpression exprObj(context, object, expr);
       
   418             bool undefined = false;
       
   419             QVariant value = exprObj.evaluate(&undefined);
       
   420             if (undefined)
       
   421                 result = QLatin1String("<undefined>");
       
   422             else
       
   423                 result = valueContents(value);
       
   424         } else {
       
   425             result = QLatin1String("<unknown context>");
       
   426         }
       
   427 
       
   428         QByteArray reply;
       
   429         QDataStream rs(&reply, QIODevice::WriteOnly);
       
   430         rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result;
       
   431 
       
   432         sendMessage(reply);
       
   433     }
       
   434 }
       
   435 
       
   436 void QDeclarativeEngineDebugServer::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
       
   437 {
       
   438     QByteArray reply;
       
   439     QDataStream rs(&reply, QIODevice::WriteOnly);
       
   440 
       
   441     rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value);
       
   442 
       
   443     sendMessage(reply);
       
   444 }
       
   445 
       
   446 void QDeclarativeEngineDebugServer::addEngine(QDeclarativeEngine *engine)
       
   447 {
       
   448     Q_ASSERT(engine);
       
   449     Q_ASSERT(!m_engines.contains(engine));
       
   450 
       
   451     m_engines.append(engine);
       
   452 }
       
   453 
       
   454 void QDeclarativeEngineDebugServer::remEngine(QDeclarativeEngine *engine)
       
   455 {
       
   456     Q_ASSERT(engine);
       
   457     Q_ASSERT(m_engines.contains(engine));
       
   458 
       
   459     m_engines.removeAll(engine);
       
   460 }
       
   461 
       
   462 QT_END_NAMESPACE