nodemetainfo.cpp 42 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30
31
32
33

#include "nodemetainfo.h"
#include "model.h"

#include "metainfo.h"
34
#include <rewriterview.h>
35
#include <propertyparser.h>
36

37
#include <QDir>
hjk's avatar
hjk committed
38
#include <QDebug>
39

Christian Kamm's avatar
Christian Kamm committed
40
#include <qmljs/qmljsscopechain.h>
41
#include <qmljs/parser/qmljsast_p.h>
42
#include <qmljs/qmljsmodelmanagerinterface.h>
43
44
45
46
47

namespace QmlDesigner {

namespace Internal {

48
struct TypeDescription
49
{
50
    TypeName className;
51
    int minorVersion;
52
    int majorVersion;
53
54
};

55
} //Internal
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

/*!
\class QmlDesigner::NodeMetaInfo
\ingroup CoreModel
\brief The NodeMetaInfo class provides meta information about a qml type.

A NodeMetaInfo object can be created via ModelNode::metaInfo, or MetaInfo::nodeMetaInfo.

The object can be invalid - you can check this by calling isValid().
The object is invalid if you ask for meta information for
an non-existing qml property. Also the node meta info can become invalid
if the enclosing type is deregistered from the meta type system (e.g.
a sub component qml file is deleted). Trying to call any accessor methods on an invalid
NodeMetaInfo object will result in an InvalidMetaInfoException being thrown.

\see QmlDesigner::MetaInfo, QmlDesigner::PropertyMetaInfo, QmlDesigner::EnumeratorMetaInfo
*/

74
75
76
77
namespace Internal {

using namespace QmlJS;

78
typedef QPair<PropertyName, TypeName> PropertyInfo;
79

80
QList<PropertyInfo> getObjectTypes(const ObjectValue *ov, const ContextPtr &context, bool local = false, int rec = 0);
81

82
static TypeName resolveTypeName(const ASTPropertyReference *ref, const ContextPtr &context,  QList<PropertyInfo> &dotProperties)
83
{
84
    TypeName type = "unknown";
85
86

    if (!ref->ast()->memberType.isEmpty()) {
87
        type = ref->ast()->memberType.toUtf8();
88

89
        if (type == "alias") {
90
91
92
93
94
95
96
            const Value *value = context->lookupReference(ref);

            if (!value)
                return type;

            if (const ASTObjectValue * astObjectValue = value->asAstObjectValue()) {
                if (astObjectValue->typeName())
97
                    type = astObjectValue->typeName()->name.toUtf8();
98
            } else if (const ObjectValue * objectValue = value->asObjectValue()) {
99
                type = objectValue->className().toUtf8();
100
                dotProperties = getObjectTypes(objectValue, context);
101
            } else if (value->asColorValue()) {
102
                type = "color";
103
            } else if (value->asUrlValue()) {
104
                type = "url";
105
            } else if (value->asStringValue()) {
106
                type = "string";
107
            } else if (value->asRealValue()) {
108
                type = "real";
109
            } else if (value->asIntValue()) {
110
                type = "int";
111
            } else if (value->asBooleanValue()) {
112
                type = "boolean";
113
114
115
116
117
118
119
            }
        }
    }

    return type;
}

120
class PropertyMemberProcessor : public MemberProcessor
121
{
122
public:
123
124
    PropertyMemberProcessor(const ContextPtr &context) : m_context(context)
    {}
125
    bool processProperty(const QString &name, const Value *value)
126
    {
127
        PropertyName propertyName = name.toUtf8();
Christian Kamm's avatar
Christian Kamm committed
128
        const ASTPropertyReference *ref = value_cast<ASTPropertyReference>(value);
129
        if (ref) {
130
            QList<PropertyInfo> dotProperties;
131
132
            const TypeName type = resolveTypeName(ref, m_context, dotProperties);
            m_properties.append(qMakePair(propertyName, type));
133
134
            if (!dotProperties.isEmpty()) {
                foreach (const PropertyInfo &propertyInfo, dotProperties) {
135
136
137
                    PropertyName dotName = propertyInfo.first;
                    TypeName type = propertyInfo.second;
                    dotName = propertyName + '.' + dotName;
138
139
140
                    m_properties.append(qMakePair(dotName, type));
                }
            }
141
        } else {
142
143
144
            if (const CppComponentValue * cppComponentValue = value_cast<CppComponentValue>(value)) {
                TypeName qualifiedTypeName = cppComponentValue->moduleName().isEmpty() ? cppComponentValue->className().toUtf8() : cppComponentValue->moduleName().toUtf8() + '.' + cppComponentValue->className().toUtf8();
                m_properties.append(qMakePair(propertyName, qualifiedTypeName));
145
            } else {
146
                TypeId typeId;
147
148
                TypeName typeName = typeId(value).toUtf8();
                if (typeName == "number") {
149
                    if (value->asRealValue())
150
                        typeName = "real";
151
                    else
152
                        typeName = "int";
153
                }
154
                m_properties.append(qMakePair(propertyName, typeName));
155
156
157
158
            }
        }
        return true;
    }
159

160
161
162
163
164
165
    virtual bool processSignal(const QString &name, const Value * /*value*/)
    {
        m_signals.append(name.toUtf8());
        return true;
    }

166
167
    QList<PropertyInfo> properties() const { return m_properties; }

168
169
    PropertyNameList signalList() const { return m_signals; }

170
171
private:
    QList<PropertyInfo> m_properties;
172
    PropertyNameList m_signals;
173
    const ContextPtr m_context;
174
175
176
};

static inline bool isValueType(const QString &type)
177
{
178
179
180
    QStringList objectValuesList;
    objectValuesList << "QFont" << "QPoint" << "QPointF" << "QSize" << "QSizeF" << "QVector3D" << "QVector2D";
    return objectValuesList.contains(type);
181
182
}

183
const CppComponentValue *findQmlPrototype(const ObjectValue *ov, const ContextPtr &context)
184
{
185
186
187
    if (!ov)
        return 0;

Christian Kamm's avatar
Christian Kamm committed
188
    const CppComponentValue * qmlValue = value_cast<CppComponentValue>(ov);
189
190
191
    if (qmlValue)
        return qmlValue;

Christian Kamm's avatar
Christian Kamm committed
192
    return findQmlPrototype(ov->prototype(context), context);
193
194
}

195
QStringList prototypes(const ObjectValue *ov, const ContextPtr &context, bool versions = false)
196
{
197
198
199
    QStringList list;
    if (!ov)
        return list;
Christian Kamm's avatar
Christian Kamm committed
200
    ov = ov->prototype(context);
201
    while (ov) {
Christian Kamm's avatar
Christian Kamm committed
202
        const CppComponentValue * qmlValue = value_cast<CppComponentValue>(ov);
203
204
        if (qmlValue) {
            if (versions) {
205
206
207
                list << qmlValue->moduleName() + '.' + qmlValue->className() +
                ' ' + QString::number(qmlValue->componentVersion().majorVersion()) +
                '.' + QString::number(qmlValue->componentVersion().minorVersion());
208
            } else {
209
                list << qmlValue->moduleName() + QLatin1Char('.') + qmlValue->className();
210
211
            }
        } else {
212
            if (versions)
213
                list << ov->className() + " -1.-1";
214
            else
215
216
                list << ov->className();
        }
Christian Kamm's avatar
Christian Kamm committed
217
        ov = ov->prototype(context);
218
219
    }
    return list;
220
221
}

222
QList<PropertyInfo> getQmlTypes(const CppComponentValue *objectValue, const ContextPtr &context, bool local = false, int rec = 0)
223
{
224
225
226
227
228
229
    QList<PropertyInfo> propertyList;

    if (!objectValue)
        return propertyList;
    if (objectValue->className().isEmpty())
        return propertyList;
230

231
232
233
    if (rec > 2)
        return propertyList;

234
    PropertyMemberProcessor processor(context);
235
    objectValue->processMembers(&processor);
236

237
238
239
    QList<PropertyInfo> newList = processor.properties();

    foreach (PropertyInfo property, newList) {
240
241
        PropertyName name = property.first;
        if (!objectValue->isWritable(name) && objectValue->isPointer(name)) {
242
            //dot property
243
            const CppComponentValue * qmlValue = value_cast<CppComponentValue>(objectValue->lookupMember(name, context));
244
            if (qmlValue) {
245
                QList<PropertyInfo> dotProperties = getQmlTypes(qmlValue, context, false, rec + 1);
246
                foreach (const PropertyInfo &propertyInfo, dotProperties) {
247
248
                    PropertyName dotName = propertyInfo.first;
                    TypeName type = propertyInfo.second;
249
                    dotName = name + '.' + dotName;
250
                    propertyList.append(qMakePair(dotName, type));
251
252
253
                }
            }
        }
254
255
        if (isValueType(objectValue->propertyType(name))) {
            const ObjectValue *dotObjectValue = value_cast<ObjectValue>(objectValue->lookupMember(name, context));
256
            if (dotObjectValue) {
257
                QList<PropertyInfo> dotProperties = getObjectTypes(dotObjectValue, context, false, rec + 1);
258
                foreach (const PropertyInfo &propertyInfo, dotProperties) {
259
260
                    PropertyName dotName = propertyInfo.first;
                    TypeName type = propertyInfo.second;
261
                    dotName = name + '.' + dotName;
262
                    propertyList.append(qMakePair(dotName, type));
263
264
265
                }
            }
        }
266
267
268
269
        TypeName type = property.second;
        if (!objectValue->isPointer(name) && !objectValue->isListProperty(name))
            type = objectValue->propertyType(name).toUtf8();
        propertyList.append(qMakePair(name, type));
270
271
272
    }

    if (!local) {
273
        const ObjectValue* prototype = objectValue->prototype(context);
274

Christian Kamm's avatar
Christian Kamm committed
275
        const CppComponentValue * qmlObjectValue = value_cast<CppComponentValue>(prototype);
276

277
        if (qmlObjectValue)
278
            propertyList.append(getQmlTypes(qmlObjectValue, context, false, rec));
279
        else
280
            propertyList.append(getObjectTypes(prototype, context, false, rec));
281
282
    }

283
    return propertyList;
284
285
}

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
PropertyNameList getSignals(const ObjectValue *objectValue, const ContextPtr &context, bool local = false)
{
    PropertyNameList signalList;

     if (!objectValue)
        return signalList;
    if (objectValue->className().isEmpty())
        return signalList;

    PropertyMemberProcessor processor(context);
    objectValue->processMembers(&processor);

    signalList.append(processor.signalList());

    if (!local) {
        const ObjectValue* prototype = objectValue->prototype(context);

        if (prototype == objectValue)
            return signalList;

        signalList.append(getSignals(prototype, context));
    }

    return signalList;
}

312
QList<PropertyInfo> getTypes(const ObjectValue *objectValue, const ContextPtr &context, bool local = false)
313
{
314
    QList<PropertyInfo> propertyList;
315

316
    const CppComponentValue * qmlObjectValue = value_cast<CppComponentValue>(objectValue);
317

318
    if (qmlObjectValue)
319
        propertyList.append(getQmlTypes(qmlObjectValue, context, local));
320
    else
321
        propertyList.append(getObjectTypes(objectValue, context, local));
322

323
    return propertyList;
324
325
}

326
QList<PropertyInfo> getObjectTypes(const ObjectValue *objectValue, const ContextPtr &context, bool local, int rec)
327
{
328
329
330
331
332
333
    QList<PropertyInfo> propertyList;

    if (!objectValue)
        return propertyList;
    if (objectValue->className().isEmpty())
        return propertyList;
Thomas Hartmann's avatar
Thomas Hartmann committed
334

335
336
337
    if (rec > 2)
        return propertyList;

338
    PropertyMemberProcessor processor(context);
339
    objectValue->processMembers(&processor);
340

341
    propertyList.append(processor.properties());
342
343

    if (!local) {
344
        const ObjectValue* prototype = objectValue->prototype(context);
345

346
347
        if (prototype == objectValue)
            return propertyList;
Thomas Hartmann's avatar
Thomas Hartmann committed
348

Christian Kamm's avatar
Christian Kamm committed
349
        const CppComponentValue * qmlObjectValue = value_cast<CppComponentValue>(prototype);
350

351
        if (qmlObjectValue)
352
            propertyList.append(getQmlTypes(qmlObjectValue, context, local, rec));
353
        else
354
            propertyList.append(getObjectTypes(prototype, context, local, rec));
355
356
    }

357
    return propertyList;
358
359
}

360
class NodeMetaInfoPrivate
361
{
362
363
364
365
366
367
public:
    typedef QSharedPointer<NodeMetaInfoPrivate> Pointer;
    NodeMetaInfoPrivate();
    ~NodeMetaInfoPrivate() {}

    bool isValid() const;
Marco Bubke's avatar
Marco Bubke committed
368
    bool isFileComponent() const;
369
370
    PropertyNameList properties() const;
    PropertyNameList localProperties() const;
371
    PropertyNameList signalNames() const;
372
373
    PropertyName defaultPropertyName() const;
    TypeName propertyType(const PropertyName &propertyName) const;
374

375
    void setupPrototypes();
376
377
    QList<TypeDescription> prototypes() const;

378
379
380
381
382
    bool isPropertyWritable(const PropertyName &propertyName) const;
    bool isPropertyPointer(const PropertyName &propertyName) const;
    bool isPropertyList(const PropertyName &propertyName) const;
    bool isPropertyEnum(const PropertyName &propertyName) const;
    QString propertyEnumScope(const PropertyName &propertyName) const;
383
384
    QStringList keysForEnum(const QString &enumName) const;
    bool cleverCheckType(const QString &otherType) const;
385
    QVariant::Type variantTypeId(const PropertyName &properyName) const;
386

Marco Bubke's avatar
Marco Bubke committed
387
388
    int majorVersion() const;
    int minorVersion() const;
389
    TypeName qualfiedTypeName() const;
Marco Bubke's avatar
Marco Bubke committed
390
    Model *model() const;
391

392
    QString cppPackageName() const;
393
394
395

    QString componentSource() const;
    QString componentFileName() const;
396
    QString importDirectoryPath() const;
397

398
    static Pointer create(Model *model, const TypeName &type, int maj = -1, int min = -1);
399

Marco Bubke's avatar
Marco Bubke committed
400
401
    QSet<QString> &prototypeCachePositives();
    QSet<QString> &prototypeCacheNegatives();
402

Marco Bubke's avatar
Marco Bubke committed
403
    static void clearCache();
404

405

406
private:
407
    NodeMetaInfoPrivate(Model *model, TypeName type, int maj = -1, int min = -1);
408

409
    const QmlJS::CppComponentValue *getCppComponentValue() const;
410
    const QmlJS::ObjectValue *getObjectValue() const;
411
412
413
414
    void setupPropertyInfo(QList<PropertyInfo> propertyInfos);
    void setupLocalPropertyInfo(QList<PropertyInfo> propertyInfos);
    QString lookupName() const;
    QStringList lookupNameComponent() const;
415
    const QmlJS::CppComponentValue *getNearestCppComponentValue() const;
416
    QString fullQualifiedImportAliasType() const;
417

418
    TypeName m_qualfiedTypeName;
419
420
421
    int m_majorVersion;
    int m_minorVersion;
    bool m_isValid;
Marco Bubke's avatar
Marco Bubke committed
422
    bool m_isFileComponent;
423
    PropertyNameList m_properties;
424
    PropertyNameList m_signals;
425
426
427
    QList<TypeName> m_propertyTypes;
    PropertyNameList m_localProperties;
    PropertyName m_defaultPropertyName;
428
    QList<TypeDescription> m_prototypes;
429
430
    QSet<QString> m_prototypeCachePositives;
    QSet<QString> m_prototypeCacheNegatives;
431
432

    //storing the pointer would not be save
433
    QmlJS::ContextPtr context() const;
434
    const Document *document() const;
435
436

    QPointer<Model> m_model;
437
    static QHash<QString, Pointer> m_nodeMetaInfoCache;
438
439
};

440
441
QHash<QString, NodeMetaInfoPrivate::Pointer> NodeMetaInfoPrivate::m_nodeMetaInfoCache;

Marco Bubke's avatar
Marco Bubke committed
442
443
444
445
446
bool NodeMetaInfoPrivate::isFileComponent() const
{
    return m_isFileComponent;
}

447
PropertyNameList NodeMetaInfoPrivate::properties() const
Marco Bubke's avatar
Marco Bubke committed
448
449
450
451
{
    return m_properties;
}

452
PropertyNameList NodeMetaInfoPrivate::localProperties() const
Marco Bubke's avatar
Marco Bubke committed
453
454
455
456
{
    return m_localProperties;
}

457
458
459
460
461
PropertyNameList NodeMetaInfoPrivate::signalNames() const
{
    return m_signals;
}

Marco Bubke's avatar
Marco Bubke committed
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
QSet<QString> &NodeMetaInfoPrivate::prototypeCachePositives()
{
    return m_prototypeCachePositives;
}

QSet<QString> &NodeMetaInfoPrivate::prototypeCacheNegatives()
{
    return m_prototypeCacheNegatives;
}

void NodeMetaInfoPrivate::clearCache()
{
    m_nodeMetaInfoCache.clear();
}

477
PropertyName NodeMetaInfoPrivate::defaultPropertyName() const
Marco Bubke's avatar
Marco Bubke committed
478
479
480
{
    if (!m_defaultPropertyName.isEmpty())
        return m_defaultPropertyName;
481
    return PropertyName("data");
Marco Bubke's avatar
Marco Bubke committed
482
}
483

484
static inline QString stringIdentifier( const QString &type, int maj, int min)
485
{
486
    return type + QString::number(maj) + '_' + QString::number(min);
487
488
}

489
NodeMetaInfoPrivate::Pointer NodeMetaInfoPrivate::create(Model *model, const TypeName &type, int major, int minor)
490
{
491
492
    if (m_nodeMetaInfoCache.contains(stringIdentifier(type, major, minor))) {
        const Pointer &info = m_nodeMetaInfoCache.value(stringIdentifier(type, major, minor));
493
        if (info->model() == model)
494
            return info;
495
        else
496
            m_nodeMetaInfoCache.clear();
497
    }
498

499
    Pointer newData(new NodeMetaInfoPrivate(model, type, major, minor));
500
    if (newData->isValid())
501
        m_nodeMetaInfoCache.insert(stringIdentifier(type, major, minor), newData);
502
    return newData;
503
504
}

505
506
NodeMetaInfoPrivate::NodeMetaInfoPrivate() : m_isValid(false)
{
507

508
}
509

510
NodeMetaInfoPrivate::NodeMetaInfoPrivate(Model *model, TypeName type, int maj, int min) :
511
                                        m_qualfiedTypeName(type), m_majorVersion(maj),
Marco Bubke's avatar
Marco Bubke committed
512
                                        m_minorVersion(min), m_isValid(false), m_isFileComponent(false),
Kai Koehne's avatar
Kai Koehne committed
513
                                        m_model(model)
514
{
Christian Kamm's avatar
Christian Kamm committed
515
    if (context()) {
516
        const CppComponentValue *objectValue = getCppComponentValue();
517

518
        if (objectValue) {
519
520
521
522
            if (m_majorVersion == -1 && m_minorVersion == -1) {
                m_majorVersion = objectValue->componentVersion().majorVersion();
                m_minorVersion = objectValue->componentVersion().minorVersion();
            }
Christian Kamm's avatar
Christian Kamm committed
523
524
            setupPropertyInfo(getTypes(objectValue, context()));
            setupLocalPropertyInfo(getTypes(objectValue, context(), true));
525
            m_defaultPropertyName = objectValue->defaultPropertyName().toUtf8();
526
            m_isValid = true;
Thomas Hartmann's avatar
Thomas Hartmann committed
527
            setupPrototypes();
528
            m_signals = getSignals(objectValue, context());
529
        } else {
530
            const ObjectValue *objectValue = getObjectValue();
531
            if (objectValue) {
Christian Kamm's avatar
Christian Kamm committed
532
                const CppComponentValue *qmlValue = value_cast<CppComponentValue>(objectValue);
533
                if (qmlValue) {
534
535
536
                    if (m_majorVersion == -1 && m_minorVersion == -1) {
                        m_majorVersion = qmlValue->componentVersion().majorVersion();
                        m_minorVersion = qmlValue->componentVersion().minorVersion();
537
                        m_qualfiedTypeName = qmlValue->moduleName().toUtf8() + '.' + qmlValue->className().toUtf8();
538
                    } else if (m_majorVersion == qmlValue->componentVersion().majorVersion() && m_minorVersion == qmlValue->componentVersion().minorVersion()) {
539
                        m_qualfiedTypeName = qmlValue->moduleName().toUtf8() + '.' + qmlValue->className().toUtf8();
540
541
542
                    } else {
                        return;
                    }
543
                } else {
Marco Bubke's avatar
Marco Bubke committed
544
                    m_isFileComponent = true;
545
546
547
548
549
550
                    const Imports *imports = context()->imports(document());
                    ImportInfo importInfo = imports->info(lookupNameComponent().last(), context().data());
                    if (importInfo.isValid() && importInfo.type() == ImportInfo::LibraryImport) {
                        m_majorVersion = importInfo.version().majorVersion();
                        m_minorVersion = importInfo.version().minorVersion();
                    }
551
                }
Christian Kamm's avatar
Christian Kamm committed
552
553
                setupPropertyInfo(getTypes(objectValue, context()));
                setupLocalPropertyInfo(getTypes(objectValue, context(), true));
554
                m_defaultPropertyName = context()->defaultPropertyName(objectValue).toUtf8();
555
                m_isValid = true;
Thomas Hartmann's avatar
Thomas Hartmann committed
556
                setupPrototypes();
557
                m_signals = getSignals(objectValue, context());
558
            }
559
560
561
562
        }
    }
}

563
const QmlJS::CppComponentValue *NodeMetaInfoPrivate::getCppComponentValue() const
564
{
565
    const QList<TypeName> nameComponents = m_qualfiedTypeName.split('.');
566
    if (nameComponents.size() < 2)
567
        return 0;
568
    const TypeName type = nameComponents.last();
569

570
    TypeName module;
571
572
    for (int i = 0; i < nameComponents.size() - 1; ++i) {
        if (i != 0)
573
            module += '/';
574
        module += nameComponents.at(i);
575
576
    }

577
    // get the qml object value that's available in the document
578
    foreach (const QmlJS::Import &import, context()->imports(document())->all()) {
579
        if (import.info.path() != QString::fromUtf8(module))
580
            continue;
581
        const Value *lookupResult = import.object->lookupMember(QString::fromUtf8(type), context());
582
583
584
585
586
587
        const CppComponentValue *cppValue = value_cast<CppComponentValue>(lookupResult);
        if (cppValue
                && (m_majorVersion == -1 || m_majorVersion == cppValue->componentVersion().majorVersion())
                && (m_minorVersion == -1 || m_minorVersion == cppValue->componentVersion().minorVersion())
                )
            return cppValue;
588
    }
589

590
591
592
593
594
595
596
597
    const QmlJS::CppComponentValue *value = value_cast<CppComponentValue>(getObjectValue());
    if (value)
        return value;

    // maybe 'type' is a cpp name
    const QmlJS::CppComponentValue *cppValue = context()->valueOwner()->cppQmlTypes().objectByCppName(type);

    return cppValue;
598
}
599

600
const QmlJS::ObjectValue *NodeMetaInfoPrivate::getObjectValue() const
601
{
Christian Kamm's avatar
Christian Kamm committed
602
    return context()->lookupType(document(), lookupNameComponent());
603
}
604

605
QmlJS::ContextPtr NodeMetaInfoPrivate::context() const
606
{
607
    if (m_model && m_model->rewriterView() && m_model->rewriterView()->scopeChain())
Thomas Hartmann's avatar
Thomas Hartmann committed
608
        return m_model->rewriterView()->scopeChain()->context();
609
    return QmlJS::ContextPtr(0);
610
}
611

612
const QmlJS::Document *NodeMetaInfoPrivate::document() const
613
{
614
    if (m_model && m_model->rewriterView())
615
616
617
        return m_model->rewriterView()->document();
    return 0;
}
618

619
620
621
622
void NodeMetaInfoPrivate::setupLocalPropertyInfo(QList<PropertyInfo> localPropertyInfos)
{
    foreach (const PropertyInfo &propertyInfo, localPropertyInfos) {
        m_localProperties.append(propertyInfo.first);
623
624
625
    }
}

626
627
628
629
630
631
632
void NodeMetaInfoPrivate::setupPropertyInfo(QList<PropertyInfo> propertyInfos)
{
    foreach (const PropertyInfo &propertyInfo, propertyInfos) {
        m_properties.append(propertyInfo.first);
        m_propertyTypes.append(propertyInfo.second);
    }
}
633

634
bool NodeMetaInfoPrivate::isPropertyWritable(const PropertyName &propertyName) const
635
{
636
637
    if (!isValid())
        return false;
638

639
    if (propertyName.contains('.')) {
640
641
642
        const PropertyNameList parts = propertyName.split('.');
        const PropertyName objectName = parts.first();
        const PropertyName rawPropertyName = parts.last();
643
        const QString objectType = propertyType(objectName);
644

645
        if (isValueType(objectType))
646
            return true;
647

648
        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType.toUtf8()));
649
650
651
652
        if (objectInfo->isValid())
            return objectInfo->isPropertyWritable(rawPropertyName);
        else
            return true;
653
    }
654

655
    const QmlJS::CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
656
657
    if (!qmlObjectValue)
        return true;
658
659
660
661
    if (qmlObjectValue->hasProperty(propertyName))
        return qmlObjectValue->isWritable(propertyName);
    else
        return true; //all properties of components are writable
662
663
664
}


