/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the documentation of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** 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, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page qml-extending.html \title Extending QML The QML syntax declaratively describes how to construct an in memory object tree. In Qt, QML is mainly used to describe a visual scene graph, but it is not conceptually limited to this: the QML format is an abstract description of any object tree. All the QML element types included in Qt are implemented using the C++ extension mechanisms describe on this page. Programmers can use these APIs to add new types that interact with the existing Qt types, or to repurpose QML for their own independent use. \tableofcontents \section1 Adding Types \snippet examples/declarative/extending/adding/example.qml 0 The QML snippet shown above instantiates one \c Person instance and sets the name and shoeSize properties on it. Everything in QML ultimately comes down to either instantiating an object instance, or assigning a property a value. QML relies heavily on Qt's meta object system and can only instantiate classes that derive from QObject. The QML engine has no intrinsic knowledge of any class types. Instead the programmer must define the C++ types, and their corresponding QML name. Custom C++ types are made available to QML using these two macros: \quotation \code #define QML_DECLARE_TYPE(T) #define QML_DEFINE_TYPE(T,QmlName) \endcode Register the C++ type \a T with the QML system, and make it available in QML under the name \a QmlName. \a T and \a QmlName may be the same. Generally the QML_DECLARE_TYPE() macro should be included immediately following the type declaration (usually in its header file), and the QML_DEFINE_TYPE() macro in the implementation file. QML_DEFINE_TYPE() must not be present in a header file. Type \a T must be a concrete type that inherits QObject and has a default constructor. \endquotation Once registered, all of the \l {Qt's Property System}{properties} of a supported type are available for use within QML. QML has intrinsic support for properties of these types: \list \o bool \o unsigned int, int \o float, double, qreal \o QString \o QUrl \o QColor \o QDate, QTime, QDateTime \o QPoint, QPointF \o QSize, QSizeF \o QRect, QRectF \o QVariant \endlist QML is typesafe. Attempting to assign an invalid value to a property will generate an error. For example, assuming the name property of the \c Person element had a type of QString, this would cause an error: \code Person { // Will NOT work name: 12 } \endcode \l {Extending QML - Adding Types Example} shows the complete code used to create the \c Person type. \section1 Object and List Property Types \snippet examples/declarative/extending/properties/example.qml 0 The QML snippet shown above assigns a \c Person object to the \c BirthdayParty's celebrant property, and assigns three \c Person objects to the guests property. QML can set properties of types that are more complex than basic intrinsics like integers and strings. Properties can also be object pointers, Qt interface pointers, lists of object points, and lists of Qt interface pointers. As QML is typesafe it ensures that only valid types are assigned to these properties, just like it does for primitive types. Properties that are pointers to objects or Qt interfaces are declared with the Q_PROPERTY() macro, just like other properties. The celebrant property declaration looks like this: \snippet examples/declarative/extending/properties/birthdayparty.h 1 As long as the property type, in this case Person, is registered with QML the property can be assigned. QML also supports assigning Qt interfaces. To assign to a property whose type is a Qt interface pointer, the interface must also be registered with QML. As they cannot be instantiated directly, registering a Qt interface is different from registering a new QML type. The following macros are used instead: \quotation \code #define QML_DECLARE_INTERFACE(T) #define QML_DEFINE_INTERFACE(T) \endcode Register the C++ interface \a T with the QML system. Generally the QML_DECLARE_INTERFACE() macro should be included immediately following the interface declaration (usually in its header file), and the QML_DEFINE_INTERFACE() macro in an implementation file. QML_DEFINE_INTERFACE() must not be present in a header file. Following registration, QML can coerce objects that implement this interface for assignment to appropriately typed properties. \endquotation The guests property is a list of \c Person objects. Properties that are lists of objects or Qt interfaces are also declared with the Q_PROPERTY() macro, just like other properties. List properties must have the type \c {QmlList*}. As with object properties, the type \a T must be registered with QML. The guest property declaration looks like this: \snippet examples/declarative/extending/properties/birthdayparty.h 2 \l {Extending QML - Object and List Property Types Example} shows the complete code used to create the \c BirthdayParty type. \section1 Inheritance and Coercion \snippet examples/declarative/extending/coercion/example.qml 0 The QML snippet shown above assigns a \c Boy object to the \c BirthdayParty's celebrant property, and assigns three other objects to the guests property. QML supports C++ inheritance heirarchies and can freely coerce between known, valid object types. This enables the creation of common base classes that allow the assignment of specialized classes to object or list properties. In the snippet shown, both the celebrant and the guests properties retain the Person type used in the previous section, but the assignment is valid as both the Boy and Girl objects inherit from Person. To assign to a property, the property's type must have been registered with QML. Both the QML_DEFINE_TYPE() and QML_DEFINE_INTERFACE() macros already shown can be used to register a type with QML. Additionally, if a type that acts purely as a base class that cannot be instantiated from QML needs to be registered these macros can be used: \quotation \code #define QML_DECLARE_TYPE(T) #define QML_DEFINE_NOCREATE_TYPE(T) \endcode Register the C++ type \a T with the QML system. QML_DEFINE_NOCREATE_TYPE() differs from QML_DEFINE_TYPE() in that it does not define a mapping between the C++ class and a QML element name, so the type is not instantiable from QML, but it is available for type coercion. Generally the QML_DECLARE_TYPE() macro should be included immediately following the type declaration (usually in its header file), and the QML_DEFINE_NOCREATE_TYPE() macro in the implementation file. QML_DEFINE_NOCREATE_TYPE() must not be present in a header file. Type \a T must inherit QObject, but there are no restrictions on whether it is concrete or the signature of its constructor. \endquotation QML will automatically coerce C++ types when assigning to either an object property, or to a list property. Only if coercion fails does an assignment error occur. \l {Extending QML - Inheritance and Coercion Example} shows the complete code used to create the \c Boy and \c Girl types. \section1 Default Property \snippet examples/declarative/extending/default/example.qml 0 The QML snippet shown above assigns a collection of objects to the \c BirthdayParty's default property. The default property is a syntactic convenience that allows a type designer to specify a single property as the type's default. The default property is assigned to whenever no explicit property is specified. As a convenience, it is behaviorally identical to assigning the default property explicitly by name. From C++, type designers mark the default property using a Q_CLASSINFO() annotation: \quotation \code Q_CLASSINFO("DefaultProperty", "property") \endcode Mark \a property as the class's default property. \a property must be either an object property, or a list property. A default property is optional. A derived class inherits its base class's default property, but may override it in its own declaration. \a property can refer to a property declared in the class itself, or a property inherited from a base class. \endquotation \l {Extending QML - Default Property Example} shows the complete code used to specify a default property. \section1 Grouped Properties \snippet examples/declarative/extending/grouped/example.qml 1 The QML snippet shown above assigns a number properties to the \c Boy object, including four properties using the grouped property syntax. Grouped properties collect similar properties together into a single named block. Grouped properties can be used to present a nicer API to developers, and may also simplify the implementation of common property collections across different types through implementation reuse. A grouped property block is implemented as a read-only object property. The shoe property shown is declared like this: \snippet examples/declarative/extending/grouped/person.h 1 The ShoeDescription type declares the properties available to the grouped property block - in this case the size, color, brand and price properties. Grouped property blocks may declared and accessed be recusively. \l {Extending QML - Grouped Properties Example} shows the complete code used to implement the \c shoe property grouping. \section1 Attached Properties \snippet examples/declarative/extending/attached/example.qml 1 The QML snippet shown above assigns the rsvp property using the attached property syntax. Attached properties allow unrelated types to annotate other types with some additional properties, generally for their own use. Attached properties are identified through the use of the attacher type name, in the case shown \c BirthdayParty, as a suffix to the property name. In the example shown, \c BirthdayParty is called the attaching type, and the Box instance the attachee object instance. For the attaching type, an attached property block is implemented as a new QObject derived type, called the attachment object. The properties on the attachment object are those that become available for use as the attached property block. Any QML type can become an attaching type by declaring the \c qmlAttachedProperties() public function: \quotation \code static AttachedPropertiesType *qmlAttachedProperties(QObject *object) \endcode Return an attachment object, of type \a AttachedPropertiesType, for the attachee \a object instance. It is customary, though not strictly required, for the attachment object to be parented to \a object to prevent memory leaks. \a AttachedPropertiesType must be a QObject derived type. The properties on this type will be accessible through the attached properties syntax. This method will be called at most once for each attachee object instance. The QML engine will cache the returned instance pointer for subsequent attached property accesses. Consequently the attachment object may not be deleted until \a object is destroyed. \endquotation Conceptually, attached properties are a \e type exporting a set of additional properties that can be set on \e any other object instance. Attached properties cannot be limited to only attaching to a sub-set of object instances, although their effect may be so limited. For example, a common usage scenario is for a type to enhance the properties available to its children in order to gather instance specific data. Here we add a rsvp field to all the guests coming to a birthday party: \code BirthdayParty { Boy { BirthdayParty.rsvp: "2009-06-01" } } \endcode However, as a type cannot limit the instances to which the attachment object must attach, the following is also allowed, even though adding a birthday party rsvp in this context will have no effect. \code GraduationParty { Boy { BirthdayParty.rsvp: "2009-06-01" } } \endcode From C++, including the attaching type implementation, the attachment object for an instance can be accessed using the following method: \quotation \code template QObject *qmlAttachedPropertiesObject(QObject *attachee, bool create = true); \endcode Returns the attachment object attached to \a attachee by the attaching type \a T. If type \a T is not a valid attaching type, this method always returns 0. If \a create is true, a valid attachment object will always be returned, creating it if it does not already exist. If \a create is false, the attachment object will only be returned if it has previously been created. \endquotation \l {Extending QML - Attached Properties Example} shows the complete code used to implement the rsvp attached property. \section1 Signal support \section1 Property Binding \section1 Property Value Sources \section1 Extension Objects \section1 Parser Status */ /*! \page qml-extending-types.html \title Extending types from QML Many of the elements available for use in QML are implemented in \l {QML for C++ Programmers}{C++}. These types are know as "core types". QML allows programmers to build new, fully functional elements without using C++. Existing core types can be extended, and new types defined entirely in the QML language. \tableofcontents \section1 Adding new properties New properties can be added to an existing type. These new properties are available for use within QML, and also appear as regular Qt properties on the C++ object, accessible through the regular property access mechanisms. Like all properties in QML, custom properties are typed. The type is used to define the property's behavior, and also determines the C++ type of the created Qt property. The following table shows the list of types available when declaring a new property, and the corresponding C++ type. \table \header \o QML Type Name \o C++ Type Name \row \o int \o int \row \o bool \o bool \row \o double \o double \row \o real \o double \row \o string \o QString \row \o url \o QUrl \row \o color \o QColor \row \o date \o QDate \row \o var \o QVariant \row \o variant \o QVariant \endtable QML supports two methods for adding a new property to a type - a new property definition, and a property alias. \section2 Property definitions Property definitions add a new property to an existing type. The storage of the property is managed by QML. The defined property may be read, written and bound to and from. The syntax for defining a new property is: \code [default] property [: defaultValue] \endcode This declaration may appear anywhere within a type body, but it is customary to include it at the top. Attempting to declare two properties with the same name in the same type block is an error. However, a new property may reuse the name of an existing property on the type. This should be done with caution, as the existing property will be hidden, and become inaccessible. The must be one of the QML type names shown in the above table. Additionally, an optional default value of the property can be provided. The default value is a convenient shortcut, but is behaviorally identical to doing it in two steps, like this: \code // Use default value property int myProperty: 10 // Longer, but behaviorally identical property int myProperty myProperty: 10 \endcode If specified, the optional "default" attribute marks the new property as the types default property, overriding any existing default property. Using the default attribute twice in the same type block is an error. The following example shows how to declare a new "innerColor" property that controls the color of the inner rectangle. \code Rect { property color innerColor: "black" color: "red"; width: 100; height: 100 Rect { anchors.centeredIn: parent width: parent.width - 10 height: parent.height - 10 color: innerColor } } \endcode \section2 Property aliases Property aliases are a more advanced form of property declaration. Unlike a property definition, that allocates a new, unique storage space for the property, a property alias connects the newly declared property (called the aliasing property) to an existing property (the aliased property). Read operations on the aliasing property act as read operations on the aliased property, and write operations on the aliasing property as write operations on the aliased property. A property alias declaration looks a lot like a property definition: \code [default] property alias : \endcode As the aliasing property has the same type as the aliased property, an explicit type is omitted, and the special "alias" keyword is used. Instead of a default value, a property alias includes a compulsary alias reference. The alias reference is used to locate the aliased property. While similar to a property binding, the alias reference syntax is highly restricted. An alias reference takes the form \code . \endcode where must refer to an object id within the same component as the type declaring the alias, and refers to a property on this object. The alias reference syntax may become more flexibly in future releases. Here is the property definition example rewritten to use property aliases. \code Rect { property alias innerColor: InnerRect.color color: "red"; width: 100; height: 100 Rect { id: InnerRect anchors.centeredIn: parent width: parent.width - 10 height: parent.height - 10 color: "black" } } \endcode Aliases are most useful when \l {Defining new Components}. Consequently they have several apparent limitations that only make sense in this context. Aliases are only activated once the component specifying them is completed. The most obvious consequence of this is that the component itself cannot generally use the aliased property directly. For example, this will not work: \code // Does NOT work property alias innerColor: InnerRect.color innerColor: "black" \endcode This behavior is required to allow type developers to redefine the behavior of existing property names while continuing to use the existing behavior within the type they are building, something that is not possible with property definitions. In the example used so far, this could allows the developer to fix the external rectangle's color as "red" and redefine the "color" property to refer to the inner rectangle, like this: \code Rect { property alias color: InnerRect.color color: "red"; width: 100; height: 100 Rect { id: InnerRect anchors.centeredIn: parent width: parent.width - 10 height: parent.height - 10 color: "black" } } \endcode Users of this type would not be able to affect the color of the red rectangle, but would find using the "color" property, rather than the strange new "innerColor" property, much more familiar. A second, much less significant, consequence of the delayed activation of aliases is that an alias reference cannot refer to another aliasing property declared within the same component. This will not work: \code // Does NOT work id: Root property alias innerColor: InnerRect.color property alias innerColor2: Root.innerColor \endcode From outside the component, aliasing properties appear as regular Qt properties and consequently can be used in alias references. \section1 Adding new signals New signals can be added to an existing type. These new signals are available for use within QML, and also appear as regular Qt signals on the C++ object that can be used in Qt signal/slot connections. The syntax for defining a new signal is: \code signal [([ [, ...]])] \endcode This declaration may appear anywhere within a type body, but it is customary to include it at the top. Attempting to declare two signals or methods with the same name in the same type block is an error. However, a new signal may reuse the name of an existing signal on the type. This should be done with caution, as the existing signal may be hidden and become inaccessible. The options for parameter types are the same as for property types (see \l {Adding new properties}. If this signal has no parameters, the parameter list may be omitted entirely. Here are three examples of signal declarations: \code Item { signal clicked signal hovered() signal performAction(string action, var actionArgument) } \endcode \section1 Adding new methods New methods can be added to an existing type. These new methods are available for use within QML, and also appear as regular Qt slots on the C++ object that can be used in Qt signal/slot connections. \code function ([[, ...]]) { } \endcode This declaration may appear anywhere within a type body, but it is customary to include it at the top. Attempting to declare two methods or signals with the same name in the same type block is an error. However, a new method may reuse the name of an existing method on the type. This should be done with caution, as the existing method may be hidden and become inaccessible. Methods parameters are not typed. In C++ these parameters are of type QVariant. The body of the method is written in JavaScript and may access the parameters by name. This example adds a new method that behaves like a child: \code Item { function say(text) { print("You said " + text); } } \endcode \section1 Defining new Components A component is a reusable type with a well-defined interface built entirely in QML. Components appear as regular QML elements, and can be used interchangably with core types. Components allow developers to create new types to be reused in other projects without the use of C++. Components can also help to reduce duplication inside one project by limiting the need for large numbers of copy-and-pasted blocks. Any snippet of QML code can become a component, just by placing it in the file ".qml" where is the new element name, and begins with an uppercase letter. These QML files automatically become available as new QML element types to other QML components and applications in the same directory. For example, here we show how a component named "Box" is defined and used multiple times by an application. \table \row \o application.qml \code Rect { width: 100; height: 400; Box { x: 0; y: 0 } Box { x: 0; y: 150 } Box { x: 0; y: 300 } } \endcode \o Box.qml \code Rect { width: 100; height: 100; color: "blue" } \endcode \endtable Components may be collected into \l {Modules of Components} that gives the developer more freedom than just putting files in the same directory. \section2 Building reusable components A component type built to be reused by others must have a well defined interface. In QML, an interface consists of a defined collection of properties, signals and methods. Users of a component have access to all the properties, signals and methods defined on the root element of the component. In the component example above, the root element of the "Box" component is a Rect. As the Rect type has a "color" property, this property is accessible to users of the Box component. For example, the application.qml can be modified to show three different colored boxes like this: \code Rect { width: 100; height: 400; Box { x: 0; y: 0; color: "red"; } Box { x: 0; y: 150; color: "yellow"; } Box { x: 0; y: 300; color: "green"; } } \endcode As expected, adding additional properties to the root element of Box, makes them available externally. Here we add a "text" property: \table \row \o application.qml \code Rect { width: 100; height: 400; Box { x: 0; y: 0; color: "red"; text: "stop" } Box { x: 0; y: 150; color: "yellow"; text: "slow" } Box { x: 0; y: 300; color: "green"; text: "go" } } \endcode \o Box.qml \code Rect { property alias text: MyText.text width: 100; height: 100; color: "blue" Text { id: MyText anchors.centeredIn: parent } } \endcode \endtable Methods and signals may be added in the same way. As all external methods, signals and properties are accessible to external users, developers should ensure that setting these properties does not have any undesirable side-effects. For most resiliance, root level properties should only be used for literal default values. When a root level property must be used inside the component - such as the children property - property aliases can be used to redirect this property to a "safe" location for external users. Try to think of the root level properties as being "owned" by the components user, rather than the component itself. */