OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / designercore / metainfo / nodemetainfo.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "nodemetainfo.h"
34 #include "model.h"
35 #include "widgetqueryview.h"
36 #include "invalidargumentexception.h"
37
38 #include "metainfo.h"
39 #include <model.h>
40 #include <rewriterview.h>
41
42 #include <QSharedData>
43 #include <QtDebug>
44 #include <QIcon>
45 #include <QDeclarativeContext>
46 #include <QDeclarativeEngine>
47 #include <QDeclarativeComponent>
48
49 #include <qmljs/qmljslookupcontext.h>
50 #include <qmljs/qmljsdocument.h>
51 #include <qmljs/qmljsinterpreter.h>
52 #include <qmljs/qmljsbind.h>
53 #include <qmljs/parser/qmljsast_p.h>
54 #include <languageutils/fakemetaobject.h>
55 #include <private/qdeclarativemetatype_p.h>
56 #include <private/qdeclarativestringconverters_p.h>
57
58 namespace QmlDesigner {
59
60 namespace Internal {
61
62 struct TypeDescription
63 {
64     QString className;
65     int minorVersion;
66     int majorVersion;
67 };
68
69 } //Internal
70
71 /*!
72 \class QmlDesigner::NodeMetaInfo
73 \ingroup CoreModel
74 \brief The NodeMetaInfo class provides meta information about a qml type.
75
76 A NodeMetaInfo object can be created via ModelNode::metaInfo, or MetaInfo::nodeMetaInfo.
77
78 The object can be invalid - you can check this by calling isValid().
79 The object is invalid if you ask for meta information for
80 an non-existing qml property. Also the node meta info can become invalid
81 if the enclosing type is deregistered from the meta type system (e.g.
82 a sub component qml file is deleted). Trying to call any accessor methods on an invalid
83 NodeMetaInfo object will result in an InvalidMetaInfoException being thrown.
84
85 \see QmlDesigner::MetaInfo, QmlDesigner::PropertyMetaInfo, QmlDesigner::EnumeratorMetaInfo
86 */
87
88 namespace Internal {
89
90 using namespace QmlJS;
91
92 typedef QPair<QString, QString> PropertyInfo;
93
94 class PropertyMemberProcessor : public Interpreter::MemberProcessor
95 {
96 public:
97     virtual bool processProperty(const QString &name, const Interpreter::Value *value)
98     {
99         const Interpreter::ASTPropertyReference *ref = dynamic_cast<const Interpreter::ASTPropertyReference*>(value);
100         if (ref) {
101             QString type = "unknown";
102             if (ref->ast()->memberType)
103                 type = ref->ast()->memberType->asString();
104             m_properties.append(qMakePair(name, type));
105         } else {
106             if (const Interpreter::QmlObjectValue * ov = dynamic_cast<const Interpreter::QmlObjectValue *>(value)) {
107                 QString qualifiedTypeName = ov->packageName().isEmpty() ? ov->className() : ov->packageName() + '.' + ov->className();
108                 m_properties.append(qMakePair(name, qualifiedTypeName));
109             } else {
110                 Interpreter::TypeId typeId;
111                 QString typeName = typeId(value);
112                 if (typeName == QLatin1String("number")) {
113                     if (value->asRealValue()) {
114                         typeName = "real";
115                     } else {
116                     typeName = "int";
117                     }
118                 }
119                 m_properties.append(qMakePair(name, typeName));
120             }
121         }
122         return true;
123     }
124
125     QList<PropertyInfo> properties() const { return m_properties; }
126
127 private:
128     QList<PropertyInfo> m_properties;
129 };
130
131 static inline bool isValueType(const QString &type)
132 {
133     QStringList objectValuesList;
134     objectValuesList << "QFont" << "QPoint" << "QPointF" << "QSize" << "QSizeF" << "QVector3D" << "QVector2D";
135     return objectValuesList.contains(type);
136 }
137
138 const Interpreter::QmlObjectValue *findQmlPrototype(const Interpreter::ObjectValue *ov, LookupContext *context)
139 {
140     if (!ov)
141         return 0;
142
143     const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(ov);
144     if (qmlValue)
145         return qmlValue;
146
147     return findQmlPrototype(ov->prototype(context->context()), context);
148 }
149
150 QStringList prototypes(const Interpreter::ObjectValue *ov, LookupContext::Ptr context, bool versions = false)
151 {
152     QStringList list;
153     if (!ov)
154         return list;
155     ov = ov->prototype(context->context());
156     while (ov) {
157         const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(ov);
158         if (qmlValue) {
159             if (versions) {
160                 list << qmlValue->packageName() + '.' + qmlValue->className() +
161                 ' ' + QString::number(qmlValue->version().majorVersion()) +
162                 '.' + QString::number(qmlValue->version().minorVersion());
163             } else {
164                 list << qmlValue->packageName() + "." + qmlValue->className();
165             }
166         } else {
167             if (versions) {
168                 list << ov->className() + " -1.-1";
169             } else {
170                 list << ov->className();
171             }
172         }
173         ov = ov->prototype(context->context());
174     }
175     return list;
176 }
177
178 QList<PropertyInfo> getObjectTypes(const Interpreter::ObjectValue *ov, LookupContext *context, bool local = false);
179
180 QList<PropertyInfo> getQmlTypes(const Interpreter::QmlObjectValue *ov, LookupContext *context, bool local = false)
181 {
182     QList<PropertyInfo> list;
183     if (!ov)
184         return list;
185
186     PropertyMemberProcessor processor;
187     ov->processMembers(&processor);
188
189     QList<PropertyInfo> newList = processor.properties();
190
191     foreach (PropertyInfo property, newList) {
192         QString name = property.first;
193         if (!ov->isWritable(name) && ov->isPointer(name)) {
194             //dot property
195             const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(ov->property(name, context->context()));
196             if (qmlValue) {
197                 QList<PropertyInfo> dotProperties = getQmlTypes(qmlValue, context);
198                 foreach (const PropertyInfo &propertyInfo, dotProperties) {
199                     QString dotName = propertyInfo.first;
200                     QString type = propertyInfo.second;
201                     dotName = name + '.' + dotName;
202                     list.append(qMakePair(dotName, type));
203                 }
204             }
205         }
206         if (isValueType(ov->propertyType(name))) {
207             const Interpreter::ObjectValue *dotObjectValue = dynamic_cast<const Interpreter::ObjectValue *>(ov->property(name, context->context()));
208             if (dotObjectValue) {
209                 QList<PropertyInfo> dotProperties = getObjectTypes(dotObjectValue, context);
210                 foreach (const PropertyInfo &propertyInfo, dotProperties) {
211                     QString dotName = propertyInfo.first;
212                     QString type = propertyInfo.second;
213                     dotName = name + '.' + dotName;
214                     list.append(qMakePair(dotName, type));
215                 }
216             }
217         }
218         QString type = property.second;
219         if (!ov->isPointer(name) && !ov->isListProperty(name))
220             type = ov->propertyType(name);
221         list.append(qMakePair(name, type));
222     }
223
224     if (!local) {
225         const Interpreter::ObjectValue* prototype = ov->prototype(context->context());
226
227         const Interpreter::QmlObjectValue * qmlObjectValue = dynamic_cast<const Interpreter::QmlObjectValue *>(prototype);
228
229         if (qmlObjectValue) {
230             list << getQmlTypes(qmlObjectValue, context);
231         } else {
232             list << getObjectTypes(prototype, context);
233         }
234     }
235
236     return list;
237 }
238
239 QList<PropertyInfo> getTypes(const Interpreter::ObjectValue *ov, LookupContext *context, bool local = false)
240 {
241     QList<PropertyInfo> list;
242
243     const Interpreter::QmlObjectValue * qmlObjectValue = dynamic_cast<const Interpreter::QmlObjectValue *>(ov);
244
245     if (qmlObjectValue) {
246         list << getQmlTypes(qmlObjectValue, context, local);
247     } else {
248         list << getObjectTypes(ov, context, local);
249     }
250
251     return list;
252 }
253
254 QList<PropertyInfo> getObjectTypes(const Interpreter::ObjectValue *ov, LookupContext *context, bool local)
255 {
256     QList<PropertyInfo> list;
257     if (!ov)
258         return list;
259     PropertyMemberProcessor processor;
260     ov->processMembers(&processor);
261
262     list << processor.properties();
263
264     if (!local) {
265         const Interpreter::ObjectValue* prototype = ov->prototype(context->context());
266
267         const Interpreter::QmlObjectValue * qmlObjectValue = dynamic_cast<const Interpreter::QmlObjectValue *>(prototype);
268
269         if (qmlObjectValue) {
270             list << getQmlTypes(qmlObjectValue, context);
271         } else {
272             list << getObjectTypes(prototype, context);
273         }
274     }
275
276     return list;
277 }
278
279 class NodeMetaInfoPrivate
280 {
281 public:
282     typedef QSharedPointer<NodeMetaInfoPrivate> Pointer;
283     NodeMetaInfoPrivate();
284     ~NodeMetaInfoPrivate() {}
285
286     bool isValid() const;
287
288     bool isComponent() const
289     {
290         return m_isComponent;
291     }
292
293     QStringList properties() const
294     {
295         return m_properties;
296     }
297
298     QStringList localProperties() const
299     {
300         return m_localProperties;
301     }
302
303     QString defaultPropertyName() const
304     {
305         return m_defaultPropertyName;
306     }
307
308     QString propertyType(const QString &propertyName) const;
309
310     void setupPrototypes();
311     QList<TypeDescription> prototypes() const;
312
313     bool isPropertyWritable(const QString &propertyName) const;
314     bool isPropertyPointer(const QString &propertyName) const;
315     bool isPropertyList(const QString &propertyName) const;
316     bool isPropertyEnum(const QString &propertyName) const;
317     QString propertyEnumScope(const QString &propertyName) const;
318     QStringList keysForEnum(const QString &enumName) const;
319     bool cleverCheckType(const QString &otherType) const;
320     QVariant::Type variantTypeId(const QString &properyName) const;
321
322     int majorVersion() const
323     { return m_majorVersion; }
324
325     int minorVersion() const
326     { return m_minorVersion; }
327
328     QString qualfiedTypeName() const
329     { return m_qualfiedTypeName; }
330
331     Model *model() const
332     { return m_model; }
333
334     QString packageName() const;
335
336     QString componentSource() const;
337     QString componentFileName() const;
338
339     static Pointer create(Model *model, const QString &type, int maj = -1, int min = -1);
340
341      QSet<QString> &prototypeCachePositives()
342      {
343          return m_prototypeCachePositives;
344      }
345
346      QSet<QString> &prototypeCacheNegatives()
347      {
348          return m_prototypeCacheNegatives;
349      }
350
351      static void clearCache()
352      {
353          m_nodeMetaInfoCache.clear();
354      }
355
356 private:
357     NodeMetaInfoPrivate(Model *model, QString type, int maj = -1, int min = -1);
358
359     const QmlJS::Interpreter::QmlObjectValue *getQmlObjectValue() const;
360     const QmlJS::Interpreter::ObjectValue *getObjectValue() const;
361     void setupPropertyInfo(QList<PropertyInfo> propertyInfos);
362     void setupLocalPropertyInfo(QList<PropertyInfo> propertyInfos);
363     QString lookupName() const;
364     QStringList lookupNameComponent() const;
365     const QmlJS::Interpreter::QmlObjectValue *getNearestQmlObjectValue() const;
366
367     QString m_qualfiedTypeName;
368     int m_majorVersion;
369     int m_minorVersion;
370     bool m_isValid;
371     bool m_isComponent;
372     QStringList m_properties;
373     QStringList m_propertyTypes;
374     QStringList m_localProperties;
375     QString m_defaultPropertyName;
376     QList<TypeDescription> m_prototypes;
377     QSet<QString> m_prototypeCachePositives;
378     QSet<QString> m_prototypeCacheNegatives;
379
380     //storing the pointer would not be save
381     QmlJS::LookupContext *lookupContext() const;
382     QmlJS::Document *document() const;
383
384     QPointer<Model> m_model;
385     static QHash<QString, Pointer> m_nodeMetaInfoCache;
386 };
387
388 QHash<QString, NodeMetaInfoPrivate::Pointer> NodeMetaInfoPrivate::m_nodeMetaInfoCache;
389
390
391 static inline QString stringIdentifier( const QString &type, int maj, int min)
392 {
393     return type + QString::number(maj) + '_' + QString::number(min);
394 }
395
396 NodeMetaInfoPrivate::Pointer NodeMetaInfoPrivate::create(Model *model, const QString &type, int maj, int min)
397 {
398     if (m_nodeMetaInfoCache.contains(stringIdentifier(type, maj, min))) {
399         const Pointer &info = m_nodeMetaInfoCache.value(stringIdentifier(type, maj, min));
400         if (info->model() == model) {
401             return info;
402         } else {
403             m_nodeMetaInfoCache.clear();
404         }
405     }
406
407     Pointer newData(new NodeMetaInfoPrivate(model, type, maj, min));
408     if (newData->isValid())
409         m_nodeMetaInfoCache.insert(stringIdentifier(type, maj, min), newData);
410     return newData;
411 }
412
413 NodeMetaInfoPrivate::NodeMetaInfoPrivate() : m_isValid(false)
414 {
415
416 }
417
418 NodeMetaInfoPrivate::NodeMetaInfoPrivate(Model *model, QString type, int maj, int min) :
419                                         m_qualfiedTypeName(type), m_majorVersion(maj),
420                                         m_minorVersion(min), m_isValid(false), m_isComponent(false),
421                                         m_model(model)
422 {
423     if (lookupContext()) {
424         const Interpreter::QmlObjectValue *objectValue = getQmlObjectValue();
425         if (objectValue) {
426             setupPropertyInfo(getTypes(objectValue, lookupContext()));
427             setupLocalPropertyInfo(getTypes(objectValue, lookupContext(), true));
428             m_defaultPropertyName = objectValue->defaultPropertyName();
429             setupPrototypes();
430             m_isValid = true;
431         } else {
432             m_qualfiedTypeName = m_qualfiedTypeName.split('.').last();
433             const Interpreter::ObjectValue *objectValue = getObjectValue();
434             if (objectValue) {
435                 const Interpreter::QmlObjectValue *qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(objectValue);
436                 if (qmlValue) {
437                     m_majorVersion = qmlValue->version().majorVersion();
438                     m_minorVersion = qmlValue->version().minorVersion();
439                     m_qualfiedTypeName = qmlValue->packageName() + '.' + qmlValue->className();
440                 } else {
441                     m_isComponent = true;
442                 }
443                 setupPropertyInfo(getTypes(objectValue, lookupContext()));
444                 setupLocalPropertyInfo(getTypes(objectValue, lookupContext(), true));
445                 m_defaultPropertyName = lookupContext()->context()->defaultPropertyName(objectValue);
446                 setupPrototypes();
447                 m_isValid = true;
448             }
449         }
450     }
451 }
452
453 const QmlJS::Interpreter::QmlObjectValue *NodeMetaInfoPrivate::getQmlObjectValue() const
454 {
455     return lookupContext()->engine()->cppQmlTypes().typeByQualifiedName(lookupName());
456 }
457
458 const QmlJS::Interpreter::ObjectValue *NodeMetaInfoPrivate::getObjectValue() const
459 {
460     return lookupContext()->context()->lookupType(document(), lookupNameComponent());
461 }
462
463 QmlJS::LookupContext *NodeMetaInfoPrivate::lookupContext() const
464 {
465     if (m_model && m_model->rewriterView()) {
466         return m_model->rewriterView()->lookupContext();
467     }
468     return 0;
469 }
470
471 QmlJS::Document *NodeMetaInfoPrivate::document() const
472 {
473     if (m_model && m_model->rewriterView()) {
474         return m_model->rewriterView()->document();
475     }
476     return 0;
477 }
478
479 void NodeMetaInfoPrivate::setupLocalPropertyInfo(QList<PropertyInfo> localPropertyInfos)
480 {
481     foreach (const PropertyInfo &propertyInfo, localPropertyInfos) {
482         m_localProperties.append(propertyInfo.first);
483     }
484 }
485
486 void NodeMetaInfoPrivate::setupPropertyInfo(QList<PropertyInfo> propertyInfos)
487 {
488     foreach (const PropertyInfo &propertyInfo, propertyInfos) {
489         m_properties.append(propertyInfo.first);
490         m_propertyTypes.append(propertyInfo.second);
491     }
492 }
493
494 bool NodeMetaInfoPrivate::isPropertyWritable(const QString &propertyName) const
495 {
496     if (!isValid())
497         return false;
498
499     if (propertyName.contains('.')) {
500         const QStringList parts = propertyName.split('.');
501         const QString objectName = parts.first();
502         const QString rawPropertyName = parts.last();
503         const QString objectType = propertyType(objectName);
504
505         if (isValueType(objectType)) {
506             return true;
507         }
508
509         QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
510         if (objectInfo->isValid())
511             return objectInfo->isPropertyWritable(rawPropertyName);
512         else
513             return true;
514     }
515
516     const QmlJS::Interpreter::QmlObjectValue *qmlObjectValue = getNearestQmlObjectValue();
517     if (!qmlObjectValue)
518         return true;
519     if (qmlObjectValue->hasProperty(propertyName))
520         return qmlObjectValue->isWritable(propertyName);
521     else
522         return true; //all properties of components are writable
523 }
524
525
526 bool NodeMetaInfoPrivate::isPropertyList(const QString &propertyName) const
527 {
528     if (!isValid())
529         return false;
530
531     if (propertyName.contains('.')) {
532         const QStringList parts = propertyName.split('.');
533         const QString objectName = parts.first();
534         const QString rawPropertyName = parts.last();
535         const QString objectType = propertyType(objectName);
536
537         if (isValueType(objectType)) {
538             return false;
539         }
540
541         QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
542         if (objectInfo->isValid())
543             return objectInfo->isPropertyList(rawPropertyName);
544         else
545             return true;
546     }
547
548     const QmlJS::Interpreter::QmlObjectValue *qmlObjectValue = getNearestQmlObjectValue();
549     if (!qmlObjectValue)
550         return false;
551     return qmlObjectValue->isListProperty(propertyName);
552 }
553
554 bool NodeMetaInfoPrivate::isPropertyPointer(const QString &propertyName) const
555 {
556     if (!isValid())
557         return false;
558
559     if (propertyName.contains('.')) {
560         const QStringList parts = propertyName.split('.');
561         const QString objectName = parts.first();
562         const QString rawPropertyName = parts.last();
563         const QString objectType = propertyType(objectName);
564
565         if (isValueType(objectType)) {
566             return false;
567         }
568
569         QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
570         if (objectInfo->isValid())
571             return objectInfo->isPropertyPointer(rawPropertyName);
572         else
573             return true;
574     }
575
576     const QmlJS::Interpreter::QmlObjectValue *qmlObjectValue = getNearestQmlObjectValue();
577     if (!qmlObjectValue)
578         return false;
579     return qmlObjectValue->isPointer(propertyName);
580 }
581
582 bool NodeMetaInfoPrivate::isPropertyEnum(const QString &propertyName) const
583 {
584     if (!isValid())
585         return false;
586
587     if (propertyName.contains('.')) {
588         const QStringList parts = propertyName.split('.');
589         const QString objectName = parts.first();
590         const QString rawPropertyName = parts.last();
591         const QString objectType = propertyType(objectName);
592
593         if (isValueType(objectType)) {
594             return false;
595         }
596
597         QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
598         if (objectInfo->isValid())
599             return objectInfo->isPropertyEnum(rawPropertyName);
600         else
601             return false;
602     }
603
604     QList<const Interpreter::ObjectValue *> objects;
605     objects = Interpreter::PrototypeIterator(getNearestQmlObjectValue(), lookupContext()->context()).all();
606
607     //We have to run the prototype chain
608     foreach (const Interpreter::ObjectValue *ov, objects) {
609         if (const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(ov)) {
610             if (qmlValue->isEnum(propertyType(propertyName)))
611                 return true;
612         }
613     }
614
615     return false;
616 }
617
618 QString NodeMetaInfoPrivate::propertyEnumScope(const QString &propertyName) const
619 {
620     if (!isValid())
621         return QString();
622
623     if (propertyName.contains('.')) {
624         const QStringList parts = propertyName.split('.');
625         const QString objectName = parts.first();
626         const QString rawPropertyName = parts.last();
627         const QString objectType = propertyType(objectName);
628
629         if (isValueType(objectType)) {
630             return QString();
631         }
632
633         QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
634         if (objectInfo->isValid())
635             return objectInfo->propertyEnumScope(rawPropertyName);
636         else
637             return QString();
638     }
639
640     QList<const Interpreter::ObjectValue *> objects;
641     objects = Interpreter::PrototypeIterator(getNearestQmlObjectValue(), lookupContext()->context()).all();
642
643     //We have to run the prototype chain
644     foreach (const Interpreter::ObjectValue *ov, objects) {
645         if (const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(ov)) {
646             if (qmlValue->isEnum(propertyType(propertyName)))
647                 return qmlValue->className();
648         }
649     }
650
651     return QString();
652 }
653
654 bool NodeMetaInfoPrivate::cleverCheckType(const QString &otherType) const
655 {
656     if (otherType == qualfiedTypeName())
657             return true;
658
659     if (isComponent())
660         return false;
661
662     QStringList split = otherType.split('.');
663     QString package;
664     QString typeName = otherType;
665     if (split.count() > 1) {
666         package = split.first();
667         typeName = split.at(1);
668     }
669     if (packageName() == package)
670         return QString(package + '.' + typeName) == qualfiedTypeName();
671
672     const LanguageUtils::FakeMetaObject::Export exp =
673             getQmlObjectValue()->metaObject()->exportInPackage(package);
674     const QString convertedName = exp.type;
675
676     return typeName == convertedName;
677 }
678
679 QVariant::Type NodeMetaInfoPrivate::variantTypeId(const QString &properyName) const
680 {
681     QString typeName = propertyType(properyName);
682     if (typeName == "string")
683         return QVariant::String;
684
685     if (typeName == "color")
686         return QVariant::Color;
687
688     if (typeName == "int")
689         return QVariant::Int;
690
691     if (typeName == "url")
692         return QVariant::Url;
693
694     if (typeName == "real")
695         return QVariant::Double;
696
697     if (typeName == "bool")
698         return QVariant::Bool;
699
700     if (typeName == "boolean")
701         return QVariant::Bool;
702
703     if (typeName == "date")
704         return QVariant::Date;
705
706     if (typeName == "alias")
707         return QVariant::UserType;
708
709     if (typeName == "var")
710         return QVariant::UserType;
711
712     return QVariant::nameToType(typeName.toLatin1().data());
713 }
714
715
716 QStringList NodeMetaInfoPrivate::keysForEnum(const QString &enumName) const
717 {
718     if (!isValid())
719         return QStringList();
720
721     return getNearestQmlObjectValue()->keysForEnum(enumName);
722 }
723
724 QString NodeMetaInfoPrivate::packageName() const
725 {
726     if (!isComponent())
727         return getQmlObjectValue()->packageName();
728     return QString();
729 }
730
731 QString NodeMetaInfoPrivate::componentSource() const
732 {
733     if (isComponent()) {
734         const Interpreter::ASTObjectValue * astObjectValue = dynamic_cast<const Interpreter::ASTObjectValue *>(getObjectValue());
735         if (astObjectValue)
736             return astObjectValue->document()->source().mid(astObjectValue->typeName()->identifierToken.begin(),
737                                                             astObjectValue->initializer()->rbraceToken.end());
738     }
739     return QString();
740 }
741
742 QString NodeMetaInfoPrivate::componentFileName() const
743 {
744     if (isComponent()) {
745         const Interpreter::ASTObjectValue * astObjectValue = dynamic_cast<const Interpreter::ASTObjectValue *>(getObjectValue());
746         if (astObjectValue) {
747             QString fileName;
748             int line;
749             int column;
750             if (astObjectValue->getSourceLocation(&fileName, &line, &column))
751                 return fileName;
752         }
753     }
754     return QString();
755 }
756
757
758 QString NodeMetaInfoPrivate::lookupName() const
759 {
760     QString className = m_qualfiedTypeName;
761     QString packageName;
762
763     QStringList packageClassName = m_qualfiedTypeName.split(QLatin1Char('.'));
764     if (packageClassName.size() > 1) {
765         className = packageClassName.takeLast();
766         packageName = packageClassName.join(QLatin1String("."));
767     }
768
769     return Interpreter::CppQmlTypes::qualifiedName(
770                 packageName,
771                 className,
772                 LanguageUtils::ComponentVersion(m_majorVersion, m_minorVersion));
773 }
774
775 QStringList NodeMetaInfoPrivate::lookupNameComponent() const
776 {
777     QString tempString = m_qualfiedTypeName;
778     return tempString.split('.');
779 }
780
781 bool NodeMetaInfoPrivate::isValid() const
782 {
783     return m_isValid && lookupContext() && document();
784 }
785
786 QString NodeMetaInfoPrivate::propertyType(const QString &propertyName) const
787 {
788     if (!m_properties.contains(propertyName))
789         return QString();
790     return m_propertyTypes.at(m_properties.indexOf(propertyName));
791 }
792
793 void NodeMetaInfoPrivate::setupPrototypes()
794 {
795     QList<const Interpreter::ObjectValue *> objects;
796     if (m_isComponent)
797         objects = Interpreter::PrototypeIterator(getObjectValue(), lookupContext()->context()).all();
798     else
799         objects = Interpreter::PrototypeIterator(getQmlObjectValue(), lookupContext()->context()).all();
800     foreach (const Interpreter::ObjectValue *ov, objects) {
801         TypeDescription description;
802         description.className = ov->className();
803         description.minorVersion = -1;
804         description.majorVersion = -1;
805         if (const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(ov)) {
806             description.minorVersion = qmlValue->version().minorVersion();
807             description.majorVersion = qmlValue->version().majorVersion();
808             if (!qmlValue->packageName().isEmpty())
809                 description.className = qmlValue->packageName() + '.' + description.className;
810             m_prototypes.append(description);
811         } else {
812             if (lookupContext()->context()->lookupType(document(), QStringList() << ov->className()))
813                 m_prototypes.append(description);
814         }
815     }
816 }
817
818
819 QList<TypeDescription> NodeMetaInfoPrivate::prototypes() const
820 {
821     return m_prototypes;
822 }
823
824 const QmlJS::Interpreter::QmlObjectValue *NodeMetaInfoPrivate::getNearestQmlObjectValue() const
825 {
826     if (m_isComponent)
827         return findQmlPrototype(getObjectValue(), lookupContext());
828     return getQmlObjectValue();
829 }
830
831 } //namespace Internal
832
833 NodeMetaInfo::NodeMetaInfo() : m_privateData(new Internal::NodeMetaInfoPrivate())
834 {
835
836 }
837
838 NodeMetaInfo::NodeMetaInfo(Model *model, QString type, int maj, int min) : m_privateData(Internal::NodeMetaInfoPrivate::create(model, type, maj, min))
839 {
840
841 }
842
843 NodeMetaInfo::~NodeMetaInfo()
844 {
845 }
846
847 NodeMetaInfo::NodeMetaInfo(const NodeMetaInfo &other)
848     : m_privateData(other.m_privateData)
849 {
850 }
851
852 NodeMetaInfo &NodeMetaInfo::operator=(const NodeMetaInfo &other)
853 {
854     if (this != &other)
855         this->m_privateData = other.m_privateData;
856
857     return *this;
858 }
859
860 bool NodeMetaInfo::isValid() const
861 {
862     return m_privateData->isValid();
863 }
864
865 bool NodeMetaInfo::isComponent() const
866 {
867     return m_privateData->isComponent();
868 }
869
870 bool NodeMetaInfo::hasProperty(const QString &propertyName) const
871 {
872     return propertyNames().contains(propertyName);
873 }
874
875 QStringList NodeMetaInfo::propertyNames() const
876 {
877     return m_privateData->properties();
878 }
879
880 QStringList NodeMetaInfo::directPropertyNames() const
881 {
882     return m_privateData->localProperties();
883 }
884
885 QString NodeMetaInfo::defaultPropertyName() const
886 {
887     return m_privateData->defaultPropertyName();
888 }
889
890 bool NodeMetaInfo::hasDefaultProperty() const
891 {
892     return !defaultPropertyName().isEmpty();
893 }
894
895 QString NodeMetaInfo::propertyTypeName(const QString &propertyName) const
896 {
897     return m_privateData->propertyType(propertyName);
898 }
899
900 bool NodeMetaInfo::propertyIsWritable(const QString &propertyName) const
901 {
902     return m_privateData->isPropertyWritable(propertyName);
903 }
904
905 bool NodeMetaInfo::propertyIsListProperty(const QString &propertyName) const
906 {
907     return m_privateData->isPropertyList(propertyName);
908 }
909
910 bool NodeMetaInfo::propertyIsEnumType(const QString &propertyName) const
911 {
912     return m_privateData->isPropertyEnum(propertyName);
913 }
914
915 QString NodeMetaInfo::propertyEnumScope(const QString &propertyName) const
916 {
917     return m_privateData->propertyEnumScope(propertyName);
918 }
919
920 QStringList NodeMetaInfo::propertyKeysForEnum(const QString &propertyName) const
921 {
922     return m_privateData->keysForEnum(propertyTypeName(propertyName));
923 }
924
925 QVariant NodeMetaInfo::propertyCastedValue(const QString &propertyName, const QVariant &value) const
926 {
927
928     QVariant variant = value;
929     if (propertyIsEnumType(propertyName)) {
930         return variant;
931     }
932
933     const QString typeName = propertyTypeName(propertyName);
934
935     QVariant::Type typeId = m_privateData->variantTypeId(propertyName);
936
937     if (variant.type() == QVariant::UserType && variant.userType() == ModelNode::variantUserType()) {
938         return variant;
939     } else if (typeId == QVariant::UserType && typeName == QLatin1String("QVariant")) {
940         return variant;
941     } else if (typeId == QVariant::UserType && typeName == QLatin1String("variant")) {
942         return variant;
943     } else if (typeId == QVariant::UserType && typeName == QLatin1String("var")) {
944         return variant;
945     } else if (variant.type() == QVariant::List && variant.type() == QVariant::List) {
946         // TODO: check the contents of the list
947         return variant;
948     } else if (typeName == "var" || typeName == "variant") {
949         return variant;
950     } else if (typeName == "alias") {
951         // TODO: The QML compiler resolves the alias type. We probably should do the same.
952         return variant;
953     } else if (variant.convert(typeId)) {
954         return variant;
955     }
956
957     return QDeclarativeStringConverters::variantFromString(variant.toString());
958
959 }
960
961 QList<NodeMetaInfo> NodeMetaInfo::superClasses() const
962 {
963     QList<NodeMetaInfo> list;
964
965     foreach (const Internal::TypeDescription &type,  m_privateData->prototypes()) {
966         list.append(NodeMetaInfo(m_privateData->model(), type.className, type.majorVersion, type.minorVersion));
967     }
968     return list;
969 }
970
971 NodeMetaInfo NodeMetaInfo::directSuperClass() const
972 {
973     QList<NodeMetaInfo> superClassesList = superClasses();
974     if (superClassesList.count() > 1)
975         return superClassesList.at(1);
976     return NodeMetaInfo();
977 }
978
979 QString NodeMetaInfo::typeName() const
980 {
981     return m_privateData->qualfiedTypeName();
982 }
983 int NodeMetaInfo::majorVersion() const
984 {
985     return m_privateData->majorVersion();
986 }
987 int NodeMetaInfo::minorVersion() const
988 {
989     return m_privateData->minorVersion();
990 }
991
992 QString NodeMetaInfo::componentSource() const
993 {
994     return m_privateData->componentSource();
995 }
996
997 QString NodeMetaInfo::componentFileName() const
998 {
999     return NodeMetaInfo::m_privateData->componentFileName();
1000 }
1001
1002 bool NodeMetaInfo::availableInVersion(int majorVersion, int minorVersion) const
1003 {
1004     if (majorVersion == -1 && minorVersion == -1)
1005         return true;
1006
1007     return (m_privateData->majorVersion() >= majorVersion)
1008         || (majorVersion == m_privateData->majorVersion() && m_privateData->minorVersion() >= minorVersion);
1009 }
1010
1011 bool NodeMetaInfo::isSubclassOf(const QString &type, int majorVersion, int minorVersion) const
1012 {
1013     if (!isValid()) {
1014         qWarning() << "NodeMetaInfo is invalid";
1015         return false;
1016     }
1017
1018     if (typeName() == type
1019         && availableInVersion(majorVersion, minorVersion))
1020         return true;
1021
1022     if (m_privateData->prototypeCachePositives().contains(Internal::stringIdentifier(type, majorVersion, minorVersion)))
1023         return true; //take a shortcut - optimization
1024
1025     if (m_privateData->prototypeCacheNegatives().contains(Internal::stringIdentifier(type, majorVersion, minorVersion)))
1026         return false; //take a shortcut - optimization
1027
1028     foreach (const NodeMetaInfo &superClass, superClasses()) {
1029         if (superClass.m_privateData->cleverCheckType(type)
1030             && superClass.availableInVersion(majorVersion, minorVersion)) {
1031                 m_privateData->prototypeCachePositives().insert(Internal::stringIdentifier(type, majorVersion, minorVersion));
1032             return true;
1033         }
1034     }
1035     m_privateData->prototypeCacheNegatives().insert(Internal::stringIdentifier(type, majorVersion, minorVersion));
1036     return false;
1037 }
1038
1039 void NodeMetaInfo::clearCache()
1040 {
1041     Internal::NodeMetaInfoPrivate::clearCache();
1042 }
1043
1044 } // namespace QmlDesigner