objectnodeinstance.cpp 34.1 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
8
9
10
11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** 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.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
30
31
32
33
34
**
**************************************************************************/

#include "objectnodeinstance.h"

Kai Koehne's avatar
Kai Koehne committed
35
36
37
38


#include <QEvent>
#include <QGraphicsScene>
39
40
41
42
#include <QDeclarativeContext>
#include <QDeclarativeError>
#include <QDeclarativeEngine>
#include <QDeclarativeProperty>
43
#include <QDeclarativeComponent>
44
#include <QSharedPointer>
45
46
47
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QPixmapCache>
48
#ifndef QT_NO_WEBKIT
49
#include <QGraphicsWebView>
50
#endif
51
#include <QGraphicsObject>
Kai Koehne's avatar
Kai Koehne committed
52

53
#include <QTextDocument>
54
#include <QLibraryInfo>
55

56
#include <private/qdeclarativebinding_p.h>
57
58
#include <private/qdeclarativemetatype_p.h>
#include <private/qdeclarativevaluetype_p.h>
59
60
61
#include <private/qdeclarativetransition_p.h>
#include <private/qdeclarativeanimation_p.h>
#include <private/qdeclarativetimer_p.h>
62
63
64
65
66

namespace QmlDesigner {
namespace Internal {

ObjectNodeInstance::ObjectNodeInstance(QObject *object)
67
68
    : m_instanceId(-1),
    m_deleteHeldInstance(true),
69
    m_object(object),
70
71
    m_metaObject(0),
    m_isInPositioner(false)
72
{
73

74
75
76
77
78
79
80
81
82
}

ObjectNodeInstance::~ObjectNodeInstance()
{
    destroy();
}

void ObjectNodeInstance::destroy()
{
Marco Bubke's avatar
Marco Bubke committed
83
84
    if (deleteHeldInstance()) {
        // Remove from old property
85
        if (object()) {
86
            setId(QString());
87
88
            if (m_instanceId >= 0) {
                reparent(parentInstance(), m_parentProperty, ObjectNodeInstance::Pointer(), QString());
89
90
91
            }
        }

Marco Bubke's avatar
Marco Bubke committed
92
93
94
95
        if (object()) {
            QObject *obj = object();
            m_object.clear();
            delete obj;
96
97
        }
    }
Marco Bubke's avatar
Marco Bubke committed
98
99

    m_metaObject = 0;
100
    m_instanceId = -1;
101
102
}

103
void ObjectNodeInstance::setInstanceId(qint32 id)
104
{
105
    m_instanceId = id;
106
107
}

108
qint32 ObjectNodeInstance::instanceId() const
109
{
110
    return m_instanceId;
111
112
}

113
NodeInstanceServer *ObjectNodeInstance::nodeInstanceServer() const
114
{
115
    return m_nodeInstanceServer.data();
116
117
}

118
void ObjectNodeInstance::setNodeInstanceServer(NodeInstanceServer *server)
119
{
120
    Q_ASSERT(!m_nodeInstanceServer.data());
121

122
    m_nodeInstanceServer = server;
123
124
}

125
126
127
128
129
130
131
132
133
134
135
136
static bool hasPropertiesWitoutNotifications(const QMetaObject *metaObject)
{
    for(int propertyIndex = QObject::staticMetaObject.propertyCount(); propertyIndex < metaObject->propertyCount(); propertyIndex++) {
        if (!metaObject->property(propertyIndex).hasNotifySignal())
            return true;
    }

    return false;
}

void ObjectNodeInstance::initializePropertyWatcher(const ObjectNodeInstance::Pointer &objectNodeInstance)
{
137
138
139
140
141
142
143
    const QMetaObject *metaObject = objectNodeInstance->object()->metaObject();
    m_metaObject = new NodeInstanceMetaObject(objectNodeInstance, nodeInstanceServer()->engine());
    for(int propertyIndex = QObject::staticMetaObject.propertyCount(); propertyIndex < metaObject->propertyCount(); propertyIndex++) {
        if (QDeclarativeMetaType::isQObject(metaObject->property(propertyIndex).userType())) {
            QObject *propertyObject = QDeclarativeMetaType::toQObject(metaObject->property(propertyIndex).read(objectNodeInstance->object()));
            if (propertyObject && hasPropertiesWitoutNotifications(propertyObject->metaObject())) {
                new NodeInstanceMetaObject(objectNodeInstance, propertyObject, metaObject->property(propertyIndex).name(), nodeInstanceServer()->engine());
144
145
146
147
148
149
150
            }
        }
    }

    m_signalSpy.setObjectNodeInstance(objectNodeInstance);
}

151
152
153
154
155
void ObjectNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance)
{
    initializePropertyWatcher(objectNodeInstance);
}

156
157
void ObjectNodeInstance::setId(const QString &id)
{
158
    if (!m_id.isEmpty() && context()) {
Marco Bubke's avatar
Marco Bubke committed
159
        context()->engine()->rootContext()->setContextProperty(m_id, 0);
160
161
    }

162
    if (!id.isEmpty() && context()) {
163
164
        context()->engine()->rootContext()->setContextProperty(id, object()); // will also force refresh of all bindings
    }
Marco Bubke's avatar
Marco Bubke committed
165

Marco Bubke's avatar
Marco Bubke committed
166
    m_id = id;
167
168
}

169
170
171
172
173
QString ObjectNodeInstance::id() const
{
    return m_id;
}

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
bool ObjectNodeInstance::isQmlGraphicsItem() const
{
    return false;
}


bool ObjectNodeInstance::isGraphicsObject() const
{
    return false;
}

bool ObjectNodeInstance::isTransition() const
{
    return false;
}

190
191
192
193
194
bool ObjectNodeInstance::isPositioner() const
{
    return false;
}

195
196
197
198
199
bool ObjectNodeInstance::isSGItem() const
{
    return false;
}

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
bool ObjectNodeInstance::equalGraphicsItem(QGraphicsItem * /*item*/) const
{
    return false;
}

QTransform ObjectNodeInstance::transform() const
{
    return QTransform();
}

QTransform ObjectNodeInstance::customTransform() const
{
    return QTransform();
}

QTransform ObjectNodeInstance::sceneTransform() const
{
    return QTransform();
}

double ObjectNodeInstance::rotation() const
{
    return 0.0;
}

double ObjectNodeInstance::scale() const
{
    return 1.0;
}

QList<QGraphicsTransform *> ObjectNodeInstance::transformations() const
{
    QList<QGraphicsTransform *> transformationsList;

    return transformationsList;
}

QPointF ObjectNodeInstance::transformOriginPoint() const
{
    return QPoint();
}

double ObjectNodeInstance::zValue() const
{
    return 0.0;
}

double ObjectNodeInstance::opacity() const
{
    return 1.0;
}

bool ObjectNodeInstance::hasAnchor(const QString &/*name*/) const
{
    return false;
}

257
258
259
260
261
262
bool ObjectNodeInstance::isAnchoredBySibling() const
{
    return false;
}

bool ObjectNodeInstance::isAnchoredByChildren() const
263
264
265
266
{
    return false;
}

267
QPair<QString, ServerNodeInstance> ObjectNodeInstance::anchor(const QString &/*name*/) const
268
{
269
    return qMakePair(QString(), ServerNodeInstance());
270
271
272
}


273
static bool isList(const QDeclarativeProperty &property)
274
{
275
    return property.propertyTypeCategory() == QDeclarativeProperty::List;
276
277
}

278
static bool isObject(const QDeclarativeProperty &property)
279
{
280
281
282
    return (property.propertyTypeCategory() == QDeclarativeProperty::Object) ||
            //QVariant can also store QObjects. Lets trust our model.
           (QLatin1String(property.propertyTypeName()) == QLatin1String("QVariant"));
283
284
285
286
}

static QVariant objectToVariant(QObject *object)
{
287
    return QVariant::fromValue(object);
288
289
}

290
291
static bool hasFullImplementedListInterface(const QDeclarativeListReference &list)
{
292
293

#if QT_VERSION<0x050000
294
    return list.isValid() && list.canCount() && list.canAt() && list.canAppend() && list.canClear();
295
296
297
#else
    return !list.isManipulatable();
#endif
298
299
}

300
static void removeObjectFromList(const QDeclarativeProperty &property, QObject *objectToBeRemoved, QDeclarativeEngine * engine)
301
{
302
    QDeclarativeListReference listReference(property.object(), property.name().toLatin1(), engine);
303

304
    if (!hasFullImplementedListInterface(listReference)) {
305
        qWarning() << "Property list interface not fully implemented for Class " << property.property().typeName() << " in property " << property.name() << "!";
306
        return;
307
    }
308

309
310
311
312
313
314
    int count = listReference.count();

    QObjectList objectList;

    for(int i = 0; i < count; i ++) {
        QObject *listItem = listReference.at(i);
Thomas Hartmann's avatar
Thomas Hartmann committed
315
        if (listItem && listItem != objectToBeRemoved)
316
317
318
319
320
321
322
            objectList.append(listItem);
    }

    listReference.clear();

    foreach(QObject *object, objectList)
        listReference.append(object);
323
324
325
326
}

void ObjectNodeInstance::removeFromOldProperty(QObject *object, QObject *oldParent, const QString &oldParentProperty)
{
327
    QDeclarativeProperty property(oldParent, oldParentProperty, context());
328

329
    if (!property.isValid())
Marco Bubke's avatar
Marco Bubke committed
330
331
        return;

332
    if (isList(property)) {
333
        removeObjectFromList(property, object, nodeInstanceServer()->engine());
334
    } else if (isObject(property)) {
335
336
        if (nodeInstanceServer()->hasInstanceForObject(oldParent)) {
            nodeInstanceServer()->instanceForObject(oldParent).resetProperty(oldParentProperty);
337
        }
338
    }
339
340
341

    if (object && object->parent())
        object->setParent(0);
342
343
344
345
}

void ObjectNodeInstance::addToNewProperty(QObject *object, QObject *newParent, const QString &newParentProperty)
{
346
    QDeclarativeProperty property(newParent, newParentProperty, context());
347

348
349
    if (isList(property)) {
        QDeclarativeListReference list = qvariant_cast<QDeclarativeListReference>(property.read());
350

351
        if (!hasFullImplementedListInterface(list)) {
352
            qWarning() << "Property list interface not fully implemented for Class " << property.property().typeName() << " in property " << property.name() << "!";
353
            return;
354
        }
355

356
        list.append(object);
357
358
    } else if (isObject(property)) {
        property.write(objectToVariant(object));
359
    }
360

361
362
363
364
365
    QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject*>(object);

    if (object && !(graphicsObject && graphicsObject->parentItem()))
        object->setParent(newParent);

366
367
368
    Q_ASSERT(objectToVariant(object).isValid());
}

369
void ObjectNodeInstance::reparent(const ObjectNodeInstance::Pointer &oldParentInstance, const QString &oldParentProperty, const ObjectNodeInstance::Pointer &newParentInstance, const QString &newParentProperty)
370
{
371
372
373
    if (oldParentInstance) {
        removeFromOldProperty(object(), oldParentInstance->object(), oldParentProperty);
        m_parentProperty.clear();
374
375
    }

376
377
378
    if (newParentInstance) {
        m_parentProperty = newParentProperty;
        addToNewProperty(object(), newParentInstance->object(), newParentProperty);
379
380
    }
}
381
382
383
384
385
386
387
388
389
390
391
392
QVariant ObjectNodeInstance::convertSpecialCharacter(const QVariant& value) const
{
    QVariant specialCharacterConvertedValue = value;
    if (value.type() == QVariant::String) {
        QString string = value.toString();
        string.replace(QLatin1String("\\n"), QLatin1String("\n"));
        string.replace(QLatin1String("\\t"), QLatin1String("\t"));
        specialCharacterConvertedValue = string;
    }

    return specialCharacterConvertedValue;
}
393

394
void ObjectNodeInstance::setPropertyVariant(const QString &name, const QVariant &value)
395
{
Marco Bubke's avatar
Marco Bubke committed
396
    QDeclarativeProperty property(object(), name, context());
397

Marco Bubke's avatar
Marco Bubke committed
398
399
400
    if (!property.isValid())
        return;

401
402
403
404
    QVariant oldValue = property.read();
    if (oldValue.type() == QVariant::Url) {
        QUrl url = oldValue.toUrl();
        QString path = url.toLocalFile();
405
406
        if (QFileInfo(path).exists() && nodeInstanceServer() && !path.isEmpty())
            nodeInstanceServer()->removeFilePropertyFromFileSystemWatcher(object(), name, path);
407
408
    }

409
410
411
    if (hasValidResetBinding(name)) {
        QDeclarativePropertyPrivate::setBinding(property, 0, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
    }
412

413
    bool isWritten = property.write(convertSpecialCharacter(value));
414
415
416

    if (!isWritten)
        qDebug() << "ObjectNodeInstance.setPropertyVariant: Cannot be written: " << object() << name << value;
417
418
419
420
421

    QVariant newValue = property.read();
    if (newValue.type() == QVariant::Url) {
        QUrl url = newValue.toUrl();
        QString path = url.toLocalFile();
422
423
        if (QFileInfo(path).exists() && nodeInstanceServer() && !path.isEmpty())
            nodeInstanceServer()->addFilePropertyToFileSystemWatcher(object(), name, path);
424
    }
425
426
427
428
}

void ObjectNodeInstance::setPropertyBinding(const QString &name, const QString &expression)
{
429
    QDeclarativeProperty property(object(), name, context());
Marco Bubke's avatar
Marco Bubke committed
430

431
    if (!property.isValid())
Marco Bubke's avatar
Marco Bubke committed
432
433
        return;

434
    if (property.isProperty()) {
435
        QDeclarativeBinding *binding = new QDeclarativeBinding(expression, object(), context(), object());
436
        binding->setTarget(property);
437
        binding->setNotifyOnValueChanged(true);
438
        QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, binding);
439
        if (oldBinding && !hasValidResetBinding(name))
440
            oldBinding->destroy();
441
        binding->update();
442
        if (binding->hasError()) {
443
            qDebug() <<" ObjectNodeInstance.setPropertyBinding has Error: " << object() << name << expression << binding->error().toString();
444
445
446
447
            if (property.property().userType() == QVariant::String)
                property.write(QVariant(QString("#%1#").arg(expression)));
        }

448
    } else {
449
        qWarning() << "ObjectNodeInstance.setPropertyBinding: Cannot set binding for property" << name << ": property is unknown for type";
450
451
452
    }
}

453
void ObjectNodeInstance::deleteObjectsInList(const QDeclarativeProperty &property)
454
455
{
    QObjectList objectList;
456
    QDeclarativeListReference list = qvariant_cast<QDeclarativeListReference>(property.read());
457

458
    if (!hasFullImplementedListInterface(list)) {
459
        qWarning() << "Property list interface not fully implemented for Class " << property.property().typeName() << " in property " << property.name() << "!";
460
        return;
461
    }
462

463
464
    for(int i = 0; i < list.count(); i++) {
        objectList += list.at(i);
465
466
    }

467
    list.clear();
468
469
470
471
}

void ObjectNodeInstance::resetProperty(const QString &name)
{
472
    doResetProperty(name);
473
474

    if (name == "font.pixelSize")
475
        doResetProperty("font.pointSize");
476
477

    if (name == "font.pointSize")
478
        doResetProperty("font.pixelSize");
479
480
}

481
482
483
484
void ObjectNodeInstance::refreshProperty(const QString &name)
{
    QDeclarativeProperty property(object(), name, context());

Marco Bubke's avatar
Marco Bubke committed
485
486
487
    if (!property.isValid())
        return;

488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
    QVariant oldValue(property.read());

    if (property.isResettable())
        property.reset();
    else
        property.write(resetValue(name));

    if (oldValue.type() == QVariant::Url) {
        QByteArray key = oldValue.toUrl().toEncoded(QUrl::FormattingOption(0x100));
        QString pixmapKey = QString::fromLatin1(key.constData(), key.count());
        QPixmapCache::remove(pixmapKey);
    }

    property.write(oldValue);
}

504
bool ObjectNodeInstance::hasBindingForProperty(const QString &name, bool *hasChanged) const
Thomas Hartmann's avatar
Thomas Hartmann committed
505
506
507
{
    QDeclarativeProperty property(object(), name, context());

508
509
510
511
512
513
514
515
    bool hasBinding = QDeclarativePropertyPrivate::binding(property);

    if (hasChanged) {
        *hasChanged = hasBinding != m_hasBindingHash.value(name, false);
        if (*hasChanged)
            m_hasBindingHash.insert(name, hasBinding);
    }

Thomas Hartmann's avatar
Thomas Hartmann committed
516
517
518
    return QDeclarativePropertyPrivate::binding(property);
}

519
void ObjectNodeInstance::doResetProperty(const QString &propertyName)
520
521
522
{
    m_modelAbstractPropertyHash.remove(propertyName);

523
    QDeclarativeProperty property(object(), propertyName, context());
524

525
    if (!property.isValid())
Marco Bubke's avatar
Marco Bubke committed
526
527
        return;

528
    QVariant oldValue = property.read();
529
530
531
    if (oldValue.type() == QVariant::Url) {
        QUrl url = oldValue.toUrl();
        QString path = url.toLocalFile();
532
533
        if (QFileInfo(path).exists() && nodeInstanceServer())
            nodeInstanceServer()->removeFilePropertyFromFileSystemWatcher(object(), propertyName, path);
534
535
    }

536

537
    QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::binding(property);
538
    if (binding && !(hasValidResetBinding(propertyName) && resetBinding(propertyName) == binding)) {
539
        binding->setEnabled(false, 0);
540
        binding->destroy();
541
542
    }

543
544
545
546
547
548

    if (hasValidResetBinding(propertyName)) {
        QDeclarativeAbstractBinding *binding = resetBinding(propertyName);
        QDeclarativePropertyPrivate::setBinding(property, binding, QDeclarativePropertyPrivate::DontRemoveBinding);
        binding->update();
    } else if (property.isResettable()) {
549
550
551
        property.reset();
    } else if (property.propertyTypeCategory() == QDeclarativeProperty::List) {
        QDeclarativeListReference list = qvariant_cast<QDeclarativeListReference>(property.read());
552
553

        if (!hasFullImplementedListInterface(list)) {
554
            qWarning() << "Property list interface not fully implemented for Class " << property.property().typeName() << " in property " << property.name() << "!";
555
            return;
556
557
        }

558
        list.clear();
559
560
    } else if (property.isWritable()) {
        if (property.read() == resetValue(propertyName))
561
            return;
562

563
        property.write(resetValue(propertyName));
564
565
566
567
568
569
570
571
572
573
    }
}

QVariant ObjectNodeInstance::property(const QString &name) const
{
    if (m_modelAbstractPropertyHash.contains(name))
        return QVariant::fromValue(m_modelAbstractPropertyHash.value(name));

    // TODO: handle model nodes

574
575
    QDeclarativeProperty property(object(), name, context());
    if (property.property().isEnumType()) {
576
        QVariant value = property.read();
577
        return property.property().enumerator().valueToKey(value.toInt());
578
579
    }

580
581
    if (property.propertyType() == QVariant::Url) {
        QUrl url = property.read().toUrl();
582
583
584
585
        if (url.isEmpty())
            return QVariant();

        if (url.scheme() == "file") {
586
            int basePathLength = nodeInstanceServer()->fileUrl().toLocalFile().lastIndexOf('/');
587
588
589
590
            return QUrl(url.toLocalFile().mid(basePathLength + 1));
        }
    }

591
    return property.read();
592
593
}

594
595
596
597
598
QStringList allPropertyNames(QObject *object, const QString &baseName = QString(), QObjectList *inspectedObjects = new QObjectList)
{
    QStringList propertyNameList;


599
    if (inspectedObjects== 0 || inspectedObjects->contains(object))
600
601
602
603
604
605
606
607
608
609
        return propertyNameList;

    inspectedObjects->append(object);


    const QMetaObject *metaObject = object->metaObject();
    for (int index = 0; index < metaObject->propertyCount(); ++index) {
        QMetaProperty metaProperty = metaObject->property(index);
        QDeclarativeProperty declarativeProperty(object, QLatin1String(metaProperty.name()));
        if (declarativeProperty.isValid() && declarativeProperty.propertyTypeCategory() == QDeclarativeProperty::Object) {
610
611
612
613
614
            if (declarativeProperty.name() != "parent") {
                QObject *childObject = QDeclarativeMetaType::toQObject(declarativeProperty.read());
                if (childObject)
                    propertyNameList.append(allPropertyNames(childObject, baseName +  QString::fromUtf8(metaProperty.name()) + '.', inspectedObjects));
            }
615
616
617
618
619
620
621
622
623
624
625
626
627
628
        } else if (QDeclarativeValueTypeFactory::valueType(metaProperty.userType())) {
            QDeclarativeValueType *valueType = QDeclarativeValueTypeFactory::valueType(metaProperty.userType());
            valueType->setValue(metaProperty.read(object));
            propertyNameList.append(allPropertyNames(valueType, baseName +  QString::fromUtf8(metaProperty.name()) + '.', inspectedObjects));
        } else  {
            propertyNameList.append(baseName + QString::fromUtf8(metaProperty.name()));
        }
    }

    return propertyNameList;
}

QStringList ObjectNodeInstance::propertyNames() const
{
629
630
631
    if (isValid())
        return allPropertyNames(object());
    return QStringList();
632
633
}

634
635
636
637
638
639
640
641
QString ObjectNodeInstance::instanceType(const QString &name) const
{
    QDeclarativeProperty property(object(), name, context());
    if (!property.isValid())
        return QLatin1String("undefined");
    return property.propertyTypeName();
}

642
643
644
645
QList<ServerNodeInstance> ObjectNodeInstance::childItems() const
{
    return QList<ServerNodeInstance>();
}
646

647
648
649
650
651
QList<ServerNodeInstance>  ObjectNodeInstance::stateInstances() const
{
    return QList<ServerNodeInstance>();
}

652
void ObjectNodeInstance::setNodeSource(const QString & /*source*/)
653
654
655
{
}

656
657
658
659
660
661
662
663
664
665
void ObjectNodeInstance::setDeleteHeldInstance(bool deleteInstance)
{
    m_deleteHeldInstance = deleteInstance;
}

bool ObjectNodeInstance::deleteHeldInstance() const
{
    return m_deleteHeldInstance;
}

666
ObjectNodeInstance::Pointer ObjectNodeInstance::create(QObject *object)
667
668
669
{
    Pointer instance(new ObjectNodeInstance(object));

670
    instance->populateResetHashes();
671
672
673
674

    return instance;
}

675
static void stopAnimation(QObject *object)
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
{
    if (object == 0)
        return;

    QDeclarativeTransition *transition = qobject_cast<QDeclarativeTransition*>(object);
    QDeclarativeAbstractAnimation *animation = qobject_cast<QDeclarativeAbstractAnimation*>(object);
    QDeclarativeScriptAction *scriptAimation = qobject_cast<QDeclarativeScriptAction*>(object);
    QDeclarativeTimer *timer = qobject_cast<QDeclarativeTimer*>(object);
    if(transition) {
       transition->setFromState("");
       transition->setToState("");
    } else if (animation) {
        if (scriptAimation) {
            scriptAimation->setScript(QDeclarativeScriptString());
        animation->setLoops(1);
        animation->complete();
        animation->setDisableUserControl();
        }
    } else if (timer) {
        timer->blockSignals(true);
    }
}

699
void allSubObject(QObject *object, QObjectList &objectList)
700
{
701
702
    // don't add null pointer and stop if the object is already in the list
    if (!object || objectList.contains(object))
703
704
        return;

705
706
    objectList.append(object);

707
708
709
    for (int index = QObject::staticMetaObject.propertyOffset();
         index < object->metaObject()->propertyCount();
         index++) {
710
711
712
713
714
715
        QMetaProperty metaProperty = object->metaObject()->property(index);

        // search recursive in property objects
        if (metaProperty.isReadable()
                && metaProperty.isWritable()
                && QDeclarativeMetaType::isQObject(metaProperty.userType())) {
716
717
718
719
            if (metaProperty.name() != QLatin1String("parent")) {
                QObject *propertyObject = QDeclarativeMetaType::toQObject(metaProperty.read(object));
                allSubObject(propertyObject, objectList);
            }
720
721
722
723
724
725
726

        }

        // search recursive in property object lists
        if (metaProperty.isReadable()
                && QDeclarativeMetaType::isList(metaProperty.userType())) {
            QDeclarativeListReference list(object, metaProperty.name());
727
#if QT_VERSION<0x050000
728
            if (list.canCount() && list.canAt()) {
729
730
731
#else
            if (list.isReadable()) {
#endif
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
                for (int i = 0; i < list.count(); i++) {
                    QObject *propertyObject = list.at(i);
                    allSubObject(propertyObject, objectList);

                }
            }
        }
    }

    // search recursive in object children list
    foreach(QObject *childObject, object->children()) {
        allSubObject(childObject, objectList);
    }

    // search recursive in graphics item childItems list
    QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject*>(object);
    if (graphicsObject) {
        foreach(QGraphicsItem *item, graphicsObject->childItems()) {
            QGraphicsObject *childObject = item->toGraphicsObject();
            allSubObject(childObject, objectList);
        }
    }
}

static void disableTiledBackingStore(QObject *object)
{
758
#ifndef QT_NO_WEBKIT
759
760
761
    QGraphicsWebView *webView = qobject_cast<QGraphicsWebView*>(object);
    if (webView)
        webView->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, false);
762
763
764
#else
    Q_UNUSED(object);
#endif
765
766
}

767
void tweakObjects(QObject *object)
768
769
770
771
772
773
774
{
    QObjectList objectList;
    allSubObject(object, objectList);
    foreach(QObject* childObject, objectList) {
        disableTiledBackingStore(childObject);
        stopAnimation(childObject);
    }
775
776
}

777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
QObject *ObjectNodeInstance::createComponentWrap(const QString &nodeSource, const QStringList &imports, QDeclarativeContext *context)
{
    QDeclarativeComponent *component = new QDeclarativeComponent(context->engine());

    QByteArray importArray;

    foreach (const QString &import, imports) {
        importArray.append(import.toUtf8());
    }

    QByteArray data(nodeSource.toUtf8());

    data.prepend(importArray);

    component->setData(data, context->baseUrl().resolved(QUrl("createComponent.qml")));

    QObject *object = component;
    tweakObjects(object);

    if (object && context)
        QDeclarativeEngine::setContextForObject(object, context);

    QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::CppOwnership);

