From 113d2b5d82736c503657f15a3ee56d4daf1829ed Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 2 Jul 2009 14:00:06 +1000 Subject: Improve JS dynamic creation Renamed evalQml to be consistent with us, not javascript. Fixed bug where createComponent never had the right path. createQmlObject (evalQml) now has a parent as a argument. It also still has a bug where that parent doesnt get set properly, although it is used as the creation context also. --- examples/declarative/dynamic/dynamic.js | 13 ++++--- examples/declarative/dynamic/dynamic.qml | 4 +-- src/declarative/qml/qmlengine.cpp | 59 ++++++++++++++++++++++---------- src/declarative/qml/qmlengine.h | 2 +- 4 files changed, 51 insertions(+), 27 deletions(-) diff --git a/examples/declarative/dynamic/dynamic.js b/examples/declarative/dynamic/dynamic.js index 6b483fd..5accc46 100644 --- a/examples/declarative/dynamic/dynamic.js +++ b/examples/declarative/dynamic/dynamic.js @@ -1,10 +1,10 @@ var dynamicObject = null; var fourthBox = null; -var component; +var component = null; var started = false; -function createWithEvalQml(p) { - return evalQml('Rect { color: "lightsteelblue"; width: 100;' - + 'height: 100; id: newRect}','DynPart.qml'); +function createQml(p) { + return createQmlObject('Rect { color: "steelblue"; width: 100;' + + 'height: 100; id: newRect }',p,'DynPart.qml'); } function destroyDynamicObject() { @@ -29,7 +29,7 @@ function instantCreateWithComponent() {//Like create, but assumes instant readyn } function finishCreation(){ - if(component.isReady()){ + if(component.isReady() && dynamicObject == null){ dynamicObject = component.createObject(); dynamicObject.parent = targetItem; }else if(component.isError()){ @@ -40,6 +40,9 @@ function finishCreation(){ } function createWithComponent(){ + if(component!=null){ + return finishCreation(); + } if(started!=false){ finishCreation();//Remakes if destroyed return dynamicObject; diff --git a/examples/declarative/dynamic/dynamic.qml b/examples/declarative/dynamic/dynamic.qml index 3e0c12e..b9f3b35 100644 --- a/examples/declarative/dynamic/dynamic.qml +++ b/examples/declarative/dynamic/dynamic.qml @@ -13,9 +13,9 @@ Rect { id: page; width: 800; height: 800; color:"black" MouseRegion { anchors.fill:parent; onClicked: { if(fourthBox == null) { - a = createWithEvalQml(); + a = createQml(targetItem2); if(a!=null) { - a.parent = targetItem2; + a.parent = targetItem2;//BUG: this should happen automatically fourthBox = a; extendStars = true; } diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index d645fb3..2a15c27 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -194,8 +194,8 @@ void QmlEnginePrivate::init() //###needed for the other funcs, but should it be exposed? scriptEngine.globalObject().setProperty(QLatin1String("qmlEngine"), scriptEngine.newQObject(q)); - scriptEngine.globalObject().setProperty(QLatin1String("evalQml"), - scriptEngine.newFunction(QmlEngine::createQMLObject, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), + scriptEngine.newFunction(QmlEngine::createQmlObject, 1)); scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), scriptEngine.newFunction(QmlEngine::createComponent, 1)); } @@ -844,8 +844,8 @@ QScriptValue QmlEngine::qmlScriptObject(QObject* object, QmlEngine* engine) \endcode If you want to just create an arbitrary string of QML, instead of - loading a qml file, consider the evalQML() function. - \sa QmlComponent::createObject(), QmlEngine::createQMLObject() + loading a qml file, consider the createQmlObject() function. + \sa QmlComponent::createObject(), QmlEngine::createQmlObject() */ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *engine) { @@ -855,21 +855,31 @@ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *eng if(ctxt->argumentCount() != 1 || !activeEngine){ c = new QmlComponent(activeEngine); }else{ - //### This url needs to be resolved in the context that the function - //### is called - it can't be done here. - QUrl url = QUrl(ctxt->argument(0).toString()); + QUrl url = QUrl(activeEngine->d_func()->currentExpression->context() + ->resolvedUrl(ctxt->argument(0).toString())); + if(!url.isValid()){ + qDebug() << "Error A:" << url << activeEngine->activeContext() << QmlEngine::activeEngine() << activeEngine; + url = QUrl(ctxt->argument(0).toString()); + } c = new QmlComponent(activeEngine, url, activeEngine); } return engine->newQObject(c); } /*! - Creates a new object from the specified string of qml. If a second argument - is provided, this is treated as the filepath that the qml came from. + Creates a new object from the specified string of QML. It requires a + second argument, which is the id of an existing QML object to use as + the new object's parent. If a third argument is provided, this is used + as the filepath that the qml came from. + + Example (where targetItem is the id of an existing QML item): + \code + newObject = createQmlObject('Rect {color: "red"; width: 20; height: 20}', + targetItem, "dynamicSnippet1"); + \endcode This function is intended for use inside QML only. It is intended to behave - similarly to eval, but for creating QML elements. Thus, it is called as - evalQml() in QtScript. + similarly to eval, but for creating QML elements. Returns the created object, or null if there is an error. In the case of an error, details of the error are output using qWarning(). @@ -878,27 +888,32 @@ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *eng the QML loads new components. If you are trying to load a new component, for example from a QML file, consider the createComponent() function instead. 'New components' refers to external QML files that have not yet - been loaded, and so it is safe to use evalQml to load built-in components. + been loaded, and so it is safe to use createQmlObject to load built-in + components. \sa QmlEngine::createComponent() */ -QScriptValue QmlEngine::createQMLObject(QScriptContext *ctxt, QScriptEngine *engine) +QScriptValue QmlEngine::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine) { QmlEngine* activeEngine = qobject_cast( engine->globalObject().property(QLatin1String("qmlEngine")).toQObject()); - if(ctxt->argumentCount() < 1 || !activeEngine){ - if(ctxt->argumentCount() < 1){ - qWarning() << "createQMLObject requires a string argument."; + if(ctxt->argumentCount() < 2 || !activeEngine){ + if(ctxt->argumentCount() < 2){ + qWarning() << "createQmlObject requires two arguments, A QML string followed by an existing QML item id."; }else{ - qWarning() << "createQMLObject cannot find engine."; + qWarning() << "createQmlObject cannot find engine."; } return engine->nullValue(); } QString qml = ctxt->argument(0).toString(); QUrl url; - if(ctxt->argumentCount() > 1) - url = QUrl(ctxt->argument(1).toString()); + if(ctxt->argumentCount() > 2) + url = QUrl(ctxt->argument(2).toString()); + QObject *parentArg = ctxt->argument(1).data().toQObject(); + QmlContext *qmlCtxt = qmlContext(parentArg); + if(qmlCtxt) + qmlCtxt->activate(); QmlComponent component(activeEngine, qml.toUtf8(), url); if(component.isError()) { QList errors = component.errors(); @@ -906,10 +921,14 @@ QScriptValue QmlEngine::createQMLObject(QScriptContext *ctxt, QScriptEngine *eng qWarning() << error; } + if(qmlCtxt) + qmlCtxt->deactivate(); return engine->nullValue(); } QObject *obj = component.create(); + if(qmlCtxt) + qmlCtxt->deactivate(); if(component.isError()) { QList errors = component.errors(); foreach (const QmlError &error, errors) { @@ -920,6 +939,8 @@ QScriptValue QmlEngine::createQMLObject(QScriptContext *ctxt, QScriptEngine *eng } if(obj){ + obj->setParent(parentArg); + obj->setProperty("parent", QVariant::fromValue(parentArg)); return qmlScriptObject(obj, activeEngine); } return engine->nullValue(); diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h index f114379..f600520 100644 --- a/src/declarative/qml/qmlengine.h +++ b/src/declarative/qml/qmlengine.h @@ -91,7 +91,7 @@ public: static QScriptValue qmlScriptObject(QObject*, QmlEngine*); static QScriptValue createComponent(QScriptContext*, QScriptEngine*); - static QScriptValue createQMLObject(QScriptContext*, QScriptEngine*); + static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*); private: // LK: move to the private class -- cgit v0.12 From 602f05025c09093650a7030da6084665cf716e08 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 3 Jul 2009 15:34:22 +1000 Subject: Doc --- doc/src/declarative/components.qdoc | 92 --------- doc/src/declarative/extending.qdoc | 348 +++++++++++++++++++++++++++++++++ doc/src/declarative/qmlforcpp.qdoc | 55 ------ doc/src/declarative/qtdeclarative.qdoc | 4 +- 4 files changed, 350 insertions(+), 149 deletions(-) delete mode 100644 doc/src/declarative/components.qdoc create mode 100644 doc/src/declarative/extending.qdoc diff --git a/doc/src/declarative/components.qdoc b/doc/src/declarative/components.qdoc deleted file mode 100644 index d7a4ba6..0000000 --- a/doc/src/declarative/components.qdoc +++ /dev/null @@ -1,92 +0,0 @@ -/*! -\page components.html -\target components -\title Components - -A \bold component is a reusable, encapsulated Qml element with a well-defined interface. - -Writing and using components allows you to: -\list -\o Reuse sections of Qml without copy-and-paste. -\o Have consistent Look and Feel between different parts of your UI. -\o Create new Qml elements without writing a new C++ class. (See \l {cppitem}{Creating Qml elements in C++}) -\endlist - -Components are placed in \e .qml files, allowing \e to then be used as a tag -elsewhere. For example, if you have a Slider.qml file, you can then use \c {Slider { ... }} to -make a slider, just as if it was a built-in type. - -Components may be collected into \l {qmlmodules}{modules}. - -\section1 Example: Creating a MyButton Component - -This example describes how to create a component from an existing snippet of Qml. - -Assume you have an existing UI with a single 'Save' button, defined as follows: - -\code -Image { - source: "pics/button-background.png" - Text { - text: "Save" - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - } - MouseRegion { - anchors.fill: parent - onClick: { saveData() } - } -} -\endcode - -For the next release, you plan to add 'Cancel' and 'Reset' buttons. Rather than copying and pasting the above markup, you can create a component: - -\list 1 -\o Create a file called MyButton.qml, and copy the relevant Qml snippet into that file. -\o Make some minor changes to define the component's interface: - -\code -Image { - property string label - signal clicked - source: "pics/button-background.png" - Text { - text: parent.label - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - } - MouseRegion { - anchors.fill: parent - onClick: { parent.click.emit() } - } -} -\endcode - -The \a label property and \a click signal that were added effectively become part of the 'public API' of the MyButton component. In a similar manner, the Text and MouseRegion elements become invisible to anyone using the component. Note that the Text element now binds in its data from \a label, and the MouseRegion emits a generic signal. - -\o The component can now be used elsewhere as MyButton: - -\code -MyButton { label: "Save"; onClicked: saveData() } -... -MyButton { label: "Cancel"; onClicked: cancelData() } -... -MyButton { label: "Reset"; onClicked: resetData() } -\endcode - -\endlist - -\section1 Placing .qml Files - -When one component refers to a another, the second must be found either in the same directory -as the first, or in a directory imported using the \c import statement: - -\code -import "library" -\endcode - -\section1 Namespaces - -Namespaces for QML will be supported in Qt 4.6. - -*/ diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc new file mode 100644 index 0000000..7163a93 --- /dev/null +++ b/doc/src/declarative/extending.qdoc @@ -0,0 +1,348 @@ +/*! +\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. +*/ diff --git a/doc/src/declarative/qmlforcpp.qdoc b/doc/src/declarative/qmlforcpp.qdoc index c95cb71..38f5665 100644 --- a/doc/src/declarative/qmlforcpp.qdoc +++ b/doc/src/declarative/qmlforcpp.qdoc @@ -567,61 +567,6 @@ engine will automatically set the property as the target of the value source. - \section1 Extending types in QML - - QML is designed to allow you to build fully working types without writing - a line of C++ code. This is, for example, used extensively when designing - applications using the Fluid UI primitives. To create new types, it is - necessary to be able to define new signals, slots and properties in QML. - - In this example, a Button is extended to have an additional - "text2" property (which always returns "Hello world!") and an additional - signal "clicked2" that is also emitted when the button is clicked. Not - a very useful extension, but an extension nonetheless. - - \table - \row - \o - \code - QmlEngine engine; - QmlComponent component(&engine, qmlData); - QObject *object = component.create(); - // Will print "Hello world!" - qDebug() << object->property("text2"); - // Will be emitted whenever the button is clicked - QObject::connect(object, SIGNAL(clicked2()), this, SLOT(...)); - \endcode - \o - \code - Button { - property string text2 - signal clicked2 - - text: "Hello!" - text2: "Hello world!" - onClicked: clicked2.emit() - } - \endcode - \endtable - - The general syntax for defining new properties and signals is: - - \list - \o - \code - [default] property [: ] - \endcode - - Where type can be one of \e int, \e bool, \e double, \e real, \e string, - \e color, \e date, \e var or \e variant. - - \o - \code - signal - \endcode - Currently only parameterless signals are supported. - \endlist - \section1 Parser Status Generally using QML is a breeze - you implement your classes in C++, add diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index 4fe9994..c945b24 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -68,15 +68,15 @@ \o \l {qmlforcpp}{QML For C++ Programmers} \endlist - Core Features: + Core QML Features: \list \o \l {binding}{Data Binding} \o \l {anchor-layout}{Layout Anchors} \o \l {qmlanimation}{Animation} \o \l {qmleffects}{Visual Effects} - \o \l {components}{Components} \o \l {qmlmodules}{Modules} \o \l {qmlfocus}{Keyboard Focus} + \o \l {Extending types from QML} \endlist QML Reference: -- cgit v0.12 From dca8a799f307d1dea635ad9c011517e9d0d1594a Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Mon, 6 Jul 2009 10:56:59 +1000 Subject: Doc fixes --- doc/src/properties.qdoc | 4 ++-- src/declarative/fx/qfxvisualitemmodel.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/src/properties.qdoc b/doc/src/properties.qdoc index cac5016..1aa41a9 100644 --- a/doc/src/properties.qdoc +++ b/doc/src/properties.qdoc @@ -123,10 +123,10 @@ gets and sets a widget's \c USER property. \o The presence of the \c CONSTANT attibute indicates that the property - value is constant. For a given object instance, the READ method of a + value is constant. For a given object instance, the \c READ method of a constant property must return the same value every time it is called. This constant value may be different for different instances of the object. A - constant property cannot have a WRTE method or a NOTIFY signal. + constant property cannot have a \c WRITE method or a \c NOTIFY signal. \endlist diff --git a/src/declarative/fx/qfxvisualitemmodel.h b/src/declarative/fx/qfxvisualitemmodel.h index 9cacde4..551c08d 100644 --- a/src/declarative/fx/qfxvisualitemmodel.h +++ b/src/declarative/fx/qfxvisualitemmodel.h @@ -70,7 +70,7 @@ class Q_DECLARATIVE_EXPORT QFxVisualItemModel : public QObject Q_PROPERTY(QVariant model READ model WRITE setModel) Q_PROPERTY(QmlComponent *delegate READ delegate WRITE setDelegate) Q_PROPERTY(QString part READ part WRITE setPart) - Q_PROPERTY(QObject *parts READ parts) + Q_PROPERTY(QObject *parts READ parts CONSTANT) Q_CLASSINFO("DefaultProperty", "delegate") public: QFxVisualItemModel(); -- cgit v0.12 From 395169a94dba47baec683c95874de9556ba4952d Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Mon, 6 Jul 2009 16:03:27 +1000 Subject: Fix bug in createQmlObject Wasn't actually loading the object's context properly, with regard to url resolution. --- examples/declarative/dynamic/DynRect.qml | 1 + examples/declarative/dynamic/dynamic.js | 3 +-- src/declarative/qml/qmlengine.cpp | 13 ++++--------- 3 files changed, 6 insertions(+), 11 deletions(-) create mode 100644 examples/declarative/dynamic/DynRect.qml diff --git a/examples/declarative/dynamic/DynRect.qml b/examples/declarative/dynamic/DynRect.qml new file mode 100644 index 0000000..d9a2ef3 --- /dev/null +++ b/examples/declarative/dynamic/DynRect.qml @@ -0,0 +1 @@ +Rect { color: "steelblue"; width: 100; height: 100; id: newRect } diff --git a/examples/declarative/dynamic/dynamic.js b/examples/declarative/dynamic/dynamic.js index 5accc46..13317df 100644 --- a/examples/declarative/dynamic/dynamic.js +++ b/examples/declarative/dynamic/dynamic.js @@ -3,8 +3,7 @@ var fourthBox = null; var component = null; var started = false; function createQml(p) { - return createQmlObject('Rect { color: "steelblue"; width: 100;' - + 'height: 100; id: newRect }',p,'DynPart.qml'); + return createQmlObject('DynRect {}',p,'DynPart.qml'); } function destroyDynamicObject() { diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 5c9273a..389e512 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -912,27 +912,22 @@ QScriptValue QmlEngine::createQmlObject(QScriptContext *ctxt, QScriptEngine *eng url = QUrl(ctxt->argument(2).toString()); QObject *parentArg = ctxt->argument(1).data().toQObject(); QmlContext *qmlCtxt = qmlContext(parentArg); - if(qmlCtxt) - qmlCtxt->activate(); + url = qmlCtxt->resolvedUrl(url); QmlComponent component(activeEngine, qml.toUtf8(), url); if(component.isError()) { QList errors = component.errors(); foreach (const QmlError &error, errors) { - qWarning() << error; + qWarning() <<"Error in createQmlObject(): "<< error; } - if(qmlCtxt) - qmlCtxt->deactivate(); return engine->nullValue(); } - QObject *obj = component.create(); - if(qmlCtxt) - qmlCtxt->deactivate(); + QObject *obj = component.create(qmlCtxt); if(component.isError()) { QList errors = component.errors(); foreach (const QmlError &error, errors) { - qWarning() << error; + qWarning() <<"Error in createQmlObject(): "<< error; } return engine->nullValue(); -- cgit v0.12 From cc5a322cbfa9ae84a6114ef7c171d7e119e6a86c Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 6 Jul 2009 16:22:56 +1000 Subject: Make TextEdit's cursor position usable from Qml. --- src/declarative/fx/qfxtextedit.cpp | 21 ++++++++++++++++++++- src/declarative/fx/qfxtextedit.h | 4 ++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 7f08fba..3778e9a 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -410,7 +410,7 @@ void QFxTextEdit::setWrap(bool w) } /*! - \property QFxTextEdit::cursorVisible + \qmlproperty TextEdit::cursorVisible \brief If true the text edit shows a cursor. This property is set and unset when the text edit gets focus, but it can also @@ -435,6 +435,25 @@ void QFxTextEdit::setCursorVisible(bool on) } /*! + \qmlproperty TextEdit::cursorPosition + \brief The position of the cursor in the TextEdit. +*/ +int QFxTextEdit::cursorPosition() const +{ + Q_D(const QFxTextEdit); + return d->control->textCursor().position(); +} + +void QFxTextEdit::setCursorPosition(int pos) +{ + Q_D(QFxTextEdit); + QTextCursor cursor = d->control->textCursor(); + if (cursor.position() == pos) + return; + cursor.setPosition(pos); +} + +/*! \qmlproperty bool TextEdit::focusOnPress Whether the TextEdit should gain focus on a mouse press. By default this is diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h index 24ba3fe..6988822 100644 --- a/src/declarative/fx/qfxtextedit.h +++ b/src/declarative/fx/qfxtextedit.h @@ -77,6 +77,7 @@ class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxPaintedItem Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat) Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible) + Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition) Q_PROPERTY(bool focusOnPress READ focusOnPress WRITE setFocusOnPress) Q_PROPERTY(bool preserveSelection READ preserveSelection WRITE setPreserveSelection) Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin) @@ -129,6 +130,9 @@ public: bool isCursorVisible() const; void setCursorVisible(bool on); + int cursorPosition() const; + void setCursorPosition(int pos); + bool focusOnPress() const; void setFocusOnPress(bool on); -- cgit v0.12 From d641b621077d5cc81ce7b3de92af9a0f6d47f4d6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 6 Jul 2009 18:32:25 +1000 Subject: Doc --- doc/src/declarative/extending-examples.qdoc | 258 ++++++++++++++ doc/src/declarative/extending.qdoc | 373 +++++++++++++++++++++ doc/src/declarative/qmlformat.qdoc | 6 + doc/src/declarative/qtdeclarative.qdoc | 2 + examples/declarative/extending/adding/adding.pro | 11 + examples/declarative/extending/adding/adding.qrc | 5 + examples/declarative/extending/adding/example.qml | 6 + examples/declarative/extending/adding/main.cpp | 22 ++ examples/declarative/extending/adding/person.cpp | 30 ++ examples/declarative/extending/adding/person.h | 27 ++ .../declarative/extending/attached/attached.pro | 13 + .../declarative/extending/attached/attached.qrc | 5 + .../extending/attached/birthdayparty.cpp | 45 +++ .../declarative/extending/attached/birthdayparty.h | 45 +++ .../declarative/extending/attached/example.qml | 27 ++ examples/declarative/extending/attached/main.cpp | 44 +++ examples/declarative/extending/attached/person.cpp | 83 +++++ examples/declarative/extending/attached/person.h | 67 ++++ .../extending/coercion/birthdayparty.cpp | 23 ++ .../declarative/extending/coercion/birthdayparty.h | 29 ++ .../declarative/extending/coercion/coercion.pro | 13 + .../declarative/extending/coercion/coercion.qrc | 5 + .../declarative/extending/coercion/example.qml | 13 + examples/declarative/extending/coercion/main.cpp | 30 ++ examples/declarative/extending/coercion/person.cpp | 46 +++ examples/declarative/extending/coercion/person.h | 41 +++ .../extending/default/birthdayparty.cpp | 23 ++ .../declarative/extending/default/birthdayparty.h | 30 ++ examples/declarative/extending/default/default.pro | 13 + examples/declarative/extending/default/default.qrc | 5 + examples/declarative/extending/default/example.qml | 12 + examples/declarative/extending/default/main.cpp | 30 ++ examples/declarative/extending/default/person.cpp | 42 +++ examples/declarative/extending/default/person.h | 39 +++ .../extending/grouped/birthdayparty.cpp | 23 ++ .../declarative/extending/grouped/birthdayparty.h | 28 ++ examples/declarative/extending/grouped/example.qml | 31 ++ examples/declarative/extending/grouped/grouped.pro | 13 + examples/declarative/extending/grouped/grouped.qrc | 5 + examples/declarative/extending/grouped/main.cpp | 40 +++ examples/declarative/extending/grouped/person.cpp | 83 +++++ examples/declarative/extending/grouped/person.h | 69 ++++ .../declarative/extending/properties/example.qml | 13 + examples/declarative/extending/properties/main.cpp | 26 ++ .../declarative/extending/properties/person.cpp | 28 ++ examples/declarative/extending/properties/person.h | 25 ++ .../extending/properties/properties.pro | 13 + .../extending/properties/properties.qrc | 5 + src/declarative/qml/qml.h | 6 +- src/declarative/qml/qmlengine.cpp | 4 +- 50 files changed, 1870 insertions(+), 5 deletions(-) create mode 100644 doc/src/declarative/extending-examples.qdoc create mode 100644 doc/src/declarative/qmlformat.qdoc create mode 100644 examples/declarative/extending/adding/adding.pro create mode 100644 examples/declarative/extending/adding/adding.qrc create mode 100644 examples/declarative/extending/adding/example.qml create mode 100644 examples/declarative/extending/adding/main.cpp create mode 100644 examples/declarative/extending/adding/person.cpp create mode 100644 examples/declarative/extending/adding/person.h create mode 100644 examples/declarative/extending/attached/attached.pro create mode 100644 examples/declarative/extending/attached/attached.qrc create mode 100644 examples/declarative/extending/attached/birthdayparty.cpp create mode 100644 examples/declarative/extending/attached/birthdayparty.h create mode 100644 examples/declarative/extending/attached/example.qml create mode 100644 examples/declarative/extending/attached/main.cpp create mode 100644 examples/declarative/extending/attached/person.cpp create mode 100644 examples/declarative/extending/attached/person.h create mode 100644 examples/declarative/extending/coercion/birthdayparty.cpp create mode 100644 examples/declarative/extending/coercion/birthdayparty.h create mode 100644 examples/declarative/extending/coercion/coercion.pro create mode 100644 examples/declarative/extending/coercion/coercion.qrc create mode 100644 examples/declarative/extending/coercion/example.qml create mode 100644 examples/declarative/extending/coercion/main.cpp create mode 100644 examples/declarative/extending/coercion/person.cpp create mode 100644 examples/declarative/extending/coercion/person.h create mode 100644 examples/declarative/extending/default/birthdayparty.cpp create mode 100644 examples/declarative/extending/default/birthdayparty.h create mode 100644 examples/declarative/extending/default/default.pro create mode 100644 examples/declarative/extending/default/default.qrc create mode 100644 examples/declarative/extending/default/example.qml create mode 100644 examples/declarative/extending/default/main.cpp create mode 100644 examples/declarative/extending/default/person.cpp create mode 100644 examples/declarative/extending/default/person.h create mode 100644 examples/declarative/extending/grouped/birthdayparty.cpp create mode 100644 examples/declarative/extending/grouped/birthdayparty.h create mode 100644 examples/declarative/extending/grouped/example.qml create mode 100644 examples/declarative/extending/grouped/grouped.pro create mode 100644 examples/declarative/extending/grouped/grouped.qrc create mode 100644 examples/declarative/extending/grouped/main.cpp create mode 100644 examples/declarative/extending/grouped/person.cpp create mode 100644 examples/declarative/extending/grouped/person.h create mode 100644 examples/declarative/extending/properties/example.qml create mode 100644 examples/declarative/extending/properties/main.cpp create mode 100644 examples/declarative/extending/properties/person.cpp create mode 100644 examples/declarative/extending/properties/person.h create mode 100644 examples/declarative/extending/properties/properties.pro create mode 100644 examples/declarative/extending/properties/properties.qrc diff --git a/doc/src/declarative/extending-examples.qdoc b/doc/src/declarative/extending-examples.qdoc new file mode 100644 index 0000000..09239c1 --- /dev/null +++ b/doc/src/declarative/extending-examples.qdoc @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/*! +\example declarative/extending/adding +\title Extending QML - Adding Types Example + +The Adding Types Example shows how to add a new element type, \c Person, to QML. +The \c Person type can be used from QML like this: + +\snippet examples/declarative/extending/adding/example.qml 0 + +\section1 Declare the Person class + +All QML elements map to C++ types. Here we declare a basic C++ Person class +with the two properties we want accessible on the QML type - name and shoeSize. +Although in this example we use the same name for the C++ class as the QML +element, the C++ class can be named differently, or appear in a namespace. + +\snippet examples/declarative/extending/adding/person.h 0 + +Following the class declaration, we include the QML_DECLARE_TYPE() macro. This +is necessary to declare the type to QML. It also includes the logic necessary +to expose the class to Qt's meta system - that is, it includes the +Q_DECLARE_METATYPE() functionality. + +\section1 Define the Person class + +\snippet examples/declarative/extending/adding/person.cpp 0 + +The Person class implementation is quite basic. The property accessors simply +return members of the object instance. + +The implementation must also include the QML_DEFINE_TYPE() macro. This macro +registers the Person class with QML, and defines the mapping between the C++ +and QML class names. + +\section1 Running the example + +The main.cpp file in the example includes a simple shell application that +loads and runs the QML snippet shown at the beginning of this page. +*/ + +/*! +\example declarative/extending/properties +\title Extending QML - Object and List Property Types Example + +This example builds on: +\list +\o \l {Extending QML - Adding Types Example} +\endlist + +The Object and List Property Types example shows how to add object and list +properties in QML. This example adds a BirthdayParty element that specifies +a birthday party, consisting of a celebrant and a list of guests. People are +specified using the People QML type built in the previous example. + +\snippet examples/declarative/extending/properties/example.qml 0 + +\section1 Declare the BirthdayParty + +The BirthdayParty class is declared like this: + +\snippet examples/declarative/extending/properties/birthdayparty.h 0 +\snippet examples/declarative/extending/properties/birthdayparty.h 1 +\snippet examples/declarative/extending/properties/birthdayparty.h 2 +\snippet examples/declarative/extending/properties/birthdayparty.h 3 + +The class contains a member to store the celebrant object, and also a +QmlConcreteList member. + +In QML, the type of a list properties - and the guests property is a list of +people - are all of type QmlList*. QmlList is an abstract list interface +that allows a developer to react to QML accessing and modifying the contents of +the list. This is useful for implementing "virtual lists" or other advanced +scenarios, but can't be used directly for the common case of just wanting a +regular list of things. For this a concrete implementation, QmlConcreteList, is +provided and that is used here. + +\section2 Define the BirthdayParty + +The implementation of BirthdayParty property accessors is straight forward. + +\snippet examples/declarative/extending/properties/birthdayparty.cpp 0 + +\section1 Running the example + +The main.cpp file in the example includes a simple shell application that +loads and runs the QML snippet shown at the beginning of this page. +*/ + +/*! +\example declarative/extending/coercion +\title Extending QML - Inheritance and Coercion Example + +This example builds on: +\list +\o \l {Extending QML - Object and List Property Types Example} +\o \l {Extending QML - Adding Types Example} +\endlist + +The Inheritance and Coercion Example shows how to use base classes to assign +elements of more than one type to a property. It specializes the Person element +developed in the previous examples into two elements - a \c Boy and a \c Girl. + +\snippet examples/declarative/extending/coercion/example.qml 0 + +\section1 Declare Boy and Girl + +\snippet examples/declarative/extending/coercion/person.h 0 + +The Person class remains unaltered in this example and the Boy and Girl C++ +classes are trivial extensions of it. As an example, the inheritance used here +is a little contrived, but in real applications it is likely that the two +extensions would add additional properties or modify the Person classes +behavior. + +\section2 Define People as a base class + +The implementation of the People class itself has not changed since the the +previous example. However, as we have repurposed the People class as a common +base for Boy and Girl, we want to prevent it from being instantiated from QML +directly - an explicit Boy or Girl should be instantiated instead. + +\snippet examples/declarative/extending/coercion/person.cpp 0 + +While we want to disallow instantiating Person from within QML, it still needs +to be registered with the QML engine, so that it can be used as a property type +and other types can be coerced to it. To register a type, without defining a +named mapping into QML, we use the QML_DEFINE_NOCREATE_TYPE() macro instead of +the QML_DEFINE_TYPE() macro used previously. + +\section2 Define Boy and Girl + +The implementation of Boy and Girl are trivial. + +\snippet examples/declarative/extending/coercion/person.cpp 1 + +All that is necessary is to implement the constructor, and to register the types +and their QML name with the QML engine. + +\section1 Running the example + +The BirthdayParty element has not changed since the previous example. The +celebrant and guests property still use the People type. + +\snippet examples/declarative/extending/coercion/birthdayparty.h 0 + +However, as all three types, Person, Boy and Girl, have been registered with the +QML system, on assignment QML automatically (and type-safely) converts the Boy +and Girl objects into a Person. + +The main.cpp file in the example includes a simple shell application that +loads and runs the QML snippet shown at the beginning of this page. +*/ + +/*! +\example declarative/extending/default +\title Extending QML - Default Property Example + +This example builds on: +\list +\o \l {Extending QML - Inheritance and Coercion Example} +\o \l {Extending QML - Object and List Property Types Example} +\o \l {Extending QML - Adding Types Example} +\endlist + +The Default Property Example is a minor modification of the +\l {Extending QML - Inheritance and Coercion Example} that simplifies the +specification of a BirthdayParty through the use of a default property. + +\snippet examples/declarative/extending/default/example.qml 0 + +\section1 Declaring the BirthdayParty class + +The only difference between this example and the last, is the addition of the +\c DefaultProperty class info annotation. + +\snippet examples/declarative/extending/default/birthdayparty.h 0 + +The default property specifies the property to assign to whenever an explicit +property is not specified, in the case of the BirthdayParty element the guest +property. It is purely a syntactic simplification, the behavior is identical +to specifying the property by name, but it can add a more natural feel in many +situations. The default property must be either an object or list property. + +\section1 Running the example + +The main.cpp file in the example includes a simple shell application that +loads and runs the QML snippet shown at the beginning of this page. +*/ + +/*! +\example declarative/extending/grouped +\title Extending QML - Grouped Properties Example + +This example builds on: +\list +\o \l {Extending QML - Default Property Example} +\o \l {Extending QML - Inheritance and Coercion Example} +\o \l {Extending QML - Object and List Property Types Example} +\o \l {Extending QML - Adding Types Example} +\endlist + +*/ + +/*! +\example declarative/extending/grouped +\title Extending QML - Attached Properties Example + +This example builds on: +\list +\o \l {Extending QML - Grouped Properties Example} +\o \l {Extending QML - Default Property Example} +\o \l {Extending QML - Inheritance and Coercion Example} +\o \l {Extending QML - Object and List Property Types Example} +\o \l {Extending QML - Adding Types Example} +\endlist + +*/ diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc index 7163a93..138ccb2 100644 --- a/doc/src/declarative/extending.qdoc +++ b/doc/src/declarative/extending.qdoc @@ -1,3 +1,376 @@ +/**************************************************************************** +** +** 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 Property Binding + +\section1 Signal support + +\section1 Extension Objects + +\section1 Parser Status + +\section1 Property Value Sources +*/ + + /*! \page qml-extending-types.html \title Extending types from QML diff --git a/doc/src/declarative/qmlformat.qdoc b/doc/src/declarative/qmlformat.qdoc new file mode 100644 index 0000000..fd22ab5 --- /dev/null +++ b/doc/src/declarative/qmlformat.qdoc @@ -0,0 +1,6 @@ +/*! + \page qmlformat.html + \title QML Format + + Format reference here... +*/ diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index c945b24..c5d32fe 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -81,11 +81,13 @@ QML Reference: \list + \o \l {QML Format} \o \l {elements}{Qml Elements} \endlist C++ Reference: \list + \o \l {Extending QML} \o \l {qtbinding}{C++ Data Binding} \o \l {cppitem}{C++ Components} \endlist diff --git a/examples/declarative/extending/adding/adding.pro b/examples/declarative/extending/adding/adding.pro new file mode 100644 index 0000000..c02a35f --- /dev/null +++ b/examples/declarative/extending/adding/adding.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +TARGET = adding +DEPENDPATH += . +INCLUDEPATH += . +QT += declarative + +# Input +SOURCES += main.cpp \ + person.cpp +HEADERS += person.h +RESOURCES += adding.qrc diff --git a/examples/declarative/extending/adding/adding.qrc b/examples/declarative/extending/adding/adding.qrc new file mode 100644 index 0000000..e2fa01d --- /dev/null +++ b/examples/declarative/extending/adding/adding.qrc @@ -0,0 +1,5 @@ + + + example.qml + + diff --git a/examples/declarative/extending/adding/example.qml b/examples/declarative/extending/adding/example.qml new file mode 100644 index 0000000..5550cec --- /dev/null +++ b/examples/declarative/extending/adding/example.qml @@ -0,0 +1,6 @@ +// ![0] +Person { + name: "Bob Jones" + shoeSize: 12 +} +// ![0] diff --git a/examples/declarative/extending/adding/main.cpp b/examples/declarative/extending/adding/main.cpp new file mode 100644 index 0000000..3d78ded --- /dev/null +++ b/examples/declarative/extending/adding/main.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include "person.h" + +int main(int argc, char ** argv) +{ + QCoreApplication app(argc, argv); + + QmlEngine engine; + QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + Person *person = qobject_cast(component.create()); + if (person) { + qWarning() << "The person's name is" << person->name(); + qWarning() << "They wear a" << person->shoeSize() << "sized shoe"; + } else { + qWarning() << "An error occured"; + } + + return 0; +} diff --git a/examples/declarative/extending/adding/person.cpp b/examples/declarative/extending/adding/person.cpp new file mode 100644 index 0000000..4198b63 --- /dev/null +++ b/examples/declarative/extending/adding/person.cpp @@ -0,0 +1,30 @@ +#include "person.h" + +// ![0] +Person::Person(QObject *parent) +: QObject(parent), m_shoeSize(0) +{ +} + +QString Person::name() const +{ + return m_name; +} + +void Person::setName(const QString &n) +{ + m_name = n; +} + +int Person::shoeSize() const +{ + return m_shoeSize; +} + +void Person::setShoeSize(int s) +{ + m_shoeSize = s; +} + +QML_DEFINE_TYPE(Person, Person); +// ![0] diff --git a/examples/declarative/extending/adding/person.h b/examples/declarative/extending/adding/person.h new file mode 100644 index 0000000..3bef2d4 --- /dev/null +++ b/examples/declarative/extending/adding/person.h @@ -0,0 +1,27 @@ +#ifndef PERSON_H +#define PERSON_H + +#include +// ![0] +#include + +class Person : public QObject { +Q_OBJECT +Q_PROPERTY(QString name READ name WRITE setName) +Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) +public: + Person(QObject *parent = 0); + + QString name() const; + void setName(const QString &); + + int shoeSize() const; + void setShoeSize(int); +private: + QString m_name; + int m_shoeSize; +}; +QML_DECLARE_TYPE(Person); +// ![0] + +#endif // PERSON_H diff --git a/examples/declarative/extending/attached/attached.pro b/examples/declarative/extending/attached/attached.pro new file mode 100644 index 0000000..b0f3fea --- /dev/null +++ b/examples/declarative/extending/attached/attached.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = attached +DEPENDPATH += . +INCLUDEPATH += . +QT += declarative + +# Input +SOURCES += main.cpp \ + person.cpp \ + birthdayparty.cpp +HEADERS += person.h \ + birthdayparty.h +RESOURCES += attached.qrc diff --git a/examples/declarative/extending/attached/attached.qrc b/examples/declarative/extending/attached/attached.qrc new file mode 100644 index 0000000..e2fa01d --- /dev/null +++ b/examples/declarative/extending/attached/attached.qrc @@ -0,0 +1,5 @@ + + + example.qml + + diff --git a/examples/declarative/extending/attached/birthdayparty.cpp b/examples/declarative/extending/attached/birthdayparty.cpp new file mode 100644 index 0000000..49ed5a3 --- /dev/null +++ b/examples/declarative/extending/attached/birthdayparty.cpp @@ -0,0 +1,45 @@ +#include "birthdayparty.h" + +BirthdayPartyAttached::BirthdayPartyAttached(QObject *object) +: QObject(object) +{ +} + +QDate BirthdayPartyAttached::rsvp() const +{ + return m_rsvp; +} + +void BirthdayPartyAttached::setRsvp(const QDate &d) +{ + m_rsvp = d; +} + +QML_DEFINE_NOCREATE_TYPE(BirthdayPartyAttached); + +BirthdayParty::BirthdayParty(QObject *parent) +: QObject(parent), m_celebrant(0) +{ +} + +Person *BirthdayParty::celebrant() const +{ + return m_celebrant; +} + +void BirthdayParty::setCelebrant(Person *c) +{ + m_celebrant = c; +} + +QmlList *BirthdayParty::guests() +{ + return &m_guests; +} + +BirthdayPartyAttached *BirthdayParty::qmlAttachedProperties(QObject *object) +{ + return new BirthdayPartyAttached(object); +} + +QML_DEFINE_TYPE(BirthdayParty, BirthdayParty); diff --git a/examples/declarative/extending/attached/birthdayparty.h b/examples/declarative/extending/attached/birthdayparty.h new file mode 100644 index 0000000..8249af5 --- /dev/null +++ b/examples/declarative/extending/attached/birthdayparty.h @@ -0,0 +1,45 @@ +#ifndef BIRTHDAYPARTY_H +#define BIRTHDAYPARTY_H + +#include +#include +#include +#include "person.h" + +class BirthdayPartyAttached : public QObject +{ +Q_OBJECT +Q_PROPERTY(QDate rsvp READ rsvp WRITE setRsvp); +public: + BirthdayPartyAttached(QObject *object); + + QDate rsvp() const; + void setRsvp(const QDate &); + +private: + QDate m_rsvp; +}; +QML_DECLARE_TYPE(BirthdayPartyAttached); + +class BirthdayParty : public QObject +{ +Q_OBJECT +Q_PROPERTY(Person *celebrant READ celebrant WRITE setCelebrant) +Q_PROPERTY(QmlList *guests READ guests) +Q_CLASSINFO("DefaultProperty", "guests") +public: + BirthdayParty(QObject *parent = 0); + + Person *celebrant() const; + void setCelebrant(Person *); + + QmlList *guests(); + + static BirthdayPartyAttached *qmlAttachedProperties(QObject *); +private: + Person *m_celebrant; + QmlConcreteList m_guests; +}; +QML_DECLARE_TYPE(BirthdayParty); + +#endif // BIRTHDAYPARTY_H diff --git a/examples/declarative/extending/attached/example.qml b/examples/declarative/extending/attached/example.qml new file mode 100644 index 0000000..2645eac --- /dev/null +++ b/examples/declarative/extending/attached/example.qml @@ -0,0 +1,27 @@ +BirthdayParty { + celebrant: Boy { + name: "Bob Jones" + shoe { size: 12; color: "white"; brand: "Nike"; price: 90.0 } + } + + // ![1] + Boy { + name: "Joan Hodges" + BirthdayParty.rsvp: "2009-07-06" + shoe { size: 10; color: "black"; brand: "Reebok"; price: 59.95 } + } + // ![1] + Boy { + name: "Jack Smith" + shoe { size: 8; color: "blue"; brand: "Puma"; price: 19.95 } + } + Girl { + name: "Anne Brown" + BirthdayParty.rsvp: "2009-07-01" + shoe.size: 7 + shoe.color: "red" + shoe.brand: "Marc Jacobs" + shoe.price: 699.99 + } +} + diff --git a/examples/declarative/extending/attached/main.cpp b/examples/declarative/extending/attached/main.cpp new file mode 100644 index 0000000..1f10cd0 --- /dev/null +++ b/examples/declarative/extending/attached/main.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include "birthdayparty.h" +#include "person.h" + +int main(int argc, char ** argv) +{ + QCoreApplication app(argc, argv); + + QmlEngine engine; + QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + BirthdayParty *party = qobject_cast(component.create()); + + if (party && party->celebrant()) { + qWarning() << party->celebrant()->name() << "is having a birthday!"; + + if (qobject_cast(party->celebrant())) + qWarning() << "He is inviting:"; + else + qWarning() << "She is inviting:"; + + for (int ii = 0; ii < party->guests()->count(); ++ii) { + Person *guest = party->guests()->at(ii); + + QDate rsvpDate; + QObject *attached = + qmlAttachedPropertiesObject(guest, false); + if (attached) + rsvpDate = attached->property("rsvp").toDate(); + + if (rsvpDate.isNull()) + qWarning() << " " << guest->name() << "RSVP date: Hasn't RSVP'd"; + else + qWarning() << " " << guest->name() << "RSVP date:" << qPrintable(rsvpDate.toString()); + } + + } else { + qWarning() << "An error occured"; + } + + return 0; +} diff --git a/examples/declarative/extending/attached/person.cpp b/examples/declarative/extending/attached/person.cpp new file mode 100644 index 0000000..48a94e8 --- /dev/null +++ b/examples/declarative/extending/attached/person.cpp @@ -0,0 +1,83 @@ +#include "person.h" + +ShoeDescription::ShoeDescription(QObject *parent) +: QObject(parent), m_size(0), m_price(0) +{ +} + +int ShoeDescription::size() const +{ + return m_size; +} + +void ShoeDescription::setSize(int s) +{ + m_size = s; +} + +QColor ShoeDescription::color() const +{ + return m_color; +} + +void ShoeDescription::setColor(const QColor &c) +{ + m_color = c; +} + +QString ShoeDescription::brand() const +{ + return m_brand; +} + +void ShoeDescription::setBrand(const QString &b) +{ + m_brand = b; +} + +qreal ShoeDescription::price() const +{ + return m_price; +} + +void ShoeDescription::setPrice(qreal p) +{ + m_price = p; +} +QML_DEFINE_NOCREATE_TYPE(ShoeDescription); + +Person::Person(QObject *parent) +: QObject(parent) +{ +} + +QString Person::name() const +{ + return m_name; +} + +void Person::setName(const QString &n) +{ + m_name = n; +} + +ShoeDescription *Person::shoe() +{ + return &m_shoe; +} + +QML_DEFINE_NOCREATE_TYPE(Person); + +Boy::Boy(QObject * parent) +: Person(parent) +{ +} + +QML_DEFINE_TYPE(Boy, Boy); + +Girl::Girl(QObject * parent) +: Person(parent) +{ +} + +QML_DEFINE_TYPE(Girl, Girl); diff --git a/examples/declarative/extending/attached/person.h b/examples/declarative/extending/attached/person.h new file mode 100644 index 0000000..07dfe0e --- /dev/null +++ b/examples/declarative/extending/attached/person.h @@ -0,0 +1,67 @@ +#ifndef PERSON_H +#define PERSON_H + +#include +#include +#include + +class ShoeDescription : public QObject { +Q_OBJECT +Q_PROPERTY(int size READ size WRITE setSize) +Q_PROPERTY(QColor color READ color WRITE setColor) +Q_PROPERTY(QString brand READ brand WRITE setBrand) +Q_PROPERTY(qreal price READ price WRITE setPrice) +public: + ShoeDescription(QObject *parent = 0); + + int size() const; + void setSize(int); + + QColor color() const; + void setColor(const QColor &); + + QString brand() const; + void setBrand(const QString &); + + qreal price() const; + void setPrice(qreal); +private: + int m_size; + QColor m_color; + QString m_brand; + qreal m_price; +}; +QML_DECLARE_TYPE(ShoeDescription); + +class Person : public QObject { +Q_OBJECT +Q_PROPERTY(QString name READ name WRITE setName) +Q_PROPERTY(ShoeDescription *shoe READ shoe); +public: + Person(QObject *parent = 0); + + QString name() const; + void setName(const QString &); + + ShoeDescription *shoe(); +private: + QString m_name; + ShoeDescription m_shoe; +}; +QML_DECLARE_TYPE(Person); + +class Boy : public Person { +Q_OBJECT +public: + Boy(QObject * parent = 0); +}; +QML_DECLARE_TYPE(Boy); + +class Girl : public Person { +Q_OBJECT +public: + Girl(QObject * parent = 0); +}; +QML_DECLARE_TYPE(Girl); + +#endif // PERSON_H diff --git a/examples/declarative/extending/coercion/birthdayparty.cpp b/examples/declarative/extending/coercion/birthdayparty.cpp new file mode 100644 index 0000000..cdff6e1 --- /dev/null +++ b/examples/declarative/extending/coercion/birthdayparty.cpp @@ -0,0 +1,23 @@ +#include "birthdayparty.h" + +BirthdayParty::BirthdayParty(QObject *parent) +: QObject(parent), m_celebrant(0) +{ +} + +Person *BirthdayParty::celebrant() const +{ + return m_celebrant; +} + +void BirthdayParty::setCelebrant(Person *c) +{ + m_celebrant = c; +} + +QmlList *BirthdayParty::guests() +{ + return &m_guests; +} + +QML_DEFINE_TYPE(BirthdayParty, BirthdayParty); diff --git a/examples/declarative/extending/coercion/birthdayparty.h b/examples/declarative/extending/coercion/birthdayparty.h new file mode 100644 index 0000000..2557d1a --- /dev/null +++ b/examples/declarative/extending/coercion/birthdayparty.h @@ -0,0 +1,29 @@ +#ifndef BIRTHDAYPARTY_H +#define BIRTHDAYPARTY_H + +#include +#include +#include "person.h" + +class BirthdayParty : public QObject +{ +Q_OBJECT +// ![0] +Q_PROPERTY(Person *celebrant READ celebrant WRITE setCelebrant) +Q_PROPERTY(QmlList *guests READ guests) +// ![0] +public: + BirthdayParty(QObject *parent = 0); + + Person *celebrant() const; + void setCelebrant(Person *); + + QmlList *guests(); + +private: + Person *m_celebrant; + QmlConcreteList m_guests; +}; +QML_DECLARE_TYPE(BirthdayParty); + +#endif // BIRTHDAYPARTY_H diff --git a/examples/declarative/extending/coercion/coercion.pro b/examples/declarative/extending/coercion/coercion.pro new file mode 100644 index 0000000..136b210 --- /dev/null +++ b/examples/declarative/extending/coercion/coercion.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = coercion +DEPENDPATH += . +INCLUDEPATH += . +QT += declarative + +# Input +SOURCES += main.cpp \ + person.cpp \ + birthdayparty.cpp +HEADERS += person.h \ + birthdayparty.h +RESOURCES += coercion.qrc diff --git a/examples/declarative/extending/coercion/coercion.qrc b/examples/declarative/extending/coercion/coercion.qrc new file mode 100644 index 0000000..e2fa01d --- /dev/null +++ b/examples/declarative/extending/coercion/coercion.qrc @@ -0,0 +1,5 @@ + + + example.qml + + diff --git a/examples/declarative/extending/coercion/example.qml b/examples/declarative/extending/coercion/example.qml new file mode 100644 index 0000000..8bcb45a --- /dev/null +++ b/examples/declarative/extending/coercion/example.qml @@ -0,0 +1,13 @@ +// ![0] +BirthdayParty { + celebrant: Boy { + name: "Bob Jones" + shoeSize: 12 + } + guests: [ + Boy { name: "Joan Hodges" }, + Boy { name: "Jack Smith" }, + Girl { name: "Anne Brown" } + ] +} +// ![0] diff --git a/examples/declarative/extending/coercion/main.cpp b/examples/declarative/extending/coercion/main.cpp new file mode 100644 index 0000000..7439ba9 --- /dev/null +++ b/examples/declarative/extending/coercion/main.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include "birthdayparty.h" +#include "person.h" + +int main(int argc, char ** argv) +{ + QCoreApplication app(argc, argv); + + QmlEngine engine; + QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + BirthdayParty *party = qobject_cast(component.create()); + + if (party && party->celebrant()) { + qWarning() << party->celebrant()->name() << "is having a birthday!"; + + if (qobject_cast(party->celebrant())) + qWarning() << "He is inviting:"; + else + qWarning() << "She is inviting:"; + for (int ii = 0; ii < party->guests()->count(); ++ii) + qWarning() << " " << party->guests()->at(ii)->name(); + } else { + qWarning() << "An error occured"; + } + + return 0; +} diff --git a/examples/declarative/extending/coercion/person.cpp b/examples/declarative/extending/coercion/person.cpp new file mode 100644 index 0000000..4605db9 --- /dev/null +++ b/examples/declarative/extending/coercion/person.cpp @@ -0,0 +1,46 @@ +#include "person.h" + +Person::Person(QObject *parent) +: QObject(parent), m_shoeSize(0) +{ +} + +QString Person::name() const +{ + return m_name; +} + +void Person::setName(const QString &n) +{ + m_name = n; +} + +int Person::shoeSize() const +{ + return m_shoeSize; +} + +void Person::setShoeSize(int s) +{ + m_shoeSize = s; +} + +// ![0] +QML_DEFINE_NOCREATE_TYPE(Person); +// ![0] + +// ![1] +Boy::Boy(QObject * parent) +: Person(parent) +{ +} + +QML_DEFINE_TYPE(Boy, Boy); + +Girl::Girl(QObject * parent) +: Person(parent) +{ +} + +QML_DEFINE_TYPE(Girl, Girl); +// ![1] diff --git a/examples/declarative/extending/coercion/person.h b/examples/declarative/extending/coercion/person.h new file mode 100644 index 0000000..de14019 --- /dev/null +++ b/examples/declarative/extending/coercion/person.h @@ -0,0 +1,41 @@ +#ifndef PERSON_H +#define PERSON_H + +#include +#include + +class Person : public QObject { +Q_OBJECT +Q_PROPERTY(QString name READ name WRITE setName) +Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) +public: + Person(QObject *parent = 0); + + QString name() const; + void setName(const QString &); + + int shoeSize() const; + void setShoeSize(int); +private: + QString m_name; + int m_shoeSize; +}; +QML_DECLARE_TYPE(Person); + +// ![0] +class Boy : public Person { +Q_OBJECT +public: + Boy(QObject * parent = 0); +}; +QML_DECLARE_TYPE(Boy); + +class Girl : public Person { +Q_OBJECT +public: + Girl(QObject * parent = 0); +}; +QML_DECLARE_TYPE(Girl); +// ![0] + +#endif // PERSON_H diff --git a/examples/declarative/extending/default/birthdayparty.cpp b/examples/declarative/extending/default/birthdayparty.cpp new file mode 100644 index 0000000..cdff6e1 --- /dev/null +++ b/examples/declarative/extending/default/birthdayparty.cpp @@ -0,0 +1,23 @@ +#include "birthdayparty.h" + +BirthdayParty::BirthdayParty(QObject *parent) +: QObject(parent), m_celebrant(0) +{ +} + +Person *BirthdayParty::celebrant() const +{ + return m_celebrant; +} + +void BirthdayParty::setCelebrant(Person *c) +{ + m_celebrant = c; +} + +QmlList *BirthdayParty::guests() +{ + return &m_guests; +} + +QML_DEFINE_TYPE(BirthdayParty, BirthdayParty); diff --git a/examples/declarative/extending/default/birthdayparty.h b/examples/declarative/extending/default/birthdayparty.h new file mode 100644 index 0000000..084da10 --- /dev/null +++ b/examples/declarative/extending/default/birthdayparty.h @@ -0,0 +1,30 @@ +#ifndef BIRTHDAYPARTY_H +#define BIRTHDAYPARTY_H + +#include +#include +#include "person.h" + +// ![0] +class BirthdayParty : public QObject +{ +Q_OBJECT +Q_PROPERTY(Person *celebrant READ celebrant WRITE setCelebrant) +Q_PROPERTY(QmlList *guests READ guests) +Q_CLASSINFO("DefaultProperty", "guests") +public: + BirthdayParty(QObject *parent = 0); + + Person *celebrant() const; + void setCelebrant(Person *); + + QmlList *guests(); + +private: + Person *m_celebrant; + QmlConcreteList m_guests; +}; +// ![0] +QML_DECLARE_TYPE(BirthdayParty); + +#endif // BIRTHDAYPARTY_H diff --git a/examples/declarative/extending/default/default.pro b/examples/declarative/extending/default/default.pro new file mode 100644 index 0000000..0d5d45c --- /dev/null +++ b/examples/declarative/extending/default/default.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = default +DEPENDPATH += . +INCLUDEPATH += . +QT += declarative + +# Input +SOURCES += main.cpp \ + person.cpp \ + birthdayparty.cpp +HEADERS += person.h \ + birthdayparty.h +RESOURCES += default.qrc diff --git a/examples/declarative/extending/default/default.qrc b/examples/declarative/extending/default/default.qrc new file mode 100644 index 0000000..e2fa01d --- /dev/null +++ b/examples/declarative/extending/default/default.qrc @@ -0,0 +1,5 @@ + + + example.qml + + diff --git a/examples/declarative/extending/default/example.qml b/examples/declarative/extending/default/example.qml new file mode 100644 index 0000000..4023abb --- /dev/null +++ b/examples/declarative/extending/default/example.qml @@ -0,0 +1,12 @@ +// ![0] +BirthdayParty { + celebrant: Boy { + name: "Bob Jones" + shoeSize: 12 + } + + Boy { name: "Joan Hodges" } + Boy { name: "Jack Smith" } + Girl { name: "Anne Brown" } +} +// ![0] diff --git a/examples/declarative/extending/default/main.cpp b/examples/declarative/extending/default/main.cpp new file mode 100644 index 0000000..7439ba9 --- /dev/null +++ b/examples/declarative/extending/default/main.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include "birthdayparty.h" +#include "person.h" + +int main(int argc, char ** argv) +{ + QCoreApplication app(argc, argv); + + QmlEngine engine; + QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + BirthdayParty *party = qobject_cast(component.create()); + + if (party && party->celebrant()) { + qWarning() << party->celebrant()->name() << "is having a birthday!"; + + if (qobject_cast(party->celebrant())) + qWarning() << "He is inviting:"; + else + qWarning() << "She is inviting:"; + for (int ii = 0; ii < party->guests()->count(); ++ii) + qWarning() << " " << party->guests()->at(ii)->name(); + } else { + qWarning() << "An error occured"; + } + + return 0; +} diff --git a/examples/declarative/extending/default/person.cpp b/examples/declarative/extending/default/person.cpp new file mode 100644 index 0000000..c47bfb7 --- /dev/null +++ b/examples/declarative/extending/default/person.cpp @@ -0,0 +1,42 @@ +#include "person.h" + +Person::Person(QObject *parent) +: QObject(parent), m_shoeSize(0) +{ +} + +QString Person::name() const +{ + return m_name; +} + +void Person::setName(const QString &n) +{ + m_name = n; +} + +int Person::shoeSize() const +{ + return m_shoeSize; +} + +void Person::setShoeSize(int s) +{ + m_shoeSize = s; +} + +QML_DEFINE_NOCREATE_TYPE(Person); + +Boy::Boy(QObject * parent) +: Person(parent) +{ +} + +QML_DEFINE_TYPE(Boy, Boy); + +Girl::Girl(QObject * parent) +: Person(parent) +{ +} + +QML_DEFINE_TYPE(Girl, Girl); diff --git a/examples/declarative/extending/default/person.h b/examples/declarative/extending/default/person.h new file mode 100644 index 0000000..872186c --- /dev/null +++ b/examples/declarative/extending/default/person.h @@ -0,0 +1,39 @@ +#ifndef PERSON_H +#define PERSON_H + +#include +#include + +class Person : public QObject { +Q_OBJECT +Q_PROPERTY(QString name READ name WRITE setName) +Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) +public: + Person(QObject *parent = 0); + + QString name() const; + void setName(const QString &); + + int shoeSize() const; + void setShoeSize(int); +private: + QString m_name; + int m_shoeSize; +}; +QML_DECLARE_TYPE(Person); + +class Boy : public Person { +Q_OBJECT +public: + Boy(QObject * parent = 0); +}; +QML_DECLARE_TYPE(Boy); + +class Girl : public Person { +Q_OBJECT +public: + Girl(QObject * parent = 0); +}; +QML_DECLARE_TYPE(Girl); + +#endif // PERSON_H diff --git a/examples/declarative/extending/grouped/birthdayparty.cpp b/examples/declarative/extending/grouped/birthdayparty.cpp new file mode 100644 index 0000000..cdff6e1 --- /dev/null +++ b/examples/declarative/extending/grouped/birthdayparty.cpp @@ -0,0 +1,23 @@ +#include "birthdayparty.h" + +BirthdayParty::BirthdayParty(QObject *parent) +: QObject(parent), m_celebrant(0) +{ +} + +Person *BirthdayParty::celebrant() const +{ + return m_celebrant; +} + +void BirthdayParty::setCelebrant(Person *c) +{ + m_celebrant = c; +} + +QmlList *BirthdayParty::guests() +{ + return &m_guests; +} + +QML_DEFINE_TYPE(BirthdayParty, BirthdayParty); diff --git a/examples/declarative/extending/grouped/birthdayparty.h b/examples/declarative/extending/grouped/birthdayparty.h new file mode 100644 index 0000000..3d53319 --- /dev/null +++ b/examples/declarative/extending/grouped/birthdayparty.h @@ -0,0 +1,28 @@ +#ifndef BIRTHDAYPARTY_H +#define BIRTHDAYPARTY_H + +#include +#include +#include "person.h" + +class BirthdayParty : public QObject +{ +Q_OBJECT +Q_PROPERTY(Person *celebrant READ celebrant WRITE setCelebrant) +Q_PROPERTY(QmlList *guests READ guests) +Q_CLASSINFO("DefaultProperty", "guests") +public: + BirthdayParty(QObject *parent = 0); + + Person *celebrant() const; + void setCelebrant(Person *); + + QmlList *guests(); + +private: + Person *m_celebrant; + QmlConcreteList m_guests; +}; +QML_DECLARE_TYPE(BirthdayParty); + +#endif // BIRTHDAYPARTY_H diff --git a/examples/declarative/extending/grouped/example.qml b/examples/declarative/extending/grouped/example.qml new file mode 100644 index 0000000..b9e5e6b --- /dev/null +++ b/examples/declarative/extending/grouped/example.qml @@ -0,0 +1,31 @@ +// ![0] +BirthdayParty { + celebrant: Boy { + name: "Bob Jones" + shoe { size: 12; color: "white"; brand: "Nike"; price: 90.0 } + } + + Boy { + name: "Joan Hodges" + shoe { size: 10; color: "black"; brand: "Reebok"; price: 59.95 } + } + // ![1] + Boy { + name: "Jack Smith" + shoe { + size: 8 + color: "blue" + brand: "Puma" + price: 19.95 + } + } + // ![1] + Girl { + name: "Anne Brown" + shoe.size: 7 + shoe.color: "red" + shoe.brand: "Marc Jacobs" + shoe.price: 699.99 + } +} +// ![0] diff --git a/examples/declarative/extending/grouped/grouped.pro b/examples/declarative/extending/grouped/grouped.pro new file mode 100644 index 0000000..8fde8e8 --- /dev/null +++ b/examples/declarative/extending/grouped/grouped.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = grouped +DEPENDPATH += . +INCLUDEPATH += . +QT += declarative + +# Input +SOURCES += main.cpp \ + person.cpp \ + birthdayparty.cpp +HEADERS += person.h \ + birthdayparty.h +RESOURCES += grouped.qrc diff --git a/examples/declarative/extending/grouped/grouped.qrc b/examples/declarative/extending/grouped/grouped.qrc new file mode 100644 index 0000000..e2fa01d --- /dev/null +++ b/examples/declarative/extending/grouped/grouped.qrc @@ -0,0 +1,5 @@ + + + example.qml + + diff --git a/examples/declarative/extending/grouped/main.cpp b/examples/declarative/extending/grouped/main.cpp new file mode 100644 index 0000000..0c9bb97 --- /dev/null +++ b/examples/declarative/extending/grouped/main.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include "birthdayparty.h" +#include "person.h" + +int main(int argc, char ** argv) +{ + QCoreApplication app(argc, argv); + + QmlEngine engine; + QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + BirthdayParty *party = qobject_cast(component.create()); + + if (party && party->celebrant()) { + qWarning() << party->celebrant()->name() << "is having a birthday!"; + + if (qobject_cast(party->celebrant())) + qWarning() << "He is inviting:"; + else + qWarning() << "She is inviting:"; + + Person *bestShoe = 0; + for (int ii = 0; ii < party->guests()->count(); ++ii) { + Person *guest = party->guests()->at(ii); + qWarning() << " " << guest->name(); + + if (!bestShoe || bestShoe->shoe()->price() < guest->shoe()->price()) + bestShoe = guest; + } + if (bestShoe) + qWarning() << bestShoe->name() << "is wearing the best shoes!"; + + } else { + qWarning() << "An error occured"; + } + + return 0; +} diff --git a/examples/declarative/extending/grouped/person.cpp b/examples/declarative/extending/grouped/person.cpp new file mode 100644 index 0000000..48a94e8 --- /dev/null +++ b/examples/declarative/extending/grouped/person.cpp @@ -0,0 +1,83 @@ +#include "person.h" + +ShoeDescription::ShoeDescription(QObject *parent) +: QObject(parent), m_size(0), m_price(0) +{ +} + +int ShoeDescription::size() const +{ + return m_size; +} + +void ShoeDescription::setSize(int s) +{ + m_size = s; +} + +QColor ShoeDescription::color() const +{ + return m_color; +} + +void ShoeDescription::setColor(const QColor &c) +{ + m_color = c; +} + +QString ShoeDescription::brand() const +{ + return m_brand; +} + +void ShoeDescription::setBrand(const QString &b) +{ + m_brand = b; +} + +qreal ShoeDescription::price() const +{ + return m_price; +} + +void ShoeDescription::setPrice(qreal p) +{ + m_price = p; +} +QML_DEFINE_NOCREATE_TYPE(ShoeDescription); + +Person::Person(QObject *parent) +: QObject(parent) +{ +} + +QString Person::name() const +{ + return m_name; +} + +void Person::setName(const QString &n) +{ + m_name = n; +} + +ShoeDescription *Person::shoe() +{ + return &m_shoe; +} + +QML_DEFINE_NOCREATE_TYPE(Person); + +Boy::Boy(QObject * parent) +: Person(parent) +{ +} + +QML_DEFINE_TYPE(Boy, Boy); + +Girl::Girl(QObject * parent) +: Person(parent) +{ +} + +QML_DEFINE_TYPE(Girl, Girl); diff --git a/examples/declarative/extending/grouped/person.h b/examples/declarative/extending/grouped/person.h new file mode 100644 index 0000000..b83eb5b --- /dev/null +++ b/examples/declarative/extending/grouped/person.h @@ -0,0 +1,69 @@ +#ifndef PERSON_H +#define PERSON_H + +#include +#include +#include + +class ShoeDescription : public QObject { +Q_OBJECT +Q_PROPERTY(int size READ size WRITE setSize) +Q_PROPERTY(QColor color READ color WRITE setColor) +Q_PROPERTY(QString brand READ brand WRITE setBrand) +Q_PROPERTY(qreal price READ price WRITE setPrice) +public: + ShoeDescription(QObject *parent = 0); + + int size() const; + void setSize(int); + + QColor color() const; + void setColor(const QColor &); + + QString brand() const; + void setBrand(const QString &); + + qreal price() const; + void setPrice(qreal); +private: + int m_size; + QColor m_color; + QString m_brand; + qreal m_price; +}; +QML_DECLARE_TYPE(ShoeDescription); + +class Person : public QObject { +Q_OBJECT +Q_PROPERTY(QString name READ name WRITE setName) +// ![1] +Q_PROPERTY(ShoeDescription *shoe READ shoe); +// ![1] +public: + Person(QObject *parent = 0); + + QString name() const; + void setName(const QString &); + + ShoeDescription *shoe(); +private: + QString m_name; + ShoeDescription m_shoe; +}; +QML_DECLARE_TYPE(Person); + +class Boy : public Person { +Q_OBJECT +public: + Boy(QObject * parent = 0); +}; +QML_DECLARE_TYPE(Boy); + +class Girl : public Person { +Q_OBJECT +public: + Girl(QObject * parent = 0); +}; +QML_DECLARE_TYPE(Girl); + +#endif // PERSON_H diff --git a/examples/declarative/extending/properties/example.qml b/examples/declarative/extending/properties/example.qml new file mode 100644 index 0000000..63bb77b --- /dev/null +++ b/examples/declarative/extending/properties/example.qml @@ -0,0 +1,13 @@ +// ![0] +BirthdayParty { + celebrant: Person { + name: "Bob Jones" + shoeSize: 12 + } + guests: [ + Person { name: "Joan Hodges" }, + Person { name: "Jack Smith" }, + Person { name: "Anne Brown" } + ] +} +// ![0] diff --git a/examples/declarative/extending/properties/main.cpp b/examples/declarative/extending/properties/main.cpp new file mode 100644 index 0000000..7b80914 --- /dev/null +++ b/examples/declarative/extending/properties/main.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include "birthdayparty.h" +#include "person.h" + +int main(int argc, char ** argv) +{ + QCoreApplication app(argc, argv); + + QmlEngine engine; + QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + BirthdayParty *party = qobject_cast(component.create()); + + if (party && party->celebrant()) { + qWarning() << party->celebrant()->name() << "is having a birthday!"; + qWarning() << "They are inviting:"; + for (int ii = 0; ii < party->guests()->count(); ++ii) + qWarning() << " " << party->guests()->at(ii)->name(); + } else { + qWarning() << "An error occured"; + } + + return 0; +} diff --git a/examples/declarative/extending/properties/person.cpp b/examples/declarative/extending/properties/person.cpp new file mode 100644 index 0000000..cf66a30 --- /dev/null +++ b/examples/declarative/extending/properties/person.cpp @@ -0,0 +1,28 @@ +#include "person.h" + +Person::Person(QObject *parent) +: QObject(parent), m_shoeSize(0) +{ +} + +QString Person::name() const +{ + return m_name; +} + +void Person::setName(const QString &n) +{ + m_name = n; +} + +int Person::shoeSize() const +{ + return m_shoeSize; +} + +void Person::setShoeSize(int s) +{ + m_shoeSize = s; +} + +QML_DEFINE_TYPE(Person, Person); diff --git a/examples/declarative/extending/properties/person.h b/examples/declarative/extending/properties/person.h new file mode 100644 index 0000000..2bc98c1 --- /dev/null +++ b/examples/declarative/extending/properties/person.h @@ -0,0 +1,25 @@ +#ifndef PERSON_H +#define PERSON_H + +#include +#include + +class Person : public QObject { +Q_OBJECT +Q_PROPERTY(QString name READ name WRITE setName) +Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) +public: + Person(QObject *parent = 0); + + QString name() const; + void setName(const QString &); + + int shoeSize() const; + void setShoeSize(int); +private: + QString m_name; + int m_shoeSize; +}; +QML_DECLARE_TYPE(Person); + +#endif // PERSON_H diff --git a/examples/declarative/extending/properties/properties.pro b/examples/declarative/extending/properties/properties.pro new file mode 100644 index 0000000..6355644 --- /dev/null +++ b/examples/declarative/extending/properties/properties.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = properties +DEPENDPATH += . +INCLUDEPATH += . +QT += declarative + +# Input +SOURCES += main.cpp \ + person.cpp \ + birthdayparty.cpp +HEADERS += person.h \ + birthdayparty.h +RESOURCES += properties.qrc diff --git a/examples/declarative/extending/properties/properties.qrc b/examples/declarative/extending/properties/properties.qrc new file mode 100644 index 0000000..e2fa01d --- /dev/null +++ b/examples/declarative/extending/properties/properties.qrc @@ -0,0 +1,5 @@ + + + example.qml + + diff --git a/src/declarative/qml/qml.h b/src/declarative/qml/qml.h index 1990b7f..cd01f6a 100644 --- a/src/declarative/qml/qml.h +++ b/src/declarative/qml/qml.h @@ -93,10 +93,10 @@ class QmlEngine; Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *); Q_DECLARATIVE_EXPORT QmlContext *qmlContext(const QObject *); Q_DECLARATIVE_EXPORT QmlEngine *qmlEngine(const QObject *); -Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *); +Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true); template -QObject *qmlAttachedPropertiesObject(const QObject *obj) +QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) { // ### is this threadsafe? static int idx = -1; @@ -107,7 +107,7 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj) if (idx == -1 || !obj) return 0; - return qmlAttachedPropertiesObjectById(idx, obj); + return qmlAttachedPropertiesObjectById(idx, obj, create); } QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 9eb169e..01a0494 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -707,13 +707,13 @@ QmlEngine *qmlEngine(const QObject *obj) return context?context->engine():0; } -QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object) +QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) { QmlExtendedDeclarativeData *edata = QmlExtendedDeclarativeData::get(const_cast(object), true); QObject *rv = edata->attachedProperties.value(id); - if (rv) + if (rv || !create) return rv; QmlAttachedPropertiesFunc pf = QmlMetaType::attachedPropertiesFuncById(id); -- cgit v0.12 From 2e063be4256d64599fd04d40894b187e0dbba045 Mon Sep 17 00:00:00 2001 From: mae Date: Mon, 6 Jul 2009 19:08:55 +0200 Subject: extend the QObjectPrivate::connectedSignals bitfield to make space for all the required NOTIFY signals we need for QML bindings. An additional internal function QMetaObject::isConnected() allows to query the bits, or you use connectedSignals[0] if you know that the signal in question has a QMetaObject::indexOfSignal() < 32. --- src/corelib/animation/qvariantanimation.cpp | 2 +- src/corelib/kernel/qobject.cpp | 77 +++++++++++++++++++++++------ src/corelib/kernel/qobject_p.h | 2 +- src/corelib/kernel/qobjectdefs.h | 3 ++ src/gui/graphicsview/qgraphicsitem.cpp | 2 +- src/gui/graphicsview/qgraphicsscene.cpp | 8 +-- 6 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index c5c805f..d166869 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -267,7 +267,7 @@ void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress) localProgress); qSwap(currentValue, ret); q->updateCurrentValue(currentValue); - if ((connectedSignals & changedSignalMask) && currentValue != ret) { + if ((connectedSignals[0] & changedSignalMask) && currentValue != ret) { //the value has changed emit q->valueChanged(currentValue); } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index d53ca7d..724ebca 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -139,7 +139,8 @@ QObjectPrivate::QObjectPrivate(int version) receiveChildEvents = true; postedEvents = 0; extraData = 0; - connectedSignals = 0; + for (uint i = 0; i < (sizeof connectedSignals / sizeof connectedSignals[0]); ++i) + connectedSignals[i] = 0; inEventHandler = false; inThreadChangeEvent = false; deleteWatch = 0; @@ -2831,10 +2832,16 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, s->d_func()->addConnection(signal_index, c); - if (signal_index < 0) - sender->d_func()->connectedSignals = ~0u; - else if (signal_index < 32) - sender->d_func()->connectedSignals |= (1 << signal_index); + if (signal_index < 0) { + for (uint i = 0; i < (sizeof sender->d_func()->connectedSignals + / sizeof sender->d_func()->connectedSignals[0] ); ++i) + sender->d_func()->connectedSignals[i] = ~0u; + } else if (signal_index < (int)sizeof sender->d_func()->connectedSignals * 8) { + uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); + sender->d_func()->connectedSignals[n] |= (1 << (signal_index - n * 8 + * sizeof sender->d_func()->connectedSignals[0])); + } + return true; } @@ -3174,11 +3181,12 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal */ void QMetaObject::activate(QObject *sender, int signal_index, void **argv) { - if (signal_index < 32 + if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 && !qt_signal_spy_callback_set.signal_begin_callback && !qt_signal_spy_callback_set.signal_end_callback) { - uint signal_mask = 1 << signal_index; - if ((sender->d_func()->connectedSignals & signal_mask) == 0) + uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); + uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); + if ((sender->d_func()->connectedSignals[n] & m) == 0) // nothing connected to these signals, and no spy return; } @@ -3191,11 +3199,12 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign void **argv) { int signal_index = m->methodOffset() + local_signal_index; - if (signal_index < 32 + if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 && !qt_signal_spy_callback_set.signal_begin_callback && !qt_signal_spy_callback_set.signal_end_callback) { - uint signal_mask = 1 << signal_index; - if ((sender->d_func()->connectedSignals & signal_mask) == 0) + uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); + uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); + if ((sender->d_func()->connectedSignals[n] & m) == 0) // nothing connected to these signals, and no spy return; } @@ -3207,21 +3216,59 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign void QMetaObject::activate(QObject *sender, const QMetaObject *m, int from_local_signal_index, int to_local_signal_index, void **argv) { + Q_ASSERT(from_local_signal_index <= to_local_signal_index); int offset = m->methodOffset(); int from_signal_index = offset + from_local_signal_index; int to_signal_index = offset + to_local_signal_index; - if (to_signal_index < 32 + + if (to_signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 && !qt_signal_spy_callback_set.signal_begin_callback && !qt_signal_spy_callback_set.signal_end_callback) { - uint signal_mask = (1 << (to_signal_index + 1)) - 1; - signal_mask ^= (1 << from_signal_index) - 1; - if ((sender->d_func()->connectedSignals & signal_mask) == 0) + + uint n = (from_signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); + uint m = 1 << (from_signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); + uint nt = (to_signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); + uint mt = 1 << (to_signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); + bool connected = false; + quint32 *connectedSignals = sender->d_func()->connectedSignals; + for (uint i = 0; !connected && i < (sizeof sender->d_func()->connectedSignals + / sizeof sender->d_func()->connectedSignals[0]); ++i) { + uint mask = 0; + if (i > n) + mask = ~0u; + else if (i == n) + mask = ~(m -1); + if (i > nt) + mask = 0; + else if (i == nt) + mask &= (mt << 1) - 1; + connected = connectedSignals[i] & mask; + } + if (!connected) // nothing connected to these signals, and no spy return; } activate(sender, from_signal_index, to_signal_index, argv); } +/*! \internal + + Returns true if the signal with index \a signal_index from object \a sender is connected. + Signals with indices above a certain range are always considered connected (see connectedSignals + in QObjectPrivate). If a signal spy is installed, all signals are considered connected. +*/ +bool QMetaObject::isConnected(QObject *sender, int signal_index) { + if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 + && !qt_signal_spy_callback_set.signal_begin_callback + && !qt_signal_spy_callback_set.signal_end_callback) { + uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); + uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); + if ((sender->d_func()->connectedSignals[n] & m) == 0) + // nothing connected to these signals, and no spy + return false; + } + return true; +} /***************************************************************************** Properties diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 1b8aee6..83239fe 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -150,7 +150,7 @@ public: QList propertyValues; }; ExtraData *extraData; - mutable quint32 connectedSignals; + mutable quint32 connectedSignals[2]; QString objectName; diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 7eb7c44..abfb01a 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -336,6 +336,9 @@ struct Q_CORE_EXPORT QMetaObject static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv); static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv); static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv); + + static bool isConnected(QObject *sender, int signal_index); + // internal guarded pointers static void addGuard(QObject **ptr); static void removeGuard(QObject **ptr); diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 2223f5d..4c15a15 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -6490,7 +6490,7 @@ void QGraphicsItem::prepareGeometryChange() // if someone is connected to the changed signal or the scene has no views. // Note that this has to be done *after* markDirty to ensure that // _q_processDirtyItems is called before _q_emitUpdated. - if ((scenePrivate->connectedSignals & scenePrivate->changedSignalMask) + if ((scenePrivate->connectedSignals[0] & scenePrivate->changedSignalMask) || scenePrivate->views.isEmpty()) { d_ptr->scene->update(sceneTransform().mapRect(boundingRect())); } diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index e50ee94..7e7ea98 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -604,7 +604,7 @@ void QGraphicsScenePrivate::_q_emitUpdated() // the optimization that items send updates directly to the views, but it // needs to happen in order to keep compatibility with the behavior from // Qt 4.4 and backward. - if (connectedSignals & changedSignalMask) { + if (connectedSignals[0] & changedSignalMask) { for (int i = 0; i < views.size(); ++i) { QGraphicsView *view = views.at(i); if (!view->d_func()->connectedToScene) { @@ -3730,7 +3730,7 @@ void QGraphicsScene::update(const QRectF &rect) // Check if anyone's connected; if not, we can send updates directly to // the views. Otherwise or if there are no views, use old behavior. - bool directUpdates = !(d->connectedSignals & d->changedSignalMask) && !d->views.isEmpty(); + bool directUpdates = !(d->connectedSignals[0] & d->changedSignalMask) && !d->views.isEmpty(); if (rect.isNull()) { d->updateAll = true; d->updatedRects.clear(); @@ -5394,7 +5394,7 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b if (removingItemFromScene) { // Note that this function can be called from the item's destructor, so // do NOT call any virtual functions on it within this block. - if ((connectedSignals & changedSignalMask) || views.isEmpty()) { + if ((connectedSignals[0] & changedSignalMask) || views.isEmpty()) { // This block of code is kept for compatibility. Since 4.5, by default // QGraphicsView does not connect the signal and we use the below // method of delivering updates. @@ -5481,7 +5481,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool // Process item. if (item && (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint)) { - const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask); + const bool useCompatUpdate = views.isEmpty() || (connectedSignals[0] & changedSignalMask); const bool untransformableItem = item->d_ptr->itemIsUntransformable(); const QRectF itemBoundingRect = adjustedItemBoundingRect(item); -- cgit v0.12 From 36018fb9de1d1943454d518fb4df1f8df41e67b5 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 7 Jul 2009 09:38:31 +1000 Subject: Add textFormat property to the Text element. --- src/declarative/fx/qfxtext.cpp | 75 +++++++++++++++++++++++++++++++++++++- src/declarative/fx/qfxtext.h | 8 ++++ src/declarative/fx/qfxtext_p.h | 4 +- src/declarative/fx/qfxtextedit.cpp | 2 +- 4 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/declarative/fx/qfxtext.cpp b/src/declarative/fx/qfxtext.cpp index f2519dc..57897ed 100644 --- a/src/declarative/fx/qfxtext.cpp +++ b/src/declarative/fx/qfxtext.cpp @@ -162,7 +162,7 @@ void QFxText::setText(const QString &n) if (d->text == n) return; - d->richText = Qt::mightBeRichText(n); // ### what's the cost? + d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n)); if (d->richText) { if (!d->doc) { @@ -170,7 +170,7 @@ void QFxText::setText(const QString &n) d->control->setTextInteractionFlags(Qt::TextBrowserInteraction); d->doc = d->control->document(); d->doc->setDocumentMargin(0); - } + } d->doc->setHtml(n); } @@ -377,6 +377,77 @@ void QFxText::setWrap(bool w) } /*! + \qmlproperty enumeration Text::textFormat + + The way the text property should be displayed. + + Supported text formats are \c AutoText, \c PlainText and \c RichText. + + The default is AutoText. If the text format is AutoText the text element + will automatically determine whether the text should be treated as + rich text. This determination is made using Qt::mightBeRichText(). + + \table + \row + \o + \qml +VerticalLayout { + TextEdit { + font.size: 24 + text: "Hello World!" + } + TextEdit { + font.size: 24 + textFormat: "RichText" + text: "Hello World!" + } + TextEdit { + font.size: 24 + textFormat: "PlainText" + text: "Hello World!" + } +} + \endqml + \o \image declarative-textformat.png + \endtable +*/ + +QFxText::TextFormat QFxText::textFormat() const +{ + Q_D(const QFxText); + return d->format; +} + +void QFxText::setTextFormat(TextFormat format) +{ + Q_D(QFxText); + if (format == d->format) + return; + bool wasRich = d->richText; + d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text)); + + if (wasRich && !d->richText) { + //### delete control? (and vice-versa below) + d->imgDirty = true; + d->updateSize(); + update(); + } else if (!wasRich && d->richText) { + if (!d->doc) + { + d->control = new QTextControl(this); + d->control->setTextInteractionFlags(Qt::TextBrowserInteraction); + d->doc = d->control->document(); + d->doc->setDocumentMargin(0); + } + d->doc->setHtml(d->text); + d->imgDirty = true; + d->updateSize(); + update(); + } + d->format = format; +} + +/*! \qmlproperty Qt::TextElideMode Text::elide Set this property to elide parts of the text fit to the Text item's width. diff --git a/src/declarative/fx/qfxtext.h b/src/declarative/fx/qfxtext.h index ee38a94..bd91f0e 100644 --- a/src/declarative/fx/qfxtext.h +++ b/src/declarative/fx/qfxtext.h @@ -58,6 +58,7 @@ class Q_DECLARATIVE_EXPORT QFxText : public QFxItem Q_ENUMS(HAlignment) Q_ENUMS(VAlignment) Q_ENUMS(TextStyle) + Q_ENUMS(TextFormat) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QmlFont *font READ font CONSTANT) @@ -67,6 +68,7 @@ class Q_DECLARATIVE_EXPORT QFxText : public QFxItem Q_PROPERTY(HAlignment hAlign READ hAlign WRITE setHAlign) Q_PROPERTY(VAlignment vAlign READ vAlign WRITE setVAlign) Q_PROPERTY(bool wrap READ wrap WRITE setWrap) + Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat) Q_PROPERTY(Qt::TextElideMode elide READ elideMode WRITE setElideMode) Q_PROPERTY(QString activeLink READ activeLink) Q_PROPERTY(bool smooth READ smoothTransform WRITE setSmoothTransform) @@ -85,6 +87,9 @@ public: Outline, Raised, Sunken }; + enum TextFormat { AutoText, + PlainText, + RichText }; QString text() const; void setText(const QString &); @@ -109,6 +114,9 @@ public: bool wrap() const; void setWrap(bool w); + TextFormat textFormat() const; + void setTextFormat(TextFormat format); + Qt::TextElideMode elideMode() const; void setElideMode(Qt::TextElideMode); diff --git a/src/declarative/fx/qfxtext_p.h b/src/declarative/fx/qfxtext_p.h index c58705c..670b685 100644 --- a/src/declarative/fx/qfxtext_p.h +++ b/src/declarative/fx/qfxtext_p.h @@ -75,7 +75,8 @@ public: QFxTextPrivate() : _font(0), color((QRgb)0), style(QFxText::Normal), imgDirty(true), hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), elideMode(Qt::ElideNone), - dirty(false), wrap(false), smooth(false), richText(false), singleline(false), control(0), doc(0) + dirty(false), wrap(false), smooth(false), richText(false), singleline(false), control(0), doc(0), + format(QFxText::AutoText) { } @@ -132,6 +133,7 @@ public: QTextDocument *doc; QTextLayout layout; QSize cachedLayoutSize; + QFxText::TextFormat format; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 3778e9a..7162bdf 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -179,7 +179,7 @@ void QFxTextEdit::setText(const QString &text) Supported text formats are \c AutoText, \c PlainText and \c RichText. The default is AutoText. If the text format is AutoText the text edit - edit will automatically determine whether the text should be treated as + will automatically determine whether the text should be treated as rich text. This determination is made using Qt::mightBeRichText(). \table -- cgit v0.12 From a2c1be26c495efac6da1668c24675afa7fc1142b Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 7 Jul 2009 09:51:05 +1000 Subject: Mark QMetaObjectBuilder and friends as internal. --- src/corelib/kernel/qmetaobjectbuilder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index d4891ff..8775c5c 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -46,6 +46,7 @@ QT_BEGIN_NAMESPACE /*! \class QMetaObjectBuilder + \internal \brief The QMetaObjectBuilder class supports building QMetaObject objects at runtime. */ @@ -1725,6 +1726,7 @@ void QMetaObjectBuilder::deserialize /*! \class QMetaMethodBuilder + \internal \brief The QMetaMethodBuilder class enables modifications to a method definition on a meta object builder. */ @@ -1921,6 +1923,7 @@ void QMetaMethodBuilder::setAttributes(int value) /*! \class QMetaPropertyBuilder + \internal \brief The QMetaPropertyBuilder class enables modifications to a property definition on a meta object builder. */ @@ -2340,6 +2343,7 @@ void QMetaPropertyBuilder::setDynamic(bool value) /*! \class QMetaEnumBuilder + \internal \brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder. */ -- cgit v0.12 From e8ed337af7e38603fcd5e5d764c8c89b5b33d74f Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 7 Jul 2009 10:42:17 +1000 Subject: Doc --- doc/src/declarative/extending.qdoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc index 138ccb2..0f9148a 100644 --- a/doc/src/declarative/extending.qdoc +++ b/doc/src/declarative/extending.qdoc @@ -359,15 +359,16 @@ object will only be returned if it has previously been created. \l {Extending QML - Attached Properties Example} shows the complete code used to implement the rsvp attached property. +\section1 Signal support + \section1 Property Binding -\section1 Signal support +\section1 Property Value Sources \section1 Extension Objects \section1 Parser Status -\section1 Property Value Sources */ -- cgit v0.12 From f0062920559dd44f5f463ea4c3fa2657fceb81fb Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 7 Jul 2009 13:28:56 +1000 Subject: Improve QmlComponent API Having to use QUrl::fromLocalFile() is crummy. Add appropriate overloads the QmlComponent, and resolve relative paths against a "base url" set on the QmlEngine. --- examples/declarative/extending/adding/main.cpp | 2 +- examples/declarative/extending/attached/main.cpp | 2 +- examples/declarative/extending/coercion/main.cpp | 2 +- examples/declarative/extending/default/main.cpp | 2 +- examples/declarative/extending/grouped/main.cpp | 2 +- examples/declarative/extending/properties/main.cpp | 2 +- src/declarative/qml/qmlcomponent.cpp | 28 ++++++++++++++++---- src/declarative/qml/qmlcomponent.h | 5 ++-- src/declarative/qml/qmlengine.cpp | 30 ++++++++++++++++++++++ src/declarative/qml/qmlengine.h | 3 +++ src/declarative/qml/qmlengine_p.h | 2 ++ 11 files changed, 67 insertions(+), 13 deletions(-) diff --git a/examples/declarative/extending/adding/main.cpp b/examples/declarative/extending/adding/main.cpp index 3d78ded..7e5cbef 100644 --- a/examples/declarative/extending/adding/main.cpp +++ b/examples/declarative/extending/adding/main.cpp @@ -9,7 +9,7 @@ int main(int argc, char ** argv) QCoreApplication app(argc, argv); QmlEngine engine; - QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + QmlComponent component(&engine, ":example.qml"); Person *person = qobject_cast(component.create()); if (person) { qWarning() << "The person's name is" << person->name(); diff --git a/examples/declarative/extending/attached/main.cpp b/examples/declarative/extending/attached/main.cpp index 1f10cd0..8b05b9d 100644 --- a/examples/declarative/extending/attached/main.cpp +++ b/examples/declarative/extending/attached/main.cpp @@ -10,7 +10,7 @@ int main(int argc, char ** argv) QCoreApplication app(argc, argv); QmlEngine engine; - QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + QmlComponent component(&engine, ":example.qml"); BirthdayParty *party = qobject_cast(component.create()); if (party && party->celebrant()) { diff --git a/examples/declarative/extending/coercion/main.cpp b/examples/declarative/extending/coercion/main.cpp index 7439ba9..75846fa 100644 --- a/examples/declarative/extending/coercion/main.cpp +++ b/examples/declarative/extending/coercion/main.cpp @@ -10,7 +10,7 @@ int main(int argc, char ** argv) QCoreApplication app(argc, argv); QmlEngine engine; - QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + QmlComponent component(&engine, ":example.qml"); BirthdayParty *party = qobject_cast(component.create()); if (party && party->celebrant()) { diff --git a/examples/declarative/extending/default/main.cpp b/examples/declarative/extending/default/main.cpp index 7439ba9..75846fa 100644 --- a/examples/declarative/extending/default/main.cpp +++ b/examples/declarative/extending/default/main.cpp @@ -10,7 +10,7 @@ int main(int argc, char ** argv) QCoreApplication app(argc, argv); QmlEngine engine; - QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + QmlComponent component(&engine, ":example.qml"); BirthdayParty *party = qobject_cast(component.create()); if (party && party->celebrant()) { diff --git a/examples/declarative/extending/grouped/main.cpp b/examples/declarative/extending/grouped/main.cpp index 0c9bb97..490e596 100644 --- a/examples/declarative/extending/grouped/main.cpp +++ b/examples/declarative/extending/grouped/main.cpp @@ -10,7 +10,7 @@ int main(int argc, char ** argv) QCoreApplication app(argc, argv); QmlEngine engine; - QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + QmlComponent component(&engine, ":example.qml"); BirthdayParty *party = qobject_cast(component.create()); if (party && party->celebrant()) { diff --git a/examples/declarative/extending/properties/main.cpp b/examples/declarative/extending/properties/main.cpp index 7b80914..d487fbe 100644 --- a/examples/declarative/extending/properties/main.cpp +++ b/examples/declarative/extending/properties/main.cpp @@ -10,7 +10,7 @@ int main(int argc, char ** argv) QCoreApplication app(argc, argv); QmlEngine engine; - QmlComponent component(&engine, QUrl::fromLocalFile(":example.qml")); + QmlComponent component(&engine, ":example.qml"); BirthdayParty *party = qobject_cast(component.create()); if (party && party->celebrant()) { diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index d6b38c9..3474487 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -270,10 +270,25 @@ QmlComponent::QmlComponent(QmlEngine *engine, const QUrl &url, QObject *parent) } /*! + Create a QmlComponent from the given \a url and give it the specified + \a parent and \a engine. + + \sa loadUrl() +*/ +QmlComponent::QmlComponent(QmlEngine *engine, const QString &url, + QObject *parent) +: QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + loadUrl(QUrl(url)); +} + +/*! Create a QmlComponent from the given QML \a data and give it the - specified \a parent and \a engine. If \a url is provided, it is used to set - the component name, and to provide a base path for items resolved - by this component. + specified \a parent and \a engine. \a url is used to provide a base path + for items resolved by this component, and may be an empty url if the + component contains no items to resolve. \sa setData() */ @@ -339,10 +354,13 @@ void QmlComponent::loadUrl(const QUrl &url) d->clear(); - d->url = url; + if (url.isRelative()) + d->url = d->engine->baseUrl().resolved(url); + else + d->url = url; QmlCompositeTypeData *data = - d->engine->d_func()->typeManager.get(url); + d->engine->d_func()->typeManager.get(d->url); if (data->status == QmlCompositeTypeData::Waiting) { diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h index b29c123..5e6dce9 100644 --- a/src/declarative/qml/qmlcomponent.h +++ b/src/declarative/qml/qmlcomponent.h @@ -67,9 +67,10 @@ class Q_DECLARATIVE_EXPORT QmlComponent : public QObject public: QmlComponent(QObject *parent = 0); QmlComponent(QmlEngine *, QObject *parent=0); + QmlComponent(QmlEngine *, const QString &url, QObject *parent = 0); QmlComponent(QmlEngine *, const QUrl &url, QObject *parent = 0); QmlComponent(QmlEngine *, const QByteArray &data, - const QUrl &baseUrl=QUrl(), QObject *parent=0); + const QUrl &baseUrl, QObject *parent=0); virtual ~QmlComponent(); Q_ENUMS(Status) @@ -92,7 +93,7 @@ public: virtual void completeCreate(); void loadUrl(const QUrl &url); - void setData(const QByteArray &, const QUrl &baseUrl = QUrl()); + void setData(const QByteArray &, const QUrl &baseUrl); Q_SIGNALS: void statusChanged(QmlComponent::Status); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 1342dec..d88d11f 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -638,6 +638,36 @@ QNetworkAccessManager *QmlEngine::networkAccessManager() const } /*! + Return the base URL for this engine. The base URL is only used to resolve + components when a relative URL is passed to the QmlComponent constructor. + + If a base URL has not been explicitly set, this method returns the + application's current working directory. + + \sa setBaseUrl() +*/ +QUrl QmlEngine::baseUrl() const +{ + Q_D(const QmlEngine); + if (d->baseUrl.isEmpty()) { + return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator()); + } else { + return d->baseUrl; + } +} + +/*! + Set the base URL for this engine to \a url. + + \sa baseUrl() +*/ +void QmlEngine::setBaseUrl(const QUrl &url) +{ + Q_D(QmlEngine); + d->baseUrl = url; +} + +/*! Returns the QmlContext for the \a object, or 0 if no context has been set. When the QmlEngine instantiates a QObject, the context is set automatically. diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h index c4259ce..9e0ac87 100644 --- a/src/declarative/qml/qmlengine.h +++ b/src/declarative/qml/qmlengine.h @@ -85,6 +85,9 @@ public: void setNetworkAccessManager(QNetworkAccessManager *); QNetworkAccessManager *networkAccessManager() const; + QUrl baseUrl() const; + void setBaseUrl(const QUrl &); + static QmlContext *contextForObject(const QObject *); static void setContextForObject(QObject *, QmlContext *); diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 25f6edf..9171fbb 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -129,6 +129,8 @@ public: QScriptEngine scriptEngine; + QUrl baseUrl; + template struct SimpleList { SimpleList() -- cgit v0.12 From 131541866b374b90e04af75ec1382154c78b69b9 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 7 Jul 2009 14:45:23 +1000 Subject: Doc --- src/declarative/debugger/qpacketprotocol.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp index 7be23b7..d109836 100644 --- a/src/declarative/debugger/qpacketprotocol.cpp +++ b/src/declarative/debugger/qpacketprotocol.cpp @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE /*! \class QPacketProtocol + \internal \brief The QPacketProtocol class encapsulates communicating discrete packets across fragmented IO channels, such as TCP sockets. @@ -354,7 +355,7 @@ QIODevice * QPacketProtocol::device() /*! \class QPacket - \inpublicgroup QtBaseModule + \internal \brief The QPacket class encapsulates an unfragmentable packet of data to be transmitted by QPacketProtocol. @@ -476,7 +477,7 @@ void QPacket::clear() /*! \class QPacketAutoSend - \inpublicgroup QtBaseModule + \internal \internal */ -- cgit v0.12 From bb11493327c3c5f351261edb64813a8ed0fc8bd6 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 8 Jul 2009 10:10:52 +1000 Subject: Support custom string convertors for animations. --- src/declarative/util/qmlanimation.cpp | 29 +++++++++++++++++------------ src/declarative/util/qmlanimation_p.h | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index c0d6481..5dfaa7f 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -1436,11 +1436,11 @@ void QmlParallelAnimation::transition(QmlStateActions &actions, QML_DEFINE_TYPE(QmlParallelAnimation,ParallelAnimation) //convert a variant from string type to another animatable type -//### should use any registered string convertor -void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, QVariant::Type type) +void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, int type) { if (variant.type() != QVariant::String) { - variant.convert(type); + if ((uint)type < QVariant::UserType) + variant.convert((QVariant::Type)type); return; } @@ -1474,7 +1474,12 @@ void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, QVariant::Ty break; } default: - variant.convert(type); + if ((uint)type >= QVariant::UserType) { + QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(type); + if (converter) + variant.setValue(converter(variant.toString())); + } else + variant.convert((QVariant::Type)type); break; } } @@ -1722,7 +1727,7 @@ void QmlPropertyAnimationPrivate::valueChanged(qreal r) if (!fromSourced) { if (!fromIsDefined) { from = property.read(); - convertVariant(from, (QVariant::Type)(interpolatorType ? interpolatorType : property.propertyType())); + convertVariant(from, interpolatorType ? interpolatorType : property.propertyType()); //### check for invalid variant if using property type } fromSourced = true; @@ -1751,9 +1756,9 @@ void QmlPropertyAnimation::prepare(QmlMetaProperty &p) d->property = d->userProperty; int propType = d->property.propertyType(); - d->convertVariant(d->to, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : propType)); + d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : propType); if (d->fromIsDefined) - d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : propType)); + d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : propType); if (!d->interpolatorType) { //### check for invalid variants @@ -1795,7 +1800,7 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (action.fromValue.isNull()) { action.fromValue = action.property.read(); if (interpolatorType) - QmlPropertyAnimationPrivate::convertVariant(action.fromValue, (QVariant::Type)interpolatorType); + QmlPropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType); } if (!interpolatorType) { int propType = action.property.propertyType(); @@ -1856,8 +1861,8 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (d->toIsDefined) myAction.toValue = d->to; - d->convertVariant(myAction.fromValue, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); - d->convertVariant(myAction.toValue, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); + d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); modified << action.property; @@ -1875,10 +1880,10 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, continue; if (d->fromIsDefined) { - d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); myAction.fromValue = d->from; } - d->convertVariant(d->to, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); myAction.toValue = d->to; data->actions << myAction; } diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index 00759e1..87d480f 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -346,7 +346,7 @@ public: QmlTimeLineValueProxy value; static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress); - static void convertVariant(QVariant &variant, QVariant::Type type); + static void convertVariant(QVariant &variant, int type); }; QT_END_NAMESPACE -- cgit v0.12 From 46688b1e8b953f9e3a12d42b9aa73a8eba904f5b Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 8 Jul 2009 11:12:20 +1000 Subject: Fix custom string convertors for animations. --- src/declarative/util/qmlanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 5dfaa7f..ff070c1 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -1477,7 +1477,7 @@ void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, int type) if ((uint)type >= QVariant::UserType) { QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(type); if (converter) - variant.setValue(converter(variant.toString())); + variant = converter(variant.toString()); } else variant.convert((QVariant::Type)type); break; -- cgit v0.12