OSDN Git Service

Merge remote branch 'origin/2.0'
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / designercore / metainfo / metainfo.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #include "metainfo.h"
31
32 #include "abstractproperty.h"
33 #include "modelnode.h"
34 #include "invalidmodelnodeexception.h"
35 #include "invalidargumentexception.h"
36 #include "propertymetainfo.h"
37 #include "metainfoparser.h"
38 #include "iwidgetplugin.h"
39
40 #include "model/variantparser.h"
41 #include "pluginmanager/widgetpluginmanager.h"
42
43 #include <QtDebug>
44 #include <QPair>
45 #include <QtAlgorithms>
46 #include <QMetaProperty>
47 #include <QDeclarativeEngine>
48
49 #include <private/qdeclarativemetatype_p.h>
50 #include <private/qdeclarativeanchors_p.h>
51
52 enum {
53     debug = false
54 };
55
56 namespace QmlDesigner {
57 namespace Internal {
58
59 class MetaInfoPrivate
60 {
61     Q_DISABLE_COPY(MetaInfoPrivate)
62 public:
63     typedef QSharedPointer<MetaInfoPrivate> Pointer;
64     typedef QWeakPointer<MetaInfoPrivate> WeakPointer;
65
66
67     MetaInfoPrivate(MetaInfo *q);
68     void clear();
69
70     void initialize();
71     void parseQmlTypes();
72     void parseNonQmlTypes();
73     void parseValueTypes();
74     void parseNonQmlClassRecursively(const QMetaObject *qMetaObject, int majorVersion, int minorVersion);
75     void parseProperties(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const;
76     void parseClassInfo(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const;
77
78     QString typeName(const QMetaObject *qMetaObject) const;
79
80     void parseXmlFiles();
81
82     QMultiHash<QString, NodeMetaInfo> m_nodeMetaInfoHash;
83     QHash<QString, EnumeratorMetaInfo> m_enumeratorMetaInfoHash;
84     QHash<QString, QString> m_QtTypesToQmlTypes;
85     QScopedPointer<ItemLibraryInfo> m_itemLibraryInfo;
86
87     MetaInfo *m_q;
88     bool m_isInitialized;
89 };
90
91 MetaInfoPrivate::MetaInfoPrivate(MetaInfo *q) :
92         m_itemLibraryInfo(new ItemLibraryInfo()),
93         m_q(q),
94         m_isInitialized(false)
95 {
96     if (!m_q->isGlobal())
97         m_itemLibraryInfo->setBaseInfo(MetaInfo::global().itemLibraryInfo());
98 }
99
100 void MetaInfoPrivate::clear()
101 {
102     m_nodeMetaInfoHash.clear();
103     m_enumeratorMetaInfoHash.clear();
104     m_itemLibraryInfo->clearEntries();
105     m_isInitialized = false;
106 }
107
108 void MetaInfoPrivate::initialize()
109 {
110     // make sure QmlGraphicsItemsModule gets initialized, that is
111     // QmlGraphicsItemsModule::defineModule called
112     QDeclarativeEngine engine;
113     Q_UNUSED(engine);
114
115     parseQmlTypes();
116     parseNonQmlTypes();
117     parseXmlFiles();
118     parseValueTypes();
119
120     m_isInitialized = true;
121 }
122
123
124
125 void MetaInfoPrivate::parseProperties(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const
126 {
127     Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject");
128     Q_ASSERT_X(nodeMetaInfo.isValid(), Q_FUNC_INFO, "invalid NodeMetaInfo");
129
130     for (int i = qMetaObject->propertyOffset(); i < qMetaObject->propertyCount(); ++i) {
131         QMetaProperty qProperty = qMetaObject->property(i);
132
133         PropertyMetaInfo propertyInfo;
134
135         propertyInfo.setName(QLatin1String(qProperty.name()));
136
137         QString typeName(qProperty.typeName());
138         QString noStar = typeName;
139         bool star = false;
140         while (noStar.contains('*')) {//strip star
141             noStar.chop(1);
142             star = true;
143         }
144         if (m_QtTypesToQmlTypes.contains(noStar)) {
145             typeName = star ? m_QtTypesToQmlTypes.value(noStar) + '*' : m_QtTypesToQmlTypes.value(noStar);
146             //### versions
147         }
148         propertyInfo.setType(typeName);
149         propertyInfo.setValid(true);
150         propertyInfo.setReadable(qProperty.isReadable());
151         propertyInfo.setWritable(qProperty.isWritable());
152         propertyInfo.setResettable(qProperty.isResettable());
153         propertyInfo.setEnumType(qProperty.isEnumType());
154         propertyInfo.setFlagType(qProperty.isFlagType());
155
156         if (propertyInfo.isEnumType()) {
157             QMetaEnum qEnumerator = qProperty.enumerator();
158             EnumeratorMetaInfo enumerator = m_q->addEnumerator(qEnumerator.scope(), qEnumerator.name());
159
160             enumerator.setValid(qEnumerator.isValid());
161             enumerator.setIsFlagType(qEnumerator.isFlag());
162             enumerator.setScope(qEnumerator.scope());
163             enumerator.setName(qEnumerator.name());
164             for (int i = 0 ;i < qEnumerator.keyCount(); i++)
165             {
166                 enumerator.addElement(qEnumerator.valueToKey(i), i);
167             }
168
169             propertyInfo.setEnumerator(enumerator);
170             
171         }
172
173         nodeMetaInfo.addProperty(propertyInfo);
174     }
175 }
176
177 void MetaInfoPrivate::parseClassInfo(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const
178 {
179     Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject");
180     Q_ASSERT_X(nodeMetaInfo.isValid(), Q_FUNC_INFO, "invalid NodeMetaInfo");
181     for (int index = qMetaObject->classInfoCount() - 1 ; index >= 0 ; --index) {
182         QMetaClassInfo classInfo = qMetaObject->classInfo(index);
183         if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
184             nodeMetaInfo.setDefaultProperty(classInfo.value());
185             return;
186         }
187     }
188 }
189
190 void MetaInfoPrivate::parseNonQmlClassRecursively(const QMetaObject *qMetaObject, int majorVersion, int minorVersion)
191 {
192     Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject");
193     const QString className = qMetaObject->className();
194
195     if (className.isEmpty()) {
196         qWarning() << "Meta type system: Registered class has no name.";
197         return;
198     }
199
200     if (!m_q->hasNodeMetaInfo(typeName(qMetaObject), majorVersion, minorVersion)) {
201         NodeMetaInfo nodeMetaInfo(*m_q);
202         nodeMetaInfo.setType(typeName(qMetaObject), majorVersion, minorVersion);
203         parseProperties(nodeMetaInfo, qMetaObject);
204         parseClassInfo(nodeMetaInfo, qMetaObject);
205
206         if (debug)
207             qDebug() << "adding non qml type" << nodeMetaInfo.typeName() << nodeMetaInfo.majorVersion() << nodeMetaInfo.minorVersion() << ", parent type" << typeName(qMetaObject->superClass());
208         if (qMetaObject->superClass())
209             nodeMetaInfo.setSuperClass(typeName(qMetaObject->superClass()));
210
211         m_q->addNodeInfo(nodeMetaInfo);
212     }
213
214     if (const QMetaObject *superClass = qMetaObject->superClass()) {
215         parseNonQmlClassRecursively(superClass, majorVersion, minorVersion);
216     }
217 }
218
219
220 QString MetaInfoPrivate::typeName(const QMetaObject *qMetaObject) const
221 {
222     if (!qMetaObject)
223         return QString();
224     QString className = qMetaObject->className();
225     if (QDeclarativeType *qmlType = QDeclarativeMetaType::qmlType(qMetaObject)) {
226         QString qmlClassName(qmlType->qmlTypeName());
227         if (!qmlClassName.isEmpty())
228             className = qmlType->qmlTypeName(); // Ensure that we always use the qml name,
229                                             // if available.
230     }
231     return className;
232 }
233
234 void MetaInfoPrivate::parseValueTypes()
235 {
236     QStringList valueTypes;
237     //there is no global list of all supported value types
238     valueTypes << "QFont"
239                << "QPoint"
240                << "QPointF"
241                << "QRect"
242                << "QRectF"
243                << "QSize"
244                << "QSizeF"
245                << "QVector3D"
246                << "QEasingCurve";
247
248     foreach (const QString &type, valueTypes) {
249         NodeMetaInfo nodeMetaInfo(*m_q);
250         nodeMetaInfo.setType(type, -1, -1);
251         foreach (const QString &propertyName, VariantParser::create(type).properties()) {
252             PropertyMetaInfo propertyInfo;
253             propertyInfo.setName(propertyName);
254             propertyInfo.setType("real");
255             if (type == ("QFont")) {
256                 if (propertyName == "bold")
257                     propertyInfo.setType("bool");
258                 else if (propertyName == "italic")
259                     propertyInfo.setType("bool");
260                 else if (propertyName == "underline")
261                     propertyInfo.setType("bool");
262                 else if (propertyName == "strikeout")
263                     propertyInfo.setType("bool");
264                 else if (propertyName == "family")
265                     propertyInfo.setType("string");
266                 else if (propertyName == "pixelSize")
267                     propertyInfo.setType("int");
268             } else if (type == ("QPoint")) {
269                 propertyInfo.setType("int");
270             } else if (type == ("QSize")) {
271                 propertyInfo.setType("int");
272             } else if (type == ("QRect")) {
273                 propertyInfo.setType("int");
274             } else if (type == ("QEasingCurve")) {
275                 if (propertyName == "type") {
276                     propertyInfo.setEnumType("true");
277                     propertyInfo.setType("QEasingCurve::Type");
278                     propertyInfo.setEnumerator(m_q->enumerator("QEasingCurve::Type"));
279                 }
280             }
281             propertyInfo.setValid(true);
282             propertyInfo.setReadable(true);
283             propertyInfo.setWritable(true);
284             nodeMetaInfo.addProperty(propertyInfo);
285         }
286         if (debug)
287             qDebug() << "adding value type" << nodeMetaInfo.typeName();
288         m_q->addNodeInfo(nodeMetaInfo);
289     }
290 }
291
292 void MetaInfoPrivate::parseQmlTypes()
293 {
294     foreach (QDeclarativeType *qmlType, QDeclarativeMetaType::qmlTypes()) {
295         const QString qtTypeName(qmlType->typeName());
296         const QString qmlTypeName(qmlType->qmlTypeName());
297         m_QtTypesToQmlTypes.insert(qtTypeName, qmlTypeName);
298     }
299     foreach (QDeclarativeType *qmlType, QDeclarativeMetaType::qmlTypes()) {
300         const QMetaObject *qMetaObject = qmlType->metaObject();
301
302         // parseQmlTypes is called iteratively e.g. when plugins are loaded
303         if (m_q->hasNodeMetaInfo(qmlType->qmlTypeName(), qmlType->majorVersion(), qmlType->minorVersion()))
304             continue;
305
306         NodeMetaInfo nodeMetaInfo(*m_q);
307         nodeMetaInfo.setType(qmlType->qmlTypeName(), qmlType->majorVersion(), qmlType->minorVersion());
308
309         parseProperties(nodeMetaInfo, qMetaObject);
310         parseClassInfo(nodeMetaInfo, qMetaObject);
311
312         QString superTypeName = typeName(qMetaObject->superClass());
313         if (qmlType->baseMetaObject() != qMetaObject) {
314             // type is declared with Q_DECLARE_EXTENDED_TYPE
315             // also parse properties of original type
316             parseProperties(nodeMetaInfo, qmlType->baseMetaObject());
317             superTypeName = typeName(qmlType->baseMetaObject()->superClass());
318         }
319
320         nodeMetaInfo.setSuperClass(superTypeName);
321
322         if (debug)
323             qDebug() << "adding qml type" << nodeMetaInfo.typeName() << nodeMetaInfo.majorVersion() << nodeMetaInfo.minorVersion() << "super class" << superTypeName;
324         m_q->addNodeInfo(nodeMetaInfo);
325     }
326 }
327
328 void MetaInfoPrivate::parseNonQmlTypes()
329 {
330     foreach (QDeclarativeType *qmlType, QDeclarativeMetaType::qmlTypes()) {
331         if (!qmlType->qmlTypeName().contains("Bauhaus"))
332             parseNonQmlClassRecursively(qmlType->metaObject(), qmlType->majorVersion(), qmlType->minorVersion());
333     }
334
335     parseNonQmlClassRecursively(&QDeclarativeAnchors::staticMetaObject, -1, -1);
336 }
337
338
339 void MetaInfoPrivate::parseXmlFiles()
340 {
341     Internal::MetaInfoParser(*m_q).parseFile(":/metainfo/gui.metainfo");
342
343     Internal::WidgetPluginManager pluginManager;
344     foreach (const QString &pluginDir, m_q->s_pluginDirs)
345         pluginManager.addPath(pluginDir);
346     QList<IWidgetPlugin *> widgetPluginList = pluginManager.instances();
347     foreach (IWidgetPlugin *plugin, widgetPluginList) {
348         parseQmlTypes();
349         Internal::MetaInfoParser parser(*m_q);
350         parser.parseFile(plugin->metaInfo());
351     }
352 }
353
354 } // namespace Internal
355
356 using QmlDesigner::Internal::MetaInfoPrivate;
357
358 MetaInfo MetaInfo::s_global;
359 QStringList MetaInfo::s_pluginDirs;
360
361
362 /*!
363 \class QmlDesigner::MetaInfo
364 \ingroup CoreModel
365 \brief The MetaInfo class provides meta information about qml types and properties.
366
367 The MetaInfo, NodeMetaInfo, PropertyMetaInfo and EnumeratorMetaInfo
368 classes provide information about the (static and dynamic) qml types available in
369 a specific model. Just like their Model, ModelNode and AbstractProperty counterparts,
370 objects of these classes are handles - that means, they are implicitly shared, and
371 should be created on the stack.
372
373 The MetaInfo object should always be accessed via the model (see Model::metaInfo()).
374 Otherwise types specific to a model (like sub components) might
375 be missed.
376
377 \see Model::metaInfo(), QmlDesigner::NodeMetaInfo, QmlDesigner::PropertyMetaInfo, QmlDesigner::EnumeratorMetaInfo
378 */
379
380 /*!
381   \brief Constructs a copy of the given meta info.
382   */
383 MetaInfo::MetaInfo(const MetaInfo &metaInfo) :
384         m_p(metaInfo.m_p)
385 {
386 }
387
388 /*!
389   \brief Creates a meta information object with just the qml types registered statically.
390   You almost always want to use Model::metaInfo() instead!
391
392   You almost certainly want to access the meta information for the model.
393
394   \see Model::metaInfo()
395   */
396 MetaInfo::MetaInfo() :
397         m_p(new MetaInfoPrivate(this))
398 {
399 }
400
401 MetaInfo::~MetaInfo()
402 {
403 }
404
405 /*!
406   \brief Assigns other to this meta information and returns a reference to this meta information.
407   */
408 MetaInfo& MetaInfo::operator=(const MetaInfo &other)
409 {
410     m_p = other.m_p;
411     return *this;
412 }
413
414 /*!
415   \brief Returns whether a type with the given name is registered in the meta system.
416   */
417 bool MetaInfo::hasNodeMetaInfo(const QString &typeName, int majorVersion, int minorVersion) const
418 {
419     foreach (const NodeMetaInfo &info, m_p->m_nodeMetaInfoHash.values(typeName)) {
420         if (info.availableInVersion(majorVersion, minorVersion)) {
421             return true;
422         }
423     }
424     if (!isGlobal())
425         return global().hasNodeMetaInfo(typeName);
426     return false;
427 }
428
429 /*!
430   \brief Returns meta information for a qml type. An invalid NodeMetaInfo object if the type is unknown.
431   */
432 NodeMetaInfo MetaInfo::nodeMetaInfo(const QString &typeName, int majorVersion, int minorVersion) const
433 {
434     foreach (const NodeMetaInfo &info, m_p->m_nodeMetaInfoHash.values(typeName)) {
435         // todo: The order for different types for different versions is random here.
436         if (info.availableInVersion(majorVersion, minorVersion)) {
437             return info;
438         }
439     }
440     if (!isGlobal())
441         return global().nodeMetaInfo(typeName);
442
443     return NodeMetaInfo();
444 }
445
446 QString MetaInfo::fromQtTypes(const QString &type) const
447 {
448     if (m_p->m_QtTypesToQmlTypes.contains(type))
449         return m_p->m_QtTypesToQmlTypes.value(type);
450     if (!isGlobal())
451         return global().fromQtTypes(type);
452     return type;
453 }
454
455 /*!
456   \brief Returns whether an enumerator is registered in the meta type system.
457   */
458 bool MetaInfo::hasEnumerator(const QString &enumeratorName) const
459 {
460     return m_p->m_enumeratorMetaInfoHash.contains(enumeratorName)
461             || (!isGlobal() ? global().hasEnumerator(enumeratorName) : false);
462 }
463
464 /*!
465   \brief Returns meta information about an enumerator. An invalid EnumeratorMetaInfo object if the enumerator is not known.
466   */
467 EnumeratorMetaInfo MetaInfo::enumerator(const QString &enumeratorName) const
468 {
469     if (m_p->m_enumeratorMetaInfoHash.contains(enumeratorName))
470         return m_p->m_enumeratorMetaInfoHash.value(enumeratorName);
471     if (!isGlobal())
472         return global().enumerator(enumeratorName);
473     return EnumeratorMetaInfo();
474 }
475
476 ItemLibraryInfo *MetaInfo::itemLibraryInfo() const
477 {
478     return m_p->m_itemLibraryInfo.data();
479 }
480
481 /*!
482   \brief Access to the global meta information object.
483   You almost always want to use Model::metaInfo() instead.
484
485   Internally all meta information objects share this "global" object
486   where static qml type information is stored.
487   */
488 MetaInfo MetaInfo::global()
489 {
490     if (!s_global.m_p->m_isInitialized) {
491         s_global.m_p = QSharedPointer<MetaInfoPrivate>(new MetaInfoPrivate(&s_global));
492         s_global.m_p->initialize();
493     }
494     return s_global;
495 }
496
497 /*!
498   \brief Clears the global meta information object.
499
500   This method should be called once on application shutdown to free static data structures.
501   */
502 void MetaInfo::clearGlobal()
503 {
504     if (s_global.m_p->m_isInitialized) {
505         s_global.m_p->clear();
506     }
507 }
508
509 void MetaInfo::setPluginPaths(const QStringList &paths)
510 {
511     s_pluginDirs = paths;
512 }
513
514 void MetaInfo::addNodeInfo(NodeMetaInfo &nodeInfo)
515 {
516     if (nodeInfo.typeName().isEmpty() || nodeInfo.metaInfo() != *this)
517         throw new InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, QLatin1String("nodeInfo"));
518
519
520     m_p->m_nodeMetaInfoHash.insertMulti(nodeInfo.typeName(), nodeInfo);
521 }
522
523 void MetaInfo::removeNodeInfo(NodeMetaInfo &info)
524 {
525     if (!info.isValid()) {
526         qWarning() << "NodeMetaInfo is invalid";
527         return;
528     }
529
530     if (m_p->m_nodeMetaInfoHash.contains(info.typeName())
531         && m_p->m_nodeMetaInfoHash.remove(info.typeName(), info)) {
532
533         foreach (const ItemLibraryEntry &entry,
534                  m_p->m_itemLibraryInfo->entriesForType(info.typeName(), info.majorVersion(), info.minorVersion())) {
535             m_p->m_itemLibraryInfo->removeEntry(entry.name());
536         }
537
538     } else if (!isGlobal()) {
539         global().removeNodeInfo(info);
540     } else {
541         Q_ASSERT_X(0, Q_FUNC_INFO, "Node meta info not in db");
542     }
543
544     info.setInvalid();
545 }
546
547 EnumeratorMetaInfo MetaInfo::addEnumerator(const QString &enumeratorScope, const QString &enumeratorName)
548 {
549     Q_ASSERT(!enumeratorName.isEmpty());
550
551     EnumeratorMetaInfo enumeratorMetaInfo;
552     enumeratorMetaInfo.setName(enumeratorName);
553     enumeratorMetaInfo.setScope(enumeratorScope);
554     enumeratorMetaInfo.setIsFlagType(false);
555     enumeratorMetaInfo.setValid(true);
556
557     m_p->m_enumeratorMetaInfoHash.insert(enumeratorMetaInfo.scopeAndName(), enumeratorMetaInfo);
558
559     return enumeratorMetaInfo;
560 }
561
562 EnumeratorMetaInfo MetaInfo::addFlag(const QString &enumeratorScope, const QString &enumeratorName)
563 {
564     Q_ASSERT(!enumeratorName.isEmpty());
565
566     EnumeratorMetaInfo enumeratorMetaInfo;
567     enumeratorMetaInfo.setName(enumeratorName);
568     enumeratorMetaInfo.setScope(enumeratorScope);
569     enumeratorMetaInfo.setIsFlagType(true);
570     m_p->m_enumeratorMetaInfoHash.insert(enumeratorMetaInfo.scopeAndName(), enumeratorMetaInfo);
571
572     return enumeratorMetaInfo;
573 }
574
575 bool MetaInfo::isGlobal() const
576 {
577     return (this->m_p == s_global.m_p);
578 }
579
580 bool operator==(const MetaInfo &first, const MetaInfo &second)
581 {
582     return first.m_p == second.m_p;
583 }
584
585 bool operator!=(const MetaInfo &first, const MetaInfo &second)
586 {
587     return !(first == second);
588 }
589
590 } //namespace QmlDesigner