    return object;
}
803

804

805
806
807
808
809
//The component might also be shipped with Creator.
//To avoid trouble with import "." we use the component shipped with Creator.
static inline QString fixComponentPathForIncompatibleQt(const QString &componentPath)
{
    QString result = componentPath;
810
    const QLatin1String importString("/imports/");
811
812

    if (componentPath.contains(importString)) {
813
        int index = componentPath.indexOf(importString) + 8;
814
815
816
817
818
        const QString relativeImportPath = componentPath.right(componentPath.length() - index);
        QString fixedComponentPath = QLibraryInfo::location(QLibraryInfo::ImportsPath) + relativeImportPath;
        fixedComponentPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
        if (QFileInfo(fixedComponentPath).exists())
            return fixedComponentPath;
819
820
821
822
823
824
825
826
        QString fixedPath = QFileInfo(fixedComponentPath).path();
        if (fixedPath.endsWith(QLatin1String(".1.0"))) {
        //plugin directories might contain the version number
            fixedPath.chop(4);
            fixedPath += QLatin1Char('/') + QFileInfo(componentPath).fileName();
            if (QFileInfo(fixedPath).exists())
                return fixedPath;
        }
827
828
829
830
831
    }

    return result;
}

832
QObject *ObjectNodeInstance::createComponent(const QString &componentPath, QDeclarativeContext *context)
833
{    
834
    QDeclarativeComponent component(context->engine(), QUrl::fromLocalFile(fixComponentPathForIncompatibleQt(componentPath)));
835
    QObject *object = component.beginCreate(context);
836

837
838
839
    tweakObjects(object);
    component.completeCreate();

840
841
842
843
844
845
    if (component.isError()) {
        qDebug() << componentPath;
        foreach(const QDeclarativeError &error, component.errors())
            qDebug() << error;
    }

846
847
    QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::CppOwnership);

