nodemetainfo.cpp 37.3 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
hjk's avatar
hjk committed
3
4
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** 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
34

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

#include "metainfo.h"
35
36
#include <model.h>
#include <rewriterview.h>
37
#include <propertyparser.h>
38

39
#include <QSharedData>
hjk's avatar
hjk committed
40
#include <QDebug>
41
42
#include <QIcon>

43
#include <qmljs/qmljsdocument.h>
44
#include <qmljs/qmljscontext.h>
45
#include <qmljs/qmljsbind.h>
Christian Kamm's avatar
Christian Kamm committed
46
#include <qmljs/qmljsscopechain.h>
47
#include <qmljs/parser/qmljsast_p.h>
48
#include <languageutils/fakemetaobject.h>
49
50
51
52
53

namespace QmlDesigner {

namespace Internal {

54
struct TypeDescription
55
{
56
    QString className;
57
    int minorVersion;
58
    int majorVersion;
59
60
};

61
} //Internal
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

/*!
\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
*/

80
81
82
83
84
85
namespace Internal {

using namespace QmlJS;

typedef QPair<QString, QString> PropertyInfo;

86
87
88
QList<PropertyInfo> getObjectTypes(const ObjectValue *ov, const ContextPtr &context, bool local = false);

static QString resolveTypeName(const ASTPropertyReference *ref, const ContextPtr &context,  QList<PropertyInfo> &dotProperties)
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
{
    QString type = QLatin1String("unknown");

    if (!ref->ast()->memberType.isEmpty()) {
        type = ref->ast()->memberType.toString();

        if (type == QLatin1String("alias")) {
            const Value *value = context->lookupReference(ref);

            if (!value)
                return type;

            if (const ASTObjectValue * astObjectValue = value->asAstObjectValue()) {
                if (astObjectValue->typeName())
                    type = astObjectValue->typeName()->name.toString();
            } else if (const ObjectValue * objectValue = value->asObjectValue()) {
                type = objectValue->className();
106
                dotProperties = getObjectTypes(objectValue, context);
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
            } else if (value->asColorValue()) {
                type = QLatin1String("color");
            } else if (value->asUrlValue()) {
                type = QLatin1String("url");
            } else if (value->asStringValue()) {
                type = QLatin1String("string");
            } else if (value->asRealValue()) {
                type = QLatin1String("real");
            } else if (value->asIntValue()) {
                type = QLatin1String("int");
            } else if (value->asBooleanValue()) {
                type = QLatin1String("boolean");
            }
        }
    }

    return type;
}

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

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

private:
    QList<PropertyInfo> m_properties;
170
    const ContextPtr m_context;
171
172
173
};

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

180
const CppComponentValue *findQmlPrototype(const ObjectValue *ov, const ContextPtr &context)
181
{
182
183
184
    if (!ov)
        return 0;

Christian Kamm's avatar
Christian Kamm committed
185
    const CppComponentValue * qmlValue = value_cast<CppComponentValue>(ov);
186
187
188
    if (qmlValue)
        return qmlValue;

Christian Kamm's avatar
Christian Kamm committed
189
    return findQmlPrototype(ov->prototype(context), context);
190
191
}

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

220
QList<PropertyInfo> getQmlTypes(const CppComponentValue *ov, const ContextPtr &context, bool local = false)
221
{
222
223
224
    QList<PropertyInfo> list;
    if (!ov)
        return list;
Thomas Hartmann's avatar
Thomas Hartmann committed
225
226
    if (ov->className().isEmpty())
        return list;
227

228
    PropertyMemberProcessor processor(context);
229
    ov->processMembers(&processor);
230

231
232
233
234
235
236
    QList<PropertyInfo> newList = processor.properties();

    foreach (PropertyInfo property, newList) {
        QString name = property.first;
        if (!ov->isWritable(name) && ov->isPointer(name)) {
            //dot property
Christian Kamm's avatar
Christian Kamm committed
237
            const CppComponentValue * qmlValue = value_cast<CppComponentValue>(ov->lookupMember(name, context));
238
239
240
241
242
243
244
245
246
247
248
            if (qmlValue) {
                QList<PropertyInfo> dotProperties = getQmlTypes(qmlValue, context);
                foreach (const PropertyInfo &propertyInfo, dotProperties) {
                    QString dotName = propertyInfo.first;
                    QString type = propertyInfo.second;
                    dotName = name + '.' + dotName;
                    list.append(qMakePair(dotName, type));
                }
            }
        }
        if (isValueType(ov->propertyType(name))) {
Christian Kamm's avatar
Christian Kamm committed
249
            const ObjectValue *dotObjectValue = value_cast<ObjectValue>(ov->lookupMember(name, context));
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
            if (dotObjectValue) {
                QList<PropertyInfo> dotProperties = getObjectTypes(dotObjectValue, context);
                foreach (const PropertyInfo &propertyInfo, dotProperties) {
                    QString dotName = propertyInfo.first;
                    QString type = propertyInfo.second;
                    dotName = name + '.' + dotName;
                    list.append(qMakePair(dotName, type));
                }
            }
        }
        QString type = property.second;
        if (!ov->isPointer(name) && !ov->isListProperty(name))
            type = ov->propertyType(name);
        list.append(qMakePair(name, type));
    }

    if (!local) {
267
        const ObjectValue* prototype = ov->prototype(context);
268

Christian Kamm's avatar
Christian Kamm committed
269
        const CppComponentValue * qmlObjectValue = value_cast<CppComponentValue>(prototype);
270
271
272
273
274
275
276
277
278

        if (qmlObjectValue) {
            list << getQmlTypes(qmlObjectValue, context);
        } else {
            list << getObjectTypes(prototype, context);
        }
    }

    return list;
279
280
}

281
QList<PropertyInfo> getTypes(const ObjectValue *ov, const ContextPtr &context, bool local = false)
282
{
283
284
    QList<PropertyInfo> list;

Christian Kamm's avatar
Christian Kamm committed
285
    const CppComponentValue * qmlObjectValue = value_cast<CppComponentValue>(ov);
286
287
288
289
290

    if (qmlObjectValue) {
        list << getQmlTypes(qmlObjectValue, context, local);
    } else {
        list << getObjectTypes(ov, context, local);
291
292
    }

293
    return list;
294
295
}

296
QList<PropertyInfo> getObjectTypes(const ObjectValue *ov, const ContextPtr &context, bool local)
297
{
298
299
300
    QList<PropertyInfo> list;
    if (!ov)
        return list;
Thomas Hartmann's avatar
Thomas Hartmann committed
301
302
303
    if (ov->className().isEmpty())
        return list;

304
    PropertyMemberProcessor processor(context);
305
306
307
308
309
    ov->processMembers(&processor);

    list << processor.properties();

    if (!local) {
310
        const ObjectValue* prototype = ov->prototype(context);
311

Thomas Hartmann's avatar
Thomas Hartmann committed
312
313
314
        if (prototype == ov)
            return list;

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

317
318
319
320
321
        if (qmlObjectValue) {
            list << getQmlTypes(qmlObjectValue, context);
        } else {
            list << getObjectTypes(prototype, context);
        }
322
323
    }

324
    return list;
325
326
}

327
class NodeMetaInfoPrivate
328
{
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
public:
    typedef QSharedPointer<NodeMetaInfoPrivate> Pointer;
    NodeMetaInfoPrivate();
    ~NodeMetaInfoPrivate() {}

    bool isValid() const;

    bool isComponent() const
    {
        return m_isComponent;
    }

    QStringList properties() const
    {
        return m_properties;
344
345
    }

346
347
348
349
350
351
352
    QStringList localProperties() const
    {
        return m_localProperties;
    }

    QString defaultPropertyName() const
    {
353
354
355
        if (!m_defaultPropertyName.isEmpty())
            return m_defaultPropertyName;
        return QLatin1String("data");
356
357
358
359
    }

    QString propertyType(const QString &propertyName) const;

360
    void setupPrototypes();
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    QList<TypeDescription> prototypes() const;

    bool isPropertyWritable(const QString &propertyName) const;
    bool isPropertyPointer(const QString &propertyName) const;
    bool isPropertyList(const QString &propertyName) const;
    bool isPropertyEnum(const QString &propertyName) const;
    QString propertyEnumScope(const QString &propertyName) const;
    QStringList keysForEnum(const QString &enumName) const;
    bool cleverCheckType(const QString &otherType) const;
    QVariant::Type variantTypeId(const QString &properyName) const;

    int majorVersion() const
    { return m_majorVersion; }

    int minorVersion() const
    { return m_minorVersion; }

    QString qualfiedTypeName() const
    { return m_qualfiedTypeName; }

    Model *model() const
    { return m_model; }

384
    QString cppPackageName() const;
385
386
387

    QString componentSource() const;
    QString componentFileName() const;
388
    QString importDirectoryPath() const;
389

390
391
    static Pointer create(Model *model, const QString &type, int maj = -1, int min = -1);

392
     QSet<QString> &prototypeCachePositives()
393
     {
394
395
396
397
398
399
         return m_prototypeCachePositives;
     }

     QSet<QString> &prototypeCacheNegatives()
     {
         return m_prototypeCacheNegatives;
400
     }
401

402
403
404
405
406
     static void clearCache()
     {
         m_nodeMetaInfoCache.clear();
     }

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

410
    const QmlJS::CppComponentValue *getCppComponentValue() const;
411
    const QmlJS::ObjectValue *getObjectValue() const;
412
413
414
415
    void setupPropertyInfo(QList<PropertyInfo> propertyInfos);
    void setupLocalPropertyInfo(QList<PropertyInfo> propertyInfos);
    QString lookupName() const;
    QStringList lookupNameComponent() const;
416
    const QmlJS::CppComponentValue *getNearestCppComponentValue() const;
417
    QString fullQualifiedImportAliasType() const;
418
419
420
421
422
423
424
425
426
427

    QString m_qualfiedTypeName;
    int m_majorVersion;
    int m_minorVersion;
    bool m_isValid;
    bool m_isComponent;
    QStringList m_properties;
    QStringList m_propertyTypes;
    QStringList m_localProperties;
    QString 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;

442

443
static inline QString stringIdentifier( const QString &type, int maj, int min)
444
{
445
    return type + QString::number(maj) + '_' + QString::number(min);
446
447
448
449
450
451
452
453
}

NodeMetaInfoPrivate::Pointer NodeMetaInfoPrivate::create(Model *model, const QString &type, int maj, int min)
{
    if (m_nodeMetaInfoCache.contains(stringIdentifier(type, maj, min))) {
        const Pointer &info = m_nodeMetaInfoCache.value(stringIdentifier(type, maj, min));
        if (info->model() == model) {
            return info;
454
        } else {
455
            m_nodeMetaInfoCache.clear();
456
457
        }
    }
458

459
460
    Pointer newData(new NodeMetaInfoPrivate(model, type, maj, min));
    if (newData->isValid())
461
        m_nodeMetaInfoCache.insert(stringIdentifier(type, maj, min), newData);
462
    return newData;
463
464
}

465
466
NodeMetaInfoPrivate::NodeMetaInfoPrivate() : m_isValid(false)
{
467

468
}
469

Kai Koehne's avatar
Kai Koehne committed
470
NodeMetaInfoPrivate::NodeMetaInfoPrivate(Model *model, QString type, int maj, int min) :
471
                                        m_qualfiedTypeName(type), m_majorVersion(maj),
472
                                        m_minorVersion(min), m_isValid(false), m_isComponent(false),
Kai Koehne's avatar
Kai Koehne committed
473
                                        m_model(model)
474
{
Christian Kamm's avatar
Christian Kamm committed
475
    if (context()) {
476
        const CppComponentValue *objectValue = getCppComponentValue();
477
        if (objectValue) {
478
479
480
481
            if (m_majorVersion == -1 && m_minorVersion == -1) {
                m_majorVersion = objectValue->componentVersion().majorVersion();
                m_minorVersion = objectValue->componentVersion().minorVersion();
            }
Christian Kamm's avatar
Christian Kamm committed
482
483
            setupPropertyInfo(getTypes(objectValue, context()));
            setupLocalPropertyInfo(getTypes(objectValue, context(), true));
484
485
486
            m_defaultPropertyName = objectValue->defaultPropertyName();
            setupPrototypes();
            m_isValid = true;
487
        } else {
488
            const ObjectValue *objectValue = getObjectValue();
489
            if (objectValue) {
Christian Kamm's avatar
Christian Kamm committed
490
                const CppComponentValue *qmlValue = value_cast<CppComponentValue>(objectValue);
491
                if (qmlValue) {
492
493
494
495
496
497
498
499
500
                    if (m_majorVersion == -1 && m_minorVersion == -1) {
                        m_majorVersion = qmlValue->componentVersion().majorVersion();
                        m_minorVersion = qmlValue->componentVersion().minorVersion();
                        m_qualfiedTypeName = qmlValue->moduleName() + '.' + qmlValue->className();
                    } else if (m_majorVersion == qmlValue->componentVersion().majorVersion() && m_minorVersion == qmlValue->componentVersion().minorVersion()) {
                        m_qualfiedTypeName = qmlValue->moduleName() + '.' + qmlValue->className();
                    } else {
                        return;
                    }
501
502
503
                } else {
                    m_isComponent = true;
                }
Christian Kamm's avatar
Christian Kamm committed
504
505
506
                setupPropertyInfo(getTypes(objectValue, context()));
                setupLocalPropertyInfo(getTypes(objectValue, context(), true));
                m_defaultPropertyName = context()->defaultPropertyName(objectValue);
507
508
509
                setupPrototypes();
                m_isValid = true;
            }
510
511
512
513
        }
    }
}

514
const QmlJS::CppComponentValue *NodeMetaInfoPrivate::getCppComponentValue() const
515
{
516
517
    const QStringList nameComponents = m_qualfiedTypeName.split('.');
    if (nameComponents.size() < 2)
518
        return 0;
519
    const QString type = nameComponents.last();
520

521
    // maybe 'type' is a cpp name
522
    const QmlJS::CppComponentValue *value = context()->valueOwner()->cppQmlTypes().objectByCppName(type);
523
524
    if (value)
        return value;
525

526
527
528
529
530
    QString module;
    for (int i = 0; i < nameComponents.size() - 1; ++i) {
        if (i != 0)
            module += QLatin1Char('/');
        module += nameComponents.at(i);
531
532
    }

533
534
    // otherwise get the qml object value that's available in the document
    foreach (const QmlJS::Import &import, context()->imports(document())->all()) {
535
        if (import.info.path() != module)
536
537
            continue;
        const Value *lookupResult = import.object->lookupMember(type, context());
538
539
540
541
542
543
        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;
544
    }
545

546
    return 0;
547
}
548

549
const QmlJS::ObjectValue *NodeMetaInfoPrivate::getObjectValue() const
550
{
Christian Kamm's avatar
Christian Kamm committed
551
    return context()->lookupType(document(), lookupNameComponent());
552
}
553

554
QmlJS::ContextPtr NodeMetaInfoPrivate::context() const
555
{
Thomas Hartmann's avatar
Thomas Hartmann committed
556
557
    if (m_model && m_model->rewriterView() && m_model->rewriterView()->scopeChain()) {
        return m_model->rewriterView()->scopeChain()->context();
558
    }
559
    return QmlJS::ContextPtr(0);
560
}
561

562
const QmlJS::Document *NodeMetaInfoPrivate::document() const
563
564
565
566
567
568
{
    if (m_model && m_model->rewriterView()) {
        return m_model->rewriterView()->document();
    }
    return 0;
}
569

570
571
572
573
void NodeMetaInfoPrivate::setupLocalPropertyInfo(QList<PropertyInfo> localPropertyInfos)
{
    foreach (const PropertyInfo &propertyInfo, localPropertyInfos) {
        m_localProperties.append(propertyInfo.first);
574
575
576
    }
}

577
578
579
580
581
582
583
void NodeMetaInfoPrivate::setupPropertyInfo(QList<PropertyInfo> propertyInfos)
{
    foreach (const PropertyInfo &propertyInfo, propertyInfos) {
        m_properties.append(propertyInfo.first);
        m_propertyTypes.append(propertyInfo.second);
    }
}
584

585
bool NodeMetaInfoPrivate::isPropertyWritable(const QString &propertyName) const
586
{
587
588
    if (!isValid())
        return false;
589

590
    if (propertyName.contains('.')) {
591
592
593
        const QStringList parts = propertyName.split('.');
        const QString objectName = parts.first();
        const QString rawPropertyName = parts.last();
594
        const QString objectType = propertyType(objectName);
595

596
597
        if (isValueType(objectType)) {
            return true;
598
599
        }

600
601
602
603
604
        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
        if (objectInfo->isValid())
            return objectInfo->isPropertyWritable(rawPropertyName);
        else
            return true;
605
    }
606

607
    const QmlJS::CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
608
609
    if (!qmlObjectValue)
        return true;
610
611
612
613
    if (qmlObjectValue->hasProperty(propertyName))
        return qmlObjectValue->isWritable(propertyName);
    else
        return true; //all properties of components are writable
614
615
616
}


617
bool NodeMetaInfoPrivate::isPropertyList(const QString &propertyName) const
618
{
619
    if (!isValid())
620
        return false;
621
622

    if (propertyName.contains('.')) {
623
624
625
        const QStringList parts = propertyName.split('.');
        const QString objectName = parts.first();
        const QString rawPropertyName = parts.last();
626
627
628
629
630
631
632
633
634
635
636
        const QString objectType = propertyType(objectName);

        if (isValueType(objectType)) {
            return false;
        }

        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
        if (objectInfo->isValid())
            return objectInfo->isPropertyList(rawPropertyName);
        else
            return true;
637
638
    }

639
    const QmlJS::CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
640
641
642
    if (!qmlObjectValue)
        return false;
    return qmlObjectValue->isListProperty(propertyName);
643
}
644

645
646
647
648
bool NodeMetaInfoPrivate::isPropertyPointer(const QString &propertyName) const
{
    if (!isValid())
        return false;
649

650
    if (propertyName.contains('.')) {
651
652
653
        const QStringList parts = propertyName.split('.');
        const QString objectName = parts.first();
        const QString rawPropertyName = parts.last();
654
        const QString objectType = propertyType(objectName);
655

656
657
        if (isValueType(objectType)) {
            return false;
658
659
        }

660
661
662
663
664
        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
        if (objectInfo->isValid())
            return objectInfo->isPropertyPointer(rawPropertyName);
        else
            return true;
665
666
    }

667
    const QmlJS::CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
668
669
670
    if (!qmlObjectValue)
        return false;
    return qmlObjectValue->isPointer(propertyName);
671
}
672

673
bool NodeMetaInfoPrivate::isPropertyEnum(const QString &propertyName) const
674
{
675
    if (!isValid())
676
        return false;
677
678

    if (propertyName.contains('.')) {
679
680
681
        const QStringList parts = propertyName.split('.');
        const QString objectName = parts.first();
        const QString rawPropertyName = parts.last();
682
683
684
685
686
687
688
689
690
691
        const QString objectType = propertyType(objectName);

        if (isValueType(objectType)) {
            return false;
        }

        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
        if (objectInfo->isValid())
            return objectInfo->isPropertyEnum(rawPropertyName);
        else
692
            return false;
693
694
    }

695
    const CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
Christian Kamm's avatar
Christian Kamm committed
696
697
    if (!qmlObjectValue)
        return false;
Christian Kamm's avatar
Christian Kamm committed
698
    return qmlObjectValue->getEnum(propertyType(propertyName)).isValid();
699
700
}

701
QString NodeMetaInfoPrivate::propertyEnumScope(const QString &propertyName) const
702
{
703
704
705
706
    if (!isValid())
        return QString();

    if (propertyName.contains('.')) {
707
708
709
        const QStringList parts = propertyName.split('.');
        const QString objectName = parts.first();
        const QString rawPropertyName = parts.last();
710
711
712
713
714
715
716
717
718
719
720
        const QString objectType = propertyType(objectName);

        if (isValueType(objectType)) {
            return QString();
        }

        QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
        if (objectInfo->isValid())
            return objectInfo->propertyEnumScope(rawPropertyName);
        else
            return QString();
721
    }
722

723
    const CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
Christian Kamm's avatar
Christian Kamm committed
724
725
    if (!qmlObjectValue)
        return QString();
726
    const CppComponentValue *definedIn = 0;
Christian Kamm's avatar
Christian Kamm committed
727
728
729
    qmlObjectValue->getEnum(propertyType(propertyName), &definedIn);
    if (definedIn)
        return definedIn->className();
730

731
732
    return QString();
}
733

734
735
736
737
738
739
740
741
static QString getUnqualifiedName(const QString &name)
{
    const QStringList nameComponents = name.split('.');
    if (nameComponents.size() < 2)
        return QString();
    return nameComponents.last();
}

742
bool NodeMetaInfoPrivate::cleverCheckType(const QString &otherType) const
743
{
744
745
746
747
748
    if (otherType == qualfiedTypeName())
            return true;

    if (isComponent())
        return false;
749

750
    QStringList split = otherType.split('.');
751
752
753
754
755
    QString package;
    QString typeName = otherType;
    if (split.count() > 1) {
        package = split.first();
        typeName = split.at(1);
756
    }
757
758
    if (cppPackageName() == package)
        return QString(package + '.' + typeName) == cppPackageName() + '.' + getUnqualifiedName(qualfiedTypeName());
759

760
    const CppComponentValue *qmlObjectValue = getCppComponentValue();
Christian Kamm's avatar
Christian Kamm committed
761
762
763
    if (!qmlObjectValue)
        return false;

764
    const LanguageUtils::FakeMetaObject::Export exp =
Christian Kamm's avatar
Christian Kamm committed
765
            qmlObjectValue->metaObject()->exportInPackage(package);
766
767
768
    QString convertedName = exp.type;
    if (convertedName.isEmpty())
        convertedName = qmlObjectValue->className();
769
770

    return typeName == convertedName;
771
}
772

773
QVariant::Type NodeMetaInfoPrivate::variantTypeId(const QString &properyName) const
774
{
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
    QString typeName = propertyType(properyName);
    if (typeName == "string")
        return QVariant::String;

    if (typeName == "color")
        return QVariant::Color;

    if (typeName == "int")
        return QVariant::Int;

    if (typeName == "url")
        return QVariant::Url;

    if (typeName == "real")
        return QVariant::Double;
790

791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
    if (typeName == "bool")
        return QVariant::Bool;

    if (typeName == "boolean")
        return QVariant::Bool;

    if (typeName == "date")
        return QVariant::Date;

    if (typeName == "alias")
        return QVariant::UserType;

    if (typeName == "var")
        return QVariant::UserType;

    return QVariant::nameToType(typeName.toLatin1().data());
807
808
809
}


810
811
812
813
QStringList NodeMetaInfoPrivate::keysForEnum(const QString &enumName) const
{
    if (!isValid())
        return QStringList();
814

815
    const CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
Christian Kamm's avatar
Christian Kamm committed
816
817
818
    if (!qmlObjectValue)
        return QStringList();
    return qmlObjectValue->getEnum(enumName).keys();
819
820
}

821
QString NodeMetaInfoPrivate::cppPackageName() const
822
{
Christian Kamm's avatar
Christian Kamm committed
823
    if (!isComponent()) {
824
        if (const CppComponentValue *qmlObject = getCppComponentValue())
Christian Kamm's avatar
Christian Kamm committed
825
826
            return qmlObject->moduleName();
    }
827
828
829
830
831
832
    return QString();
}

QString NodeMetaInfoPrivate::componentSource() const
{
    if (isComponent()) {
Christian Kamm's avatar
Christian Kamm committed
833
        const ASTObjectValue * astObjectValue = value_cast<ASTObjectValue>(getObjectValue());
834
835
836
        if (astObjectValue)
            return astObjectValue->document()->source().mid(astObjectValue->typeName()->identifierToken.begin(),
                                                            astObjectValue->initializer()->rbraceToken.end());
837
    }
838
839
    return QString();
}
840

841
842
843
QString NodeMetaInfoPrivate::componentFileName() const
{
    if (isComponent()) {
Christian Kamm's avatar
Christian Kamm committed
844
        const ASTObjectValue * astObjectValue = value_cast<ASTObjectValue>(getObjectValue());
845
846
847
848
849
850
851
852
853
        if (astObjectValue) {
            QString fileName;
            int line;
            int column;
            if (astObjectValue->getSourceLocation(&fileName, &line, &column))
                return fileName;
        }
    }
    return QString();
854
855
}

856
857
858
859
860
861
862
863
864
865
QString NodeMetaInfoPrivate::importDirectoryPath() const
{
    if (isValid()) {
        const Imports *imports = context()->imports(document());
        ImportInfo importInfo = imports->info(qualfiedTypeName(), context().data());

        return importInfo.path();
    }
    return QString();
}
866
867

QString NodeMetaInfoPrivate::lookupName() const
868
{
869
870
    QString className = m_qualfiedTypeName;
    QString packageName;
871

872
    QStringList packageClassName = m_qualfiedTypeName.split(QLatin1Char('.'));
873
874
875
876
    if (packageClassName.size() > 1) {
        className = packageClassName.takeLast();
        packageName = packageClassName.join(QLatin1String("."));
    }
877

878
    return CppQmlTypes::qualifiedName(
879
880
881
                packageName,
                className,
                LanguageUtils::ComponentVersion(m_majorVersion, m_minorVersion));
882
883
}

884
QStringList NodeMetaInfoPrivate::lookupNameComponent() const
885
{
886
        QString tempString = fullQualifiedImportAliasType();
887
        return tempString.split('.');
888
889
}

890

891
bool NodeMetaInfoPrivate::isValid() const
892
{
Christian Kamm's avatar
Christian Kamm committed
893
    return m_isValid && context() && document();
894
895
896
897
898
}

QString NodeMetaInfoPrivate::propertyType(const QString &propertyName) const
{
    if (!m_properties.contains(propertyName))
899
        return QLatin1String("Property does not exist...");
900
901
902
    return m_propertyTypes.at(m_properties.indexOf(propertyName));
}

903
void NodeMetaInfoPrivate::setupPrototypes()
904
{
905
    QList<const ObjectValue *> objects;
906
    if (m_isComponent)
907
        objects = PrototypeIterator(getObjectValue(), context()).all();
908
    else
909
        objects = PrototypeIterator(getCppComponentValue(), context()).all();
910

911
    foreach (const ObjectValue *ov, objects) {
912
913
914
915
        TypeDescription description;
        description.className = ov->className();
        description.minorVersion = -1;
        description.majorVersion = -1;
Christian Kamm's avatar
Christian Kamm committed
916
        if (const CppComponentValue * qmlValue = value_cast<CppComponentValue>(ov)) {
917
918
            description.minorVersion = qmlValue->componentVersion().minorVersion();
            description.majorVersion = qmlValue->componentVersion().majorVersion();
919
920
921
922
923
924
925
            LanguageUtils::FakeMetaObject::Export qtquickExport = qmlValue->metaObject()->exportInPackage("QtQuick");
            LanguageUtils::FakeMetaObject::Export cppExport = qmlValue->metaObject()->exportInPackage("<cpp>");
            if (qtquickExport.isValid()) {
                description.className = qtquickExport.package + '.' + qtquickExport.type;
            } else if (qmlValue->moduleName().isEmpty() && cppExport.isValid()) {
                description.className = cppExport.package + '.' + cppExport.type;
            } else if (!qmlValue->moduleName().isEmpty()) {
926
                description.className = qmlValue->moduleName() + '.' + description.className;
927
            }
Marco Bubke's avatar
Marco Bubke committed
928
            m_prototypes.append(description);
929
        } else {
Christian Kamm's avatar
Christian Kamm committed
930
            if (context()->lookupType(document(), QStringList() << ov->className()))
931
932
                m_prototypes.append(description);
        }
933
    }
934
935
936
937
938
939
}


QList<TypeDescription> NodeMetaInfoPrivate::prototypes() const
{
    return m_prototypes;
940
}
941

942
const QmlJS::CppComponentValue *NodeMetaInfoPrivate::getNearestCppComponentValue() const
943
944
{
    if (m_isComponent)
Christian Kamm's avatar
Christian Kamm committed
945
        return findQmlPrototype(getObjectValue(), context());
946
    return getCppComponentValue();
947
948
}

949
950
951
952
953
954
955
QString NodeMetaInfoPrivate::fullQualifiedImportAliasType() const
{
    if (m_model && m_model->rewriterView())
        return model()->rewriterView()->convertTypeToImportAlias(m_qualfiedTypeName);
    return m_qualfiedTypeName;
}

956
957
958
} //namespace Internal

NodeMetaInfo::NodeMetaInfo() : m_privateData(new Internal::NodeMetaInfoPrivate())
959
960
961
962
{

}

963
NodeMetaInfo::NodeMetaInfo(Model *model, QString type, int maj, int min) : m_privateData(Internal::NodeMetaInfoPrivate::create(model, type, maj, min))
964
{
965

966
967
}

968
NodeMetaInfo::~NodeMetaInfo()
969
{
970
}
971

972
973
974
NodeMetaInfo::NodeMetaInfo(const NodeMetaInfo &other)
    : m_privateData(other.m_privateData)
{
975
976
}

977
NodeMetaInfo &NodeMetaInfo::operator=(const NodeMetaInfo &other)
978
{