665
bool NodeMetaInfoPrivate::isPropertyList(const PropertyName &propertyName) const
666
{
667
    if (!isValid())
668
        return false;
669
670

    if (propertyName.contains('.')) {
671
672
673
        const PropertyNameList parts = propertyName.split('.');
        const PropertyName objectName = parts.first();
        const PropertyName rawPropertyName = parts.last();
674
675
        const QString objectType = propertyType(objectName);

676
        if (isValueType(objectType))
677
678
            return false;

679
        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType.toUtf8()));
680
681
682
683
        if (objectInfo->isValid())
            return objectInfo->isPropertyList(rawPropertyName);
        else
            return true;
684
685
    }

686
    const QmlJS::CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
687
688
689
    if (!qmlObjectValue)
        return false;
    return qmlObjectValue->isListProperty(propertyName);
690
}
691

692
bool NodeMetaInfoPrivate::isPropertyPointer(const PropertyName &propertyName) const
693
694
695
{
    if (!isValid())
        return false;
696

697
    if (propertyName.contains('.')) {
698
699
700
        const PropertyNameList parts = propertyName.split('.');
        const PropertyName objectName = parts.first();
        const PropertyName rawPropertyName = parts.last();
701
        const QString objectType = propertyType(objectName);
702

703
        if (isValueType(objectType))
704
            return false;
705

706
        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType.toUtf8()));