848
849
850
    return object;
}

851
QObject *ObjectNodeInstance::createCustomParserObject(const QString &nodeSource, const QStringList &imports, QDeclarativeContext *context)
852
853
854
855
856
857
858
859
{
    QDeclarativeComponent component(context->engine());

    QByteArray importArray;
    foreach(const QString &import, imports) {
        importArray.append(import.toUtf8());
    }

860
    QByteArray data(nodeSource.toUtf8());
861
862
863
864
865
866
867
868
869

    data.prepend(importArray);

    component.setData(data, context->baseUrl().resolved(QUrl("createCustomParserObject.qml")));

    QObject *object = component.beginCreate(context);
    tweakObjects(object);
    component.completeCreate();

870
    QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::CppOwnership);
871

872
    return object;
873
}
874

875
QObject *ObjectNodeInstance::createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QDeclarativeContext *context)
876
{
877
    QObject *object = 0;
878
879
    QDeclarativeType *type = QDeclarativeMetaType::qmlType(typeName.toUtf8(), majorNumber, minorNumber);
    if (type)  {
880
881
882
883
884
        if (type->typeName() == "QDeclarativeComponent") {
            object = new QDeclarativeComponent(context->engine(), 0);
        } else  {
            object = type->create();
        }
885
    } else {
886
887
888
        qWarning() << "QuickDesigner: Cannot create an object of type"
                   << QString("%1 %2,%3").arg(typeName).arg(majorNumber).arg(minorNumber)
                   << "- type isn't known to declarative meta type system";
889
890
    }

891
892
    tweakObjects(object);

893
894
895
896
    if (object && context)
        QDeclarativeEngine::setContextForObject(object, context);

    QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::CppOwnership);
