1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
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.
16 ** GNU Lesser General Public License Usage
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.
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
28 **************************************************************************/
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"
40 #include "model/variantparser.h"
41 #include "pluginmanager/widgetpluginmanager.h"
45 #include <QtAlgorithms>
46 #include <QMetaProperty>
47 #include <QDeclarativeEngine>
49 #include <private/qdeclarativemetatype_p.h>
50 #include <private/qdeclarativeanchors_p.h>
56 namespace QmlDesigner {
61 Q_DISABLE_COPY(MetaInfoPrivate)
63 typedef QSharedPointer<MetaInfoPrivate> Pointer;
64 typedef QWeakPointer<MetaInfoPrivate> WeakPointer;
67 MetaInfoPrivate(MetaInfo *q);
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;
78 QString typeName(const QMetaObject *qMetaObject) const;
82 QMultiHash<QString, NodeMetaInfo> m_nodeMetaInfoHash;
83 QHash<QString, EnumeratorMetaInfo> m_enumeratorMetaInfoHash;
84 QHash<QString, QString> m_QtTypesToQmlTypes;
85 QScopedPointer<ItemLibraryInfo> m_itemLibraryInfo;
91 MetaInfoPrivate::MetaInfoPrivate(MetaInfo *q) :
92 m_itemLibraryInfo(new ItemLibraryInfo()),
94 m_isInitialized(false)
97 m_itemLibraryInfo->setBaseInfo(MetaInfo::global().itemLibraryInfo());
100 void MetaInfoPrivate::clear()
102 m_nodeMetaInfoHash.clear();
103 m_enumeratorMetaInfoHash.clear();
104 m_itemLibraryInfo->clearEntries();
105 m_isInitialized = false;
108 void MetaInfoPrivate::initialize()
110 // make sure QmlGraphicsItemsModule gets initialized, that is
111 // QmlGraphicsItemsModule::defineModule called
112 QDeclarativeEngine engine;
120 m_isInitialized = true;
125 void MetaInfoPrivate::parseProperties(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const
127 Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject");
128 Q_ASSERT_X(nodeMetaInfo.isValid(), Q_FUNC_INFO, "invalid NodeMetaInfo");
130 for (int i = qMetaObject->propertyOffset(); i < qMetaObject->propertyCount(); ++i) {
131 QMetaProperty qProperty = qMetaObject->property(i);
133 PropertyMetaInfo propertyInfo;
135 propertyInfo.setName(QLatin1String(qProperty.name()));
137 QString typeName(qProperty.typeName());
138 QString noStar = typeName;
140 while (noStar.contains('*')) {//strip star
144 if (m_QtTypesToQmlTypes.contains(noStar)) {
145 typeName = star ? m_QtTypesToQmlTypes.value(noStar) + '*' : m_QtTypesToQmlTypes.value(noStar);
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());
156 if (propertyInfo.isEnumType()) {
157 QMetaEnum qEnumerator = qProperty.enumerator();
158 EnumeratorMetaInfo enumerator = m_q->addEnumerator(qEnumerator.scope(), qEnumerator.name());
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++)
166 enumerator.addElement(qEnumerator.valueToKey(i), i);
169 propertyInfo.setEnumerator(enumerator);
173 nodeMetaInfo.addProperty(propertyInfo);
177 void MetaInfoPrivate::parseClassInfo(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const
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());
190 void MetaInfoPrivate::parseNonQmlClassRecursively(const QMetaObject *qMetaObject, int majorVersion, int minorVersion)
192 Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject");
193 const QString className = qMetaObject->className();
195 if (className.isEmpty()) {
196 qWarning() << "Meta type system: Registered class has no name.";
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);
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()));
211 m_q->addNodeInfo(nodeMetaInfo);
214 if (const QMetaObject *superClass = qMetaObject->superClass()) {
215 parseNonQmlClassRecursively(superClass, majorVersion, minorVersion);
220 QString MetaInfoPrivate::typeName(const QMetaObject *qMetaObject) const
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,
234 void MetaInfoPrivate::parseValueTypes()
236 QStringList valueTypes;
237 //there is no global list of all supported value types
238 valueTypes << "QFont"
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"));
281 propertyInfo.setValid(true);
282 propertyInfo.setReadable(true);
283 propertyInfo.setWritable(true);
284 nodeMetaInfo.addProperty(propertyInfo);
287 qDebug() << "adding value type" << nodeMetaInfo.typeName();
288 m_q->addNodeInfo(nodeMetaInfo);
292 void MetaInfoPrivate::parseQmlTypes()
294 foreach (QDeclarativeType *qmlType, QDeclarativeMetaType::qmlTypes()) {
295 const QString qtTypeName(qmlType->typeName());
296 const QString qmlTypeName(qmlType->qmlTypeName());
297 m_QtTypesToQmlTypes.insert(qtTypeName, qmlTypeName);
299 foreach (QDeclarativeType *qmlType, QDeclarativeMetaType::qmlTypes()) {
300 const QMetaObject *qMetaObject = qmlType->metaObject();
302 // parseQmlTypes is called iteratively e.g. when plugins are loaded
303 if (m_q->hasNodeMetaInfo(qmlType->qmlTypeName(), qmlType->majorVersion(), qmlType->minorVersion()))
306 NodeMetaInfo nodeMetaInfo(*m_q);
307 nodeMetaInfo.setType(qmlType->qmlTypeName(), qmlType->majorVersion(), qmlType->minorVersion());
309 parseProperties(nodeMetaInfo, qMetaObject);
310 parseClassInfo(nodeMetaInfo, qMetaObject);
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());
320 nodeMetaInfo.setSuperClass(superTypeName);
323 qDebug() << "adding qml type" << nodeMetaInfo.typeName() << nodeMetaInfo.majorVersion() << nodeMetaInfo.minorVersion() << "super class" << superTypeName;
324 m_q->addNodeInfo(nodeMetaInfo);
328 void MetaInfoPrivate::parseNonQmlTypes()
330 foreach (QDeclarativeType *qmlType, QDeclarativeMetaType::qmlTypes()) {
331 if (!qmlType->qmlTypeName().contains("Bauhaus"))
332 parseNonQmlClassRecursively(qmlType->metaObject(), qmlType->majorVersion(), qmlType->minorVersion());
335 parseNonQmlClassRecursively(&QDeclarativeAnchors::staticMetaObject, -1, -1);
339 void MetaInfoPrivate::parseXmlFiles()
341 Internal::MetaInfoParser(*m_q).parseFile(":/metainfo/gui.metainfo");
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) {
349 Internal::MetaInfoParser parser(*m_q);
350 parser.parseFile(plugin->metaInfo());
354 } // namespace Internal
356 using QmlDesigner::Internal::MetaInfoPrivate;
358 MetaInfo MetaInfo::s_global;
359 QStringList MetaInfo::s_pluginDirs;
363 \class QmlDesigner::MetaInfo
365 \brief The MetaInfo class provides meta information about qml types and properties.
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.
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
377 \see Model::metaInfo(), QmlDesigner::NodeMetaInfo, QmlDesigner::PropertyMetaInfo, QmlDesigner::EnumeratorMetaInfo
381 \brief Constructs a copy of the given meta info.
383 MetaInfo::MetaInfo(const MetaInfo &metaInfo) :
389 \brief Creates a meta information object with just the qml types registered statically.
390 You almost always want to use Model::metaInfo() instead!
392 You almost certainly want to access the meta information for the model.
394 \see Model::metaInfo()
396 MetaInfo::MetaInfo() :
397 m_p(new MetaInfoPrivate(this))
401 MetaInfo::~MetaInfo()
406 \brief Assigns other to this meta information and returns a reference to this meta information.
408 MetaInfo& MetaInfo::operator=(const MetaInfo &other)
415 \brief Returns whether a type with the given name is registered in the meta system.
417 bool MetaInfo::hasNodeMetaInfo(const QString &typeName, int majorVersion, int minorVersion) const
419 foreach (const NodeMetaInfo &info, m_p->m_nodeMetaInfoHash.values(typeName)) {
420 if (info.availableInVersion(majorVersion, minorVersion)) {
425 return global().hasNodeMetaInfo(typeName);
430 \brief Returns meta information for a qml type. An invalid NodeMetaInfo object if the type is unknown.
432 NodeMetaInfo MetaInfo::nodeMetaInfo(const QString &typeName, int majorVersion, int minorVersion) const
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)) {
441 return global().nodeMetaInfo(typeName);
443 return NodeMetaInfo();
446 QString MetaInfo::fromQtTypes(const QString &type) const
448 if (m_p->m_QtTypesToQmlTypes.contains(type))
449 return m_p->m_QtTypesToQmlTypes.value(type);
451 return global().fromQtTypes(type);
456 \brief Returns whether an enumerator is registered in the meta type system.
458 bool MetaInfo::hasEnumerator(const QString &enumeratorName) const
460 return m_p->m_enumeratorMetaInfoHash.contains(enumeratorName)
461 || (!isGlobal() ? global().hasEnumerator(enumeratorName) : false);
465 \brief Returns meta information about an enumerator. An invalid EnumeratorMetaInfo object if the enumerator is not known.
467 EnumeratorMetaInfo MetaInfo::enumerator(const QString &enumeratorName) const
469 if (m_p->m_enumeratorMetaInfoHash.contains(enumeratorName))
470 return m_p->m_enumeratorMetaInfoHash.value(enumeratorName);
472 return global().enumerator(enumeratorName);
473 return EnumeratorMetaInfo();
476 ItemLibraryInfo *MetaInfo::itemLibraryInfo() const
478 return m_p->m_itemLibraryInfo.data();
482 \brief Access to the global meta information object.
483 You almost always want to use Model::metaInfo() instead.
485 Internally all meta information objects share this "global" object
486 where static qml type information is stored.
488 MetaInfo MetaInfo::global()
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();
498 \brief Clears the global meta information object.
500 This method should be called once on application shutdown to free static data structures.
502 void MetaInfo::clearGlobal()
504 if (s_global.m_p->m_isInitialized) {
505 s_global.m_p->clear();
509 void MetaInfo::setPluginPaths(const QStringList &paths)
511 s_pluginDirs = paths;
514 void MetaInfo::addNodeInfo(NodeMetaInfo &nodeInfo)
516 if (nodeInfo.typeName().isEmpty() || nodeInfo.metaInfo() != *this)
517 throw new InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, QLatin1String("nodeInfo"));
520 m_p->m_nodeMetaInfoHash.insertMulti(nodeInfo.typeName(), nodeInfo);
523 void MetaInfo::removeNodeInfo(NodeMetaInfo &info)
525 if (!info.isValid()) {
526 qWarning() << "NodeMetaInfo is invalid";
530 if (m_p->m_nodeMetaInfoHash.contains(info.typeName())
531 && m_p->m_nodeMetaInfoHash.remove(info.typeName(), info)) {
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());
538 } else if (!isGlobal()) {
539 global().removeNodeInfo(info);
541 Q_ASSERT_X(0, Q_FUNC_INFO, "Node meta info not in db");
547 EnumeratorMetaInfo MetaInfo::addEnumerator(const QString &enumeratorScope, const QString &enumeratorName)
549 Q_ASSERT(!enumeratorName.isEmpty());
551 EnumeratorMetaInfo enumeratorMetaInfo;
552 enumeratorMetaInfo.setName(enumeratorName);
553 enumeratorMetaInfo.setScope(enumeratorScope);
554 enumeratorMetaInfo.setIsFlagType(false);
555 enumeratorMetaInfo.setValid(true);
557 m_p->m_enumeratorMetaInfoHash.insert(enumeratorMetaInfo.scopeAndName(), enumeratorMetaInfo);
559 return enumeratorMetaInfo;
562 EnumeratorMetaInfo MetaInfo::addFlag(const QString &enumeratorScope, const QString &enumeratorName)
564 Q_ASSERT(!enumeratorName.isEmpty());
566 EnumeratorMetaInfo enumeratorMetaInfo;
567 enumeratorMetaInfo.setName(enumeratorName);
568 enumeratorMetaInfo.setScope(enumeratorScope);
569 enumeratorMetaInfo.setIsFlagType(true);
570 m_p->m_enumeratorMetaInfoHash.insert(enumeratorMetaInfo.scopeAndName(), enumeratorMetaInfo);
572 return enumeratorMetaInfo;
575 bool MetaInfo::isGlobal() const
577 return (this->m_p == s_global.m_p);
580 bool operator==(const MetaInfo &first, const MetaInfo &second)
582 return first.m_p == second.m_p;
585 bool operator!=(const MetaInfo &first, const MetaInfo &second)
587 return !(first == second);
590 } //namespace QmlDesigner