707
708
709
710
        if (objectInfo->isValid())
            return objectInfo->isPropertyPointer(rawPropertyName);
        else
            return true;
711
712
    }

713
    const QmlJS::CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
714
715
716
    if (!qmlObjectValue)
        return false;
    return qmlObjectValue->isPointer(propertyName);
717
}
718

719
bool NodeMetaInfoPrivate::isPropertyEnum(const PropertyName &propertyName) const
720
{
721
    if (!isValid())
722
        return false;
723
724

    if (propertyName.contains('.')) {
725
726
727
        const PropertyNameList parts = propertyName.split('.');
        const PropertyName objectName = parts.first();
        const PropertyName rawPropertyName = parts.last();
728
729
        const QString objectType = propertyType(objectName);

730
        if (isValueType(objectType))
731
732
            return false;

733
        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType.toUtf8()));
734
735
736
        if (objectInfo->isValid())
            return objectInfo->isPropertyEnum(rawPropertyName);
        else
737
            return false;
738
739
    }

740
    const CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
Christian Kamm's avatar
Christian Kamm committed
741
742
    if (!qmlObjectValue)
        return false;
Christian Kamm's avatar
Christian Kamm committed
743
    return qmlObjectValue->getEnum(propertyType(propertyName)).isValid();
744
745
}