897
898
899
900
901
902

    return object;
}

QObject *ObjectNodeInstance::object() const
{
Thomas Hartmann's avatar
Thomas Hartmann committed
903
904
905
        if (!m_object.isNull() && !QObjectPrivate::get(m_object.data())->wasDeleted)
            return m_object.data();
        return 0;
906
907
908
909
910
911
912
}

bool ObjectNodeInstance::hasContent() const
{
    return false;
}

913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
bool ObjectNodeInstance::isResizable() const
{
    return false;
}

bool ObjectNodeInstance::isMovable() const
{
    return false;
}

bool ObjectNodeInstance::isInPositioner() const
{
    return m_isInPositioner;
}

void ObjectNodeInstance::setInPositioner(bool isInPositioner)
{
    m_isInPositioner = isInPositioner;
}

933
934
935
936
void ObjectNodeInstance::refreshPositioner()
{
}

937
938
939
940
void ObjectNodeInstance::updateAnchors()
{
}

941
QDeclarativeContext *ObjectNodeInstance::context() const
942
{
943
944
    if (nodeInstanceServer())
        return nodeInstanceServer()->context();
945

946
    qWarning() << "Error: No NodeInstanceServer";
947
948
949
    return 0;
}

950
951
QDeclarativeEngine *ObjectNodeInstance::engine() const
{
952
    return nodeInstanceServer()->engine();
953
954
}

955
956
957
958
void ObjectNodeInstance::paintUpdate()
{
}

Marco Bubke's avatar
Marco Bubke committed
959
960
961
962
963
964
965
966
void ObjectNodeInstance::activateState()
{
}

void ObjectNodeInstance::deactivateState()
{
}

967
QStringList propertyNameForWritableProperties(QObject *object, const QString &baseName = QString(), QObjectList *inspectedObjects = new QObjectList())
968
969
970
{
    QStringList propertyNameList;

971
    if (inspectedObjects == 0 || inspectedObjects->contains(object))
972
973
974
975
        return propertyNameList;

    inspectedObjects->append(object);

976
977
978
    const QMetaObject *metaObject = object->metaObject();
    for (int index = 0; index < metaObject->propertyCount(); ++index) {
        QMetaProperty metaProperty = metaObject->property(index);
979
        QDeclarativeProperty declarativeProperty(object, QLatin1String(metaProperty.name()));
980
        if (declarativeProperty.isValid() && !declarativeProperty.isWritable() && declarativeProperty.propertyTypeCategory() == QDeclarativeProperty::Object) {
981
982
983
984
985
            if (declarativeProperty.name() != "parent") {
                QObject *childObject = QDeclarativeMetaType::toQObject(declarativeProperty.read());
                if (childObject)
                    propertyNameList.append(propertyNameForWritableProperties(childObject, baseName +  QString::fromUtf8(metaProperty.name()) + '.', inspectedObjects));
            }
986
987
        } else if (QDeclarativeValueTypeFactory::valueType(metaProperty.userType())) {
            QDeclarativeValueType *valueType = QDeclarativeValueTypeFactory::valueType(metaProperty.userType());
988
            valueType->setValue(metaProperty.read(object));
989
            propertyNameList.append(propertyNameForWritableProperties(valueType, baseName +  QString::fromUtf8(metaProperty.name()) + '.', inspectedObjects));
990
991
992
993
994
995
996
997
        } else if (metaProperty.isReadable() && metaProperty.isWritable()) {
            propertyNameList.append(baseName + QString::fromUtf8(metaProperty.name()));
        }
    }

    return propertyNameList;
}

998
void ObjectNodeInstance::populateResetHashes()
999
1000
{
    QStringList propertyNameList = propertyNameForWritableProperties(object());
For faster browsing, not all history is shown. View entire blame