746
QString NodeMetaInfoPrivate::propertyEnumScope(const PropertyName &propertyName) const
747
{
748
749
750
751
    if (!isValid())
        return QString();

    if (propertyName.contains('.')) {
752
753
754
        const PropertyNameList parts = propertyName.split('.');
        const PropertyName objectName = parts.first();
        const PropertyName rawPropertyName = parts.last();
755
756
        const QString objectType = propertyType(objectName);

757
        if (isValueType(objectType))
758
759
            return QString();

760
        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType.toUtf8()));
761
762
763
764
        if (objectInfo->isValid())
            return objectInfo->propertyEnumScope(rawPropertyName);
        else
            return QString();
765
    }
766

767
    const CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
Christian Kamm's avatar
Christian Kamm committed
768
769
    if (!qmlObjectValue)
        return QString();
770
    const CppComponentValue *definedIn = 0;
Christian Kamm's avatar
Christian Kamm committed
771
772
773
    qmlObjectValue->getEnum(propertyType(propertyName), &definedIn);
    if (definedIn)
        return definedIn->className();
774

775
776
    return QString();
}
777

778
779
780
781
static QString getUnqualifiedName(const QString &name)
{
    const QStringList nameComponents = name.split('.');
    if (nameComponents.size() < 2)
782
        return name;
783
784
785
    return nameComponents.last();
}