From 28b3eb37f7647450ccbac1365a06ffc6ba6a8584 Mon Sep 17 00:00:00 2001 From: Ian Walters Date: Fri, 1 May 2009 12:57:49 +1000 Subject: Review of chapters 1 and 2 of tutorial. --- doc/src/images/declarative-reuse-1.png | Bin 0 -> 3489 bytes doc/src/images/declarative-reuse-2.png | Bin 0 -> 3700 bytes doc/src/images/declarative-reuse-3.png | Bin 0 -> 8829 bytes doc/src/images/declarative-reuse-bluerect.png | Bin 0 -> 1474 bytes doc/src/images/declarative-reuse-focus.png | Bin 0 -> 8026 bytes doc/src/tutorials/declarative.qdoc | 276 ++++++++++++--------- .../1_Drawing_and_Animation/4a/RemoveButton.qml | 117 +++++++++ .../tutorials/contacts/2_Reuse/1b/BlueRect.qml | 33 +++ .../tutorials/contacts/2_Reuse/1b/ContactField.qml | 29 --- .../tutorials/contacts/2_Reuse/2/RemoveButton.qml | 4 + 10 files changed, 312 insertions(+), 147 deletions(-) create mode 100644 doc/src/images/declarative-reuse-1.png create mode 100644 doc/src/images/declarative-reuse-2.png create mode 100644 doc/src/images/declarative-reuse-3.png create mode 100644 doc/src/images/declarative-reuse-bluerect.png create mode 100644 doc/src/images/declarative-reuse-focus.png create mode 100644 examples/declarative/tutorials/contacts/1_Drawing_and_Animation/4a/RemoveButton.qml create mode 100644 examples/declarative/tutorials/contacts/2_Reuse/1b/BlueRect.qml delete mode 100644 examples/declarative/tutorials/contacts/2_Reuse/1b/ContactField.qml diff --git a/doc/src/images/declarative-reuse-1.png b/doc/src/images/declarative-reuse-1.png new file mode 100644 index 0000000..c704457 Binary files /dev/null and b/doc/src/images/declarative-reuse-1.png differ diff --git a/doc/src/images/declarative-reuse-2.png b/doc/src/images/declarative-reuse-2.png new file mode 100644 index 0000000..0b6006b Binary files /dev/null and b/doc/src/images/declarative-reuse-2.png differ diff --git a/doc/src/images/declarative-reuse-3.png b/doc/src/images/declarative-reuse-3.png new file mode 100644 index 0000000..695a725 Binary files /dev/null and b/doc/src/images/declarative-reuse-3.png differ diff --git a/doc/src/images/declarative-reuse-bluerect.png b/doc/src/images/declarative-reuse-bluerect.png new file mode 100644 index 0000000..97dbb5f Binary files /dev/null and b/doc/src/images/declarative-reuse-bluerect.png differ diff --git a/doc/src/images/declarative-reuse-focus.png b/doc/src/images/declarative-reuse-focus.png new file mode 100644 index 0000000..f91d374 Binary files /dev/null and b/doc/src/images/declarative-reuse-focus.png differ diff --git a/doc/src/tutorials/declarative.qdoc b/doc/src/tutorials/declarative.qdoc index 3724b10..61c9fdf 100644 --- a/doc/src/tutorials/declarative.qdoc +++ b/doc/src/tutorials/declarative.qdoc @@ -97,10 +97,7 @@ \tableofcontents The first part of this tutorial covers basic drawing of elements on the - screen and causing them to animate. The file 1_Drawing_and_Animation.qml - loads and displays each of the five stages of this tutorial in a single - window. For now you don't need to worry about the contents of - 1_Drawing_and_Animation.qml. + screen and causing them to animate. \section1 Drawing @@ -115,7 +112,9 @@ Because Declarative UI is declarative, you don't pass instructions on what to paint in a sequential manner as you may be used to. Instead elements and how they appear on the screen are declared in much the - same was as elements on a web page are declared. + same was as elements on a web page are declared. This is done using + the Qt Markup Language which we will refer to by the abbreviation QML + for the remainder of the tutorial. We will start by drawing a simple red rectangle with rounded corners. @@ -123,14 +122,11 @@ \snippet declarative/tutorials/contacts/1_Drawing_and_Animation/1/RemoveButton.qml 0 - This is the simplest of QML components. It describes a rectangle with + This is one of the simplest of QML components. It describes a rectangle with some simple properties. In QML all components start with a capital - letter, and their properties with lower case letters. Properties - can either be declared as XML attributes or as children of the - component element. + letter, and their properties with lower case letters. - The rectangle component is one of the more simple QML components. Apart - from the properties all QML components share, it has the properties + Apart from the properties all QML components share, the \l{qml-rect}{Rect} component has the properties \list \o color - The background color of the rectangle @@ -140,13 +136,9 @@ \o radius - The corner radius used to draw rounded rectangles. \endlist - \omit - For more information on the Rect element, see: TODO - \endomit - - There are also a number of properties all QML components share. To see - a full description of the base QML item, see {QFxItem}. The rectangle - drawn in the above code uses the properties; + There are also a number of properties all QML components shares, described + in the \l{qml-item}{Item} element reference documentation. The rectangle drawn in the + above code uses the properties; \list \o id - An identifier of the component @@ -154,61 +146,61 @@ \o height - the height of the component when drawn \endlist - All items have properties to handle their position on the screen, size, - clipping, rotation, scale and layout in regards to other elements. In - the current example width and height refer to how large to draw the - rectangle. The identifier allows other components to refer to the - identified component. - - Another important property of a component is its children. All components - have a list of children. When drawing, first any components earlier - siblings are drawn, then the component, then any of the components children. + Currently we have described a rectangle with a width and height of 30 pixels, filled in with + the color red and with rounded corners using a radius of 5. \section1 Layout - The next step of the tutorial adds an image over the rectangle. + The next step of the tutorial adds an image over the rectangle. We + will do this by adding an \l{qml-image}{Image} component as a child of the + \l{qml-rect}{Rect} component. All QML components have a list of children which + are drawn in order after the parent component has been drawn. + By having the \l{qml-image}{Image} + component as a child of the \l{qml-rect}{Rect} component we ensure it is drawn + over the \l{qml-rect}{Rect} component. Children also are affected by the opacity + of the parent component and calculate their position in within the bounds of + the parent component. \image declarative-removebutton-close.png \snippet declarative/tutorials/contacts/1_Drawing_and_Animation/2/RemoveButton.qml 0 The trashIcon image is added as a child of the Rectangle. In this case - the tag isn't used because the default property of the - Rect component is its children. Some elements don't often have children - and use some other default component, when this is the case its possible + the children property isn't explicitly used because the default property + of the \l{qml-rect}{Rect} component is its children. Some elements often don't have children + and use some other default component. When this is the case its possible to explicitly list the sub component as a child as follows: \snippet declarative/tutorials/contacts/1_Drawing_and_Animation/2a/RemoveButton.qml 0 - The Image element allows loading an image file for display. The source + The \l{qml-image}{Image} element allows loading an image file for display. The source specified is a URL, and in this case refers to a portable network graphics file in a relative directory to where the QML file was loaded from. Also new in this code is the use of anchors. In QML components can either have their position and size specified explicitly using x, y, width and height, or they can instead specify the size and position in relation - to elements either parent or sibling elements. The Image component uses + to either parent or sibling elements. The \l{qml-image}{Image} component uses a combination of both styles. It has a fixed size, but specifies its position to align to the right of its parent and for its vertical center - to align with the vertical center of its parent. The braces "{}" are - used to indicate that the value is not a static value, but instead a - binding to an expression. In this case it binds to the parent - element, which is a special identifier that always refers to the - parent component of a component. The removeButton identifier can - be used interchangeably with parent in this case, however it must - always be a parent or sibling. Because of this its most common to - use the parent identifier as it makes later refactoring of code easier. + to align with the vertical center of its parent. Setting a property + by the identifier of a separate property binds them. This means + that if while running the example the position of the \l{qml-rect}{Rect} component's + vertical center changed, so to would the vertical center of + the \l{qml-image}{Image} component. - Anchors are most useful when the size of items might change based on - the component state or contents. + The parent value is a special identifier that always refers to the + parent component of a component. - \omit - See TODO for full list of anchor properties. - \endomit + Anchors are most useful when the size of items might change based on + the component state or contents. However they are limited in that they + must always refer to a parent or sibling component. See + \l{anchor-layout}{Anchor-based Layout} for more information on using + anchors in QML. At this point the initial state of the RemoveButton is complete. A small - rounded rectangle with a trash icon. The component also needs a - description of its open state: + rounded rectangle with a trash icon. Next we will design the open + state for the button. \image declarative-removebutton-open.png @@ -217,32 +209,31 @@ \snippet declarative/tutorials/contacts/1_Drawing_and_Animation/3/RemoveButton.qml 0 - The rectangle with is now wider by 200 pixels. Also the trashIcon has - been replaced with the confirm state children. Normally we wouldn't + The rectangle width is now wider by 200 pixels. Also the trashIcon has + been replaced. Normally we wouldn't remove the trashIcon when developing an alternate state of the RemoveButton, however since this is a tutorial its been done so that its easier to understand the alternate state we are aiming for and how it relates to transitioning between states. - We also introduce the Text element, which is used to display read only - text. \omit see {Text} for more information on the text element \endomit - Because we want text to fill the space between the icons, rather than - a fixed with the left and right anchors are specified instead. This + We also introduce the \l{qml-text}{Text} element. + Left and Right anchors are specified in terms of the neighboring icons + because we want text to fill the space between the icons. This means as the parent removeButton gets wider, so will the text component. It also means that if we animate a width change on the removeButton, - any bindings, that is the values specified by a braced expression such as - "{parent.left}" will be evaluated and animated as well. + any bindings, that is the values specified by an expression such as + \c{parent.left} will be evaluated and animated as well. \section1 Defining States When designing a component with multiple states, it should be developed - with the initial state and the changes that would be made specified - as an additional state. Its not possible to add new children to an - element when changing state, only changing the properties of existing - children. This means that all possible child components should be included + in the initial state and the changes that would be made specified + as an additional state. Its not normally possible to add new children + to an element when changing state + This means that all possible child components should be included in the initial state, and those that should not be visible in the initial state should have their opacity set to zero. Thus - for the RemoveButton we specify the starting size of the removeButton + for the RemoveButton we specify the starting size of the RemoveButton and hide any items that should not initially be visible. The code snippet below shows what the start of the duel state specification @@ -305,9 +296,9 @@ all the children of the earlier sibling, should they overlap. When a component has a signal, such as clicked, the action for the signal - can be specified using on, as is done above. In this + can be specified using \c{onSignalName}, as is done above. In this case when the clicked signal is emitted by the MouseRegion component, - a function called toggle() is called. It might also have been written + a function called \c{toggle()} is called. It might also have been written \code onClicked: { removeButton.state='opened' } @@ -317,14 +308,21 @@ mouse regions to use the same functionality, and also makes it easier to specify complex behavior in response to a signal. - The toggle() function is a new function specified as part of the remove + An alternative would be to explicitly state the connection: + + \snippet declarative/tutorials/contacts/1_Drawing_and_Animation/4a/RemoveButton.qml mouse region + + This will connect to the \c{clicked()} signal of the trashMouseRegion component + and execute the associated script. + + The \c{toggle()} function is a new function specified as part of the remove button element. \snippet declarative/tutorials/contacts/1_Drawing_and_Animation/4/RemoveButton.qml script Any QML component can have a set of resources specified. One of those resources is any Script that might be needed. See the - {QtScript Module}{QtScript Module} for more information on how to write + \l{qtscript}{QtScript Module} for more information on how to write script code in Qt. It is possible to refer to identified QML components @@ -333,7 +331,7 @@ \section1 Animation - Currently the RemoveButton is function, but snaps between our two states. + Currently the RemoveButton is functional, but snaps between our two states. Fortunately making the transition between states smooth is very simple. We only need one more bit of code at the end of our removeButton component. @@ -368,6 +366,8 @@ editing a field of our contact. This ContactField in turn is intended to be used in a contact editing control. + \image declarative-reuse-3.png + \section1 Loading QML Components Reusing the RemoveButton itself is very simple. When parsing a QML file @@ -386,50 +386,88 @@ \o The run directory + "/qml" \o the directory of the QML code file \o the directory of the QML code file + "/qml" - \endlist. + \endlist All the properties of the button are accessible and can be overridden from defaults. The loaded component can also refer to elements further up in the tree, so that code within - RemoveButton.qml could refer to the contactField component. However only - properties of the top level element in RemoveButton.qml are visible to - the contact field. In order to allow contact field to modify how wide - the remove button will be when opened we need to add a property to the - remove button. + RemoveButton.qml could refer to the contactField component. + Only properties of the top level element in RemoveButton.qml are visible to + the contact field. + + There are also two other ways to reuse components in QML. A component + can be reused from within the same QML file using Component and ComponentInstance + elements. The next code snippet produces three red rounded rectangles + within a large blue rectangle. + + \image declarative-reuse-bluerect.png + + \snippet declarative/tutorials/contacts/2_Reuse/1b/BlueRect.qml all + + This can be useful when the component is not complex enough to justify its + own file. The third way to reuse components allows for delaying loading + of the QML until some later event. Each \l{qml-item}{Item} includes + a special child, qmlItem, which has its definition provided by the + contents of the qml property of its parent. + + \snippet declarative/tutorials/contacts/2_Reuse/1a/ContactField.qml load + + This last method is useful if the contents of a item need to change at + run time or if the initial complexity of the loaded QML needs to be + reduced in order to improve the time it takes to start the application. In + chapter three this method is used to improve performance of + scrolling through very large numbers of items. + + Because of its simplicity, the first method is the recommended in most + cases and will be the focus of the remainder of this chapter. \section1 Properties and Signals + The next task is to be able to control aspects of the RemoveButton from + the components that use it. In particular controlling how far it + expands and how it reacts when the user clicks on the confirm icon + of the remove button. When reusing a component in a separate QML file + only the attributes of the root element are visible. To allow controlling + attributes of child elements within an imported component we need to define + some properties and signals for the RemoveButton. + \snippet declarative/tutorials/contacts/2_Reuse/2/RemoveButton.qml define properties and signals - These properties and signals are accessed from the contact field the same - way standard system components are accessed. + The children of the remove button can use these properties and signals. The + opened state can now bind the expanded width to the expandedWidth property. + + \snippet declarative/tutorials/contacts/2_Reuse/2/RemoveButton.qml use width + + Also when the confirm icon is clicked, as well as toggling the state it will + emit the confirmed signal of the RemoveButton component. + + \snippet declarative/tutorials/contacts/2_Reuse/2/RemoveButton.qml use signal - \snippet declarative/tutorials/contacts/2_Reuse/2/RemoveButton.qml use properties and signals + These properties and signals can also be accessed from the contact field the same + way standard system component properties and signals are accessed. + + \snippet declarative/tutorials/contacts/2_Reuse/2/ContactField.qml use properties and signals Now when the remove button is expanded, it will expand to the width of the contact field. Also when the user confirms the remove action, the - text section of the contact field will be cleared. When creating a - component that does have children out of its own - bounds its important to consider whether the item should be clipped, - which is done above with \c{clip: true}. + text section of the contact field will be cleared. \section1 States Its also possible to access the state of included components. The FieldText component we will use in this tutorial is also been written specifically - for our contacts application, as was the RemoveButton component. In + for our contacts application. In this case we want it to expand when editing. One way to do this would be to anchor the field text component to the center of its parent and then let its own width change push the remove button away, however that would make it difficult to have the remove button also push the field - text to the left when the remove button expands. - - So instead we will anchor the right edge of the field text to - the left edge of the remove button and use a state change in the - contact field itself to move the remove button and the field icon out of + text to the left when the remove button expands. Instead we will anchor + the right edge of the field text to the left edge of the remove button + and use a state change in the contact field itself to move the + remove button and the field icon out of view. - \snippet declarative/tutorials/contacts/2_Reuse/3/RemoveButton.qml all + \snippet declarative/tutorials/contacts/2_Reuse/3/ContactField.qml all Apart from accessing the fieldText.state, the above code also uses the when attribute of its own editingText state. This is an alternative to using @@ -438,63 +476,65 @@ that state. In the FieldText element a similar approach is used to fade out the label of the FieldText when the user enters some text of their own. - \snippet declarative/tutorials/contacts/3_Reuse/2/FieldText.qml behavior + \snippet declarative/tutorials/contacts/2_Reuse/3/FieldText.qml behavior - fieldText is the enclosing component and textEdit is a TextEdit element + \c{fieldText} is the enclosing component and \c{textEdit} is a TextEdit element provided by Qt. In the QML code above, the opacity of the textLabel is - only 1 if there is text for the textEdit is empty. This is a form of + only 1 if the text for the textEdit is empty. This is a form of short cut to using states for an element, useful if only one property is changing as it is for the textLabel. To animate a property change is similar to animating a state change. Using the Behavior element we can specify how the property changes if it does change state, allowing for a smooth transition. - The fieldText element also handles changes to the text using the - onValueChanged attribute when specifying properties. - - \snippet declarative/tutorials/contacts/2_Reuse/3/FieldText.qml value change - - Because the user needs to be able to edit text in the text edit, it - shouldn't be simply bound to the text property of the FieldText component. - However if a component using the FieldText component sets the text - property of the FieldText component it should in turn set the text - of the text edit. - \section1 Key and Mouse Focus - Unlike in Qt setting focus to true on a component does not always mean + Setting focus to true on a component does not always mean that the component has focus. This is due to the declarative nature of QML, and can be affected by multiple components both indicating focus to be true. At the time of writing this tutorial both key and mouse focus handling are still being improved. Hence we will only lightly cover the topic. - Normally in QML this is handled by FocusRealm components. A focus realm - is a sort of cut off point for determining focus. If a FocusRealm does - not have focus then any children of it won't be able to get focus even - if they do set focus to true. If your component has multiple child - components that could gain focus ensure that they are guarded by FocusRealm - component, and add code to handle which focus realms have focus - at that level. The alternative and approach done at this stage in - the tutorial is to only have one component set focus to true at a time. + For an item to have key focus in QML it is required that: + + \list + \o If there is a FocusRealm ancestor of the component that it has focus as well. + \o That it is the most recent component within the focus realms descendent's + to receive focus + \endlist + + The read-only property activeFocus can be used to determine whether a + component will receive key input. Any un-handled keys will be passed to + the components parent, which in turn will pass keys it doesn't handle up to its + own ancestors. + + Some components such as ListView components are also FocusRealm components, as they + handle focus among the child list items. + + At this stage of the tutorial it is sufficient to use the setting of 'focus' + as we only have a list of line edits and only one should be active at any given time. Currently if multiple contact fields were put into our contact editor, any of the FieldText components could be clicked and opened, and any of the RemoveButton components could be clicked and opened, all - at the same time. We would like this behavior to be some what modal - instead, encouraging the user to either accept or cancel the current - action before moving onto a new action. + at the same time. This leads to situations where the users actions + are ambiguous + + \image declarative-reuse-focus.png - In the tutorial we do this with a property of our top level component - to handle whether we are in this state or not. + To counteract this we will add a property of the root element to indicate + when an element has 'grabbed' mouse interaction, preventing other + clickable elements from reacting. \snippet declarative/tutorials/contacts/2_Reuse/4/Contact.qml grab property - And in the code where we want to check or avoid allowing mouse interaction. + The code that we want to disable then simply needs to check this property before + acting. \snippet declarative/tutorials/contacts/2_Reuse/4/RemoveButton.qml grab - Handling Key and Mouse focus in QML is quite likely to change before + \note Handling Key and Mouse focus in QML is quite likely to change before the Qt 4.6 release. */ @@ -618,13 +658,13 @@ Its important then to try and minimize the complexity of the delegate. This can be done by delaying the loading of the component. By using the qml property - of the Item component, we can delay building the Contact.qml item until the user + of the \l{qml-item}{Item} component, we can delay building the Contact.qml item until the user attempts to open the list. \snippet declarative/tutorials/contacts/3_Collections/3/ContactView.qml setting qml Each item has a qml property that represents the filename for the contents of - a special qmlItem child of the Item. By setting the qml property of the Details + a special qmlItem child of the \l{qml-item}{Item}. By setting the qml property of the Details component on clicking the mouse region, the more complex component isn't loaded until needed. The down side about this though is the properties of Contact cannot be set until the item is loaded. This requires using the Bind diff --git a/examples/declarative/tutorials/contacts/1_Drawing_and_Animation/4a/RemoveButton.qml b/examples/declarative/tutorials/contacts/1_Drawing_and_Animation/4a/RemoveButton.qml new file mode 100644 index 0000000..ce8459d --- /dev/null +++ b/examples/declarative/tutorials/contacts/1_Drawing_and_Animation/4a/RemoveButton.qml @@ -0,0 +1,117 @@ +Rect { + id: removeButton + width: 30 + height: 30 + color: "red" + radius: 5 +//! [script] + resources: [ + Script { + function toggle() { + if (removeButton.state == 'opened') { + removeButton.state = ''; + } else { + removeButton.state = 'opened'; + } + } + + } + ] +//! [script] +//! [mouse region] + Image { + id: trashIcon + width: 22 + height: 22 + anchors.right: parent.right + anchors.rightMargin: 4 + anchors.verticalCenter: parent.verticalCenter + source: "../../shared/pics/trash.png" + opacity: 1 + MouseRegion { + id: trashMouseRegion + anchors.fill: parent + } + Connection { + sender: trashMouseRegion + signal: clicked() + script: { + toggle() + } + } + } +//! [mouse region] + Image { + id: cancelIcon + width: 22 + height: 22 + anchors.right: parent.right + anchors.rightMargin: 4 + anchors.verticalCenter: parent.verticalCenter + source: "../../shared/pics/cancel.png" + opacity: 0 + MouseRegion { + anchors.fill: parent + onClicked: { toggle() } + } + } + Image { + id: confirmIcon + width: 22 + height: 22 + anchors.left: parent.left + anchors.leftMargin: 4 + anchors.verticalCenter: parent.verticalCenter + source: "../../shared/pics/ok.png" + opacity: 0 + MouseRegion { + anchors.fill: parent + onClicked: { toggle() } + } + } + Text { + id: text + anchors.verticalCenter: parent.verticalCenter + anchors.left: confirmIcon.right + anchors.leftMargin: 4 + anchors.right: cancelIcon.left + anchors.rightMargin: 4 + font.bold: true + color: "white" + hAlign: AlignHCenter + text: "Remove" + opacity: 0 + } +//! [states] + states: [ + State { + name: "opened" + SetProperty { + target: removeButton + property: "width" + value: 230 + } + SetProperty { + target: text + property: "opacity" + value: 1 + } + SetProperty { + target: confirmIcon + property: "opacity" + value: 1 + } + SetProperty { + target: cancelIcon + property: "opacity" + value: 1 + } + SetProperty { + target: trashIcon + property: "opacity" + value: 0 + } + } + ] +//! [states] +} diff --git a/examples/declarative/tutorials/contacts/2_Reuse/1b/BlueRect.qml b/examples/declarative/tutorials/contacts/2_Reuse/1b/BlueRect.qml new file mode 100644 index 0000000..92893f6 --- /dev/null +++ b/examples/declarative/tutorials/contacts/2_Reuse/1b/BlueRect.qml @@ -0,0 +1,33 @@ +//! [all] +Rect { + width: 100 + height: 100 + color: "blue" + resources: [ + Component { + id: redRectangle + Rect { + width: 30 + height: 30 + color: "red" + radius: 5 + } + } + ] + ComponentInstance { + component: redRectangle + anchors.right: parent.right + anchors.top: parent.top + } + ComponentInstance { + component: redRectangle + anchors.left: parent.left + anchors.top: parent.top + } + ComponentInstance { + component: redRectangle + anchors.left: parent.left + anchors.bottom: parent.bottom + } +} +//! [all] diff --git a/examples/declarative/tutorials/contacts/2_Reuse/1b/ContactField.qml b/examples/declarative/tutorials/contacts/2_Reuse/1b/ContactField.qml deleted file mode 100644 index 1366548..0000000 --- a/examples/declarative/tutorials/contacts/2_Reuse/1b/ContactField.qml +++ /dev/null @@ -1,29 +0,0 @@ -import "lib" -Item { - id: contactField - clip: true - width: 230 - height: 30 - RemoveButton { - id: removeButton - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - } - Text { - id: fieldText - width: contactField.width-80 - anchors.right: removeButton.left - anchors.rightMargin: 10 - anchors.verticalCenter: parent.verticalCenter - font.bold: true - color: "black" - text: 123123 - } - Image { - source: "../../shared/pics/phone.png" - anchors.right: fieldText.left - anchors.rightMargin: 10 - anchors.verticalCenter: parent.verticalCenter - } -} diff --git a/examples/declarative/tutorials/contacts/2_Reuse/2/RemoveButton.qml b/examples/declarative/tutorials/contacts/2_Reuse/2/RemoveButton.qml index 45b1899..dc49d8e 100644 --- a/examples/declarative/tutorials/contacts/2_Reuse/2/RemoveButton.qml +++ b/examples/declarative/tutorials/contacts/2_Reuse/2/RemoveButton.qml @@ -62,10 +62,12 @@ Rect { anchors.verticalCenter: parent.verticalCenter source: "../../shared/pics/ok.png" opacity: 0 +//! [use signal] MouseRegion { anchors.fill: parent onClicked: { toggle(); removeButton.confirmed.emit() } } +//! [use signal] } Text { id: text @@ -83,11 +85,13 @@ Rect { states: [ State { name: "opened" +//! [use width] SetProperty { target: removeButton property: "width" value: removeButton.expandedWidth } +//! [use width] SetProperty { target: text property: "opacity" -- cgit v0.12 From 15765bc59d2569803d5b1b200e26919e27d00bcd Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 4 May 2009 15:07:56 +0200 Subject: Added (failing) testcase for QmlDomValueValueSource. --- tests/auto/declarative/qmldom/tst_qmldom.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/auto/declarative/qmldom/tst_qmldom.cpp b/tests/auto/declarative/qmldom/tst_qmldom.cpp index 390e79a..91fe7a6 100644 --- a/tests/auto/declarative/qmldom/tst_qmldom.cpp +++ b/tests/auto/declarative/qmldom/tst_qmldom.cpp @@ -16,6 +16,8 @@ private slots: void loadProperties(); void loadChildObject(); + void testValueSource(); + private: QmlEngine engine; }; @@ -85,6 +87,23 @@ void tst_qmldom::loadChildObject() QVERIFY(childItem.objectType() == "Item"); } +void tst_qmldom::testValueSource() +{ + QByteArray qml = "Rect { height: Follow { spring: 1.4; damping: .15; source: Math.min(Math.max(-130, value*2.2 - 130), 133); }}"; + + QmlEngine freshEngine; + QmlDomDocument document; + QVERIFY(document.load(&freshEngine, qml)); + + QmlDomObject rootItem = document.rootObject(); + QVERIFY(rootItem.isValid()); + QmlDomProperty heightProperty = rootItem.properties().at(0); + QVERIFY(heightProperty.propertyName() == "height"); + QVERIFY(heightProperty.value().isValueSource()); + const QmlDomValueValueSource valueSource = heightProperty.value().toValueSource(); + QVERIFY(valueSource.object().isValid()); +} + QTEST_MAIN(tst_qmldom) #include "tst_qmldom.moc" -- cgit v0.12 From 51a0ebdea3942e23cd7396b57d7c452442d1371d Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 4 May 2009 15:33:11 +0200 Subject: Fixed QmlDomValueValueSource::object() to actually return the newly created object. --- src/declarative/qml/qmldom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index e1c4c28..5380740 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -949,7 +949,7 @@ QmlDomObject QmlDomValueValueSource::object() const rv.d->object = d->value->object; rv.d->object->addref(); } - return QmlDomObject(); + return rv; } /*! -- cgit v0.12 From 74c8e4c15fce7dce9d279b6a8086aaf679500fab Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 4 May 2009 15:42:32 +0200 Subject: Extended the test for QmlDomValueValueSource. --- tests/auto/declarative/qmldom/tst_qmldom.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/auto/declarative/qmldom/tst_qmldom.cpp b/tests/auto/declarative/qmldom/tst_qmldom.cpp index 91fe7a6..36d37f6 100644 --- a/tests/auto/declarative/qmldom/tst_qmldom.cpp +++ b/tests/auto/declarative/qmldom/tst_qmldom.cpp @@ -100,8 +100,22 @@ void tst_qmldom::testValueSource() QmlDomProperty heightProperty = rootItem.properties().at(0); QVERIFY(heightProperty.propertyName() == "height"); QVERIFY(heightProperty.value().isValueSource()); + const QmlDomValueValueSource valueSource = heightProperty.value().toValueSource(); - QVERIFY(valueSource.object().isValid()); + QmlDomObject valueSourceObject = valueSource.object(); + QVERIFY(valueSourceObject.isValid()); + + QVERIFY(valueSourceObject.objectType() == "Follow"); + + const QmlDomValue springValue = valueSourceObject.property("spring").value(); + QVERIFY(!springValue.isInvalid()); + QVERIFY(springValue.isLiteral()); + QVERIFY(springValue.toLiteral().literal() == "1.4"); + + const QmlDomValue sourceValue = valueSourceObject.property("source").value(); + QVERIFY(!sourceValue.isInvalid()); + QVERIFY(sourceValue.isBinding()); + QVERIFY(sourceValue.toBinding().binding() == "Math.min(Math.max(-130, value*2.2 - 130), 133)"); } QTEST_MAIN(tst_qmldom) -- cgit v0.12 From fab8fa152901cb84132f11b52f950c0dbb6d7a23 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Mon, 4 May 2009 15:54:14 +0200 Subject: Store the location for the `default' token. --- src/declarative/qml/parser/javascript.g | 6 ++++-- src/declarative/qml/parser/javascriptast_p.h | 8 +++++++- src/declarative/qml/parser/javascriptparser.cpp | 6 ++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/declarative/qml/parser/javascript.g b/src/declarative/qml/parser/javascript.g index 0da7571..5482392 100644 --- a/src/declarative/qml/parser/javascript.g +++ b/src/declarative/qml/parser/javascript.g @@ -688,7 +688,8 @@ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType T_IDENTIFIER ; case $rule_number: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), sym(3).sval, sym(4).sval); node->isDefaultMember = true; - node->propertyToken = loc(1); + node->defaultToken = loc(1); + node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); sym(1).Node = node; @@ -714,7 +715,8 @@ case $rule_number: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), sym(3).sval, sym(4).sval, sym(6).Expression); node->isDefaultMember = true; - node->propertyToken = loc(1); + node->defaultToken = loc(1); + node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); node->colonToken = loc(5); diff --git a/src/declarative/qml/parser/javascriptast_p.h b/src/declarative/qml/parser/javascriptast_p.h index 3a22fff..ad317e8 100644 --- a/src/declarative/qml/parser/javascriptast_p.h +++ b/src/declarative/qml/parser/javascriptast_p.h @@ -2336,7 +2336,12 @@ public: { kind = K; } virtual SourceLocation firstSourceLocation() const - { return propertyToken; } + { + if (defaultToken.isValid()) + return defaultToken; + + return propertyToken; + } virtual SourceLocation lastSourceLocation() const { @@ -2359,6 +2364,7 @@ public: JavaScriptNameIdImpl *name; ExpressionNode *expression; bool isDefaultMember; + SourceLocation defaultToken; SourceLocation propertyToken; SourceLocation typeToken; SourceLocation identifierToken; diff --git a/src/declarative/qml/parser/javascriptparser.cpp b/src/declarative/qml/parser/javascriptparser.cpp index b241297..185a824 100644 --- a/src/declarative/qml/parser/javascriptparser.cpp +++ b/src/declarative/qml/parser/javascriptparser.cpp @@ -298,7 +298,8 @@ case 30: { case 31: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), sym(3).sval, sym(4).sval); node->isDefaultMember = true; - node->propertyToken = loc(1); + node->defaultToken = loc(1); + node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); sym(1).Node = node; @@ -318,7 +319,8 @@ case 33: { AST::UiPublicMember *node = makeAstNode (driver->nodePool(), sym(3).sval, sym(4).sval, sym(6).Expression); node->isDefaultMember = true; - node->propertyToken = loc(1); + node->defaultToken = loc(1); + node->propertyToken = loc(2); node->typeToken = loc(3); node->identifierToken = loc(4); node->colonToken = loc(5); -- cgit v0.12 From 0e75846b831bbeb4794cc4e3d00cd3096726d35e Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 5 May 2009 10:43:23 +1000 Subject: Join some lines in examples. --- examples/declarative/listview/highlight.qml | 46 +++------- examples/declarative/listview/listview.qml | 63 +++++-------- examples/declarative/listview/recipes.qml | 134 +++++++--------------------- 3 files changed, 66 insertions(+), 177 deletions(-) diff --git a/examples/declarative/listview/highlight.qml b/examples/declarative/listview/highlight.qml index cbadb72..9a672d9 100644 --- a/examples/declarative/listview/highlight.qml +++ b/examples/declarative/listview/highlight.qml @@ -1,7 +1,6 @@ Rect { - width: 400 - height: 300 - color: "white" + width: 400; height: 300; color: "white" + // MyPets model is defined in dummydata/MyPetsModel.qml // The viewer automatically loads files in dummydata/* to assist // development without a real data source. @@ -12,18 +11,11 @@ Rect { id: PetDelegate Item { id: Wrapper - width: 200 - height: 50 + width: 200; height: 50 VerticalLayout { - Text { - text: 'Name: ' + name - } - Text { - text: 'Type: ' + type - } - Text { - text: 'Age: ' + age - } + Text { text: 'Name: ' + name } + Text { text: 'Type: ' + type } + Text { text: 'Age: ' + age } } // Use the ListView.isCurrentItem attached property to // indent the item if it is the current item. @@ -32,17 +24,14 @@ Rect { name: "Current" when: Wrapper.ListView.isCurrentItem SetProperty { - target: Wrapper - property: "x" - value: 10 + target: Wrapper; property: "x"; value: 10 } } ] transitions: [ Transition { NumericAnimation { - properties: "x" - duration: 200 + properties: "x"; duration: 200 } } ] @@ -54,24 +43,15 @@ Rect { Component { id: PetHighlight Rect { - width: 200 - height: 50 - color: "#FFFF88" - y: Follow { - source: List1.current.y - spring: 3 - damping: 0.1 - } + width: 200; height: 50; color: "#FFFF88" + y: Follow { source: List1.current.y; spring: 3; damping: 0.1 } } } ListView { id: List1 - width: 200 - height: parent.height - model: MyPetsModel - delegate: PetDelegate - highlight: PetHighlight - autoHighlight: false + width: 200; height: parent.height + model: MyPetsModel; delegate: PetDelegate + highlight: PetHighlight; autoHighlight: false focus: true } } diff --git a/examples/declarative/listview/listview.qml b/examples/declarative/listview/listview.qml index b71ed4e..a222378 100644 --- a/examples/declarative/listview/listview.qml +++ b/examples/declarative/listview/listview.qml @@ -1,7 +1,6 @@ Rect { - width: 600 - height: 300 - color: "white" + width: 600; height: 300; color: "white" + // MyPets model is defined in dummydata/MyPetsModel.qml // The viewer automatically loads files in dummydata/* to assist // development without a real data source. @@ -12,29 +11,22 @@ Rect { id: PetDelegate Item { id: Wrapper - width: 200 - height: 50 + width: 200; height: 50 VerticalLayout { - Text { - text: 'Name: ' + name - } - Text { - text: 'Type: ' + type - } - Text { - text: 'Age: ' + age - } + Text { text: 'Name: ' + name } + Text { text: 'Type: ' + type } + Text { text: 'Age: ' + age } } } } + // Define a highlight component. Just one of these will be instantiated // by each ListView and placed behind the current item. Component { id: PetHighlight - Rect { - color: "#FFFF88" - } + Rect { color: "#FFFF88" } } + // Show the model in three lists, with different currentItemPositioning. // currentItemPositioning determines how the list behaves when the // current item changes. Note that the second and third ListView @@ -54,35 +46,23 @@ Rect { // the mouse, the current index of List1 will be changed. ListView { id: List1 - width: 200 - height: parent.height - model: MyPetsModel - delegate: PetDelegate - highlight: PetHighlight - currentIndex: List3.currentIndex + width: 200; height: parent.height + model: MyPetsModel; delegate: PetDelegate + highlight: PetHighlight; currentIndex: List3.currentIndex focus: true } ListView { id: List2 - x: 200 - width: 200 - height: parent.height - model: MyPetsModel - delegate: PetDelegate - highlight: PetHighlight - currentItemPositioning: "Snap" - snapPosition: 125 + x: 200; width: 200; height: parent.height + model: MyPetsModel; delegate: PetDelegate; highlight: PetHighlight + currentItemPositioning: "Snap"; snapPosition: 125 currentIndex: List1.currentIndex } ListView { id: List3 - x: 400 - width: 200 - height: parent.height - model: MyPetsModel - delegate: PetDelegate - currentItemPositioning: "SnapAuto" - snapPosition: 125 + x: 400; width: 200; height: parent.height + model: MyPetsModel; delegate: PetDelegate + currentItemPositioning: "SnapAuto"; snapPosition: 125 currentIndex: List1.currentIndex children: [ // Position a static highlight rather than a normal highlight so that @@ -92,11 +72,8 @@ Rect { // Note that we specify the 'children' property. This is because // the default property of a ListView is 'delegate'. Rect { - y: 125 - width: 200 - height: 50 - color: "#FFFF88" - z: -1 + y: 125; width: 200; height: 50 + color: "#FFFF88"; z: -1 } ] } diff --git a/examples/declarative/listview/recipes.qml b/examples/declarative/listview/recipes.qml index db8604e..db9ef61 100644 --- a/examples/declarative/listview/recipes.qml +++ b/examples/declarative/listview/recipes.qml @@ -2,9 +2,7 @@ import "content" // This example illustrates expanding a list item to show a more detailed view Rect { id: page - width: 400 - height: 240 - color: "black" + width: 400; height: 240; color: "black" resources: [ // Delegate for the recipes. This delegate has two modes: // 1. the list mode (default), which just shows the picture and title of the recipe. @@ -26,13 +24,8 @@ Rect { // A simple rounded rectangle for the background Rect { id: background - x: 1 - y: 2 - width: parent.width-2 - height: parent.height-4 - color: "#FEFFEE" - pen.color: "#FFBE4F" - radius: 5 + x: 1; y: 2; width: parent.width-2; height: parent.height-4 + color: "#FEFFEE"; pen.color: "#FFBE4F"; radius: 5 } // This mouse region covers the entire delegate. // When clicked it changes mode to 'Details'. If we are already @@ -47,145 +40,86 @@ Rect { // mode have their opacity set to wrapper.detailsOpacity. HorizontalLayout { id: topLayout - x: 10 - y: 10 + x: 10; y: 10; height: recipePic.height; width: parent.width spacing: 10 - height: recipePic.height - width: parent.width Image { id: recipePic - source: picture - width: 48 - height: 48 + source: picture; width: 48; height: 48 } VerticalLayout { - height: recipePic.height + height: recipePic.height; width: background.width-recipePic.width-20 spacing: 5 - width: background.width-recipePic.width-20 - Text { - id: name - text: title - font.bold: true - font.size: 16 - } + Text { id: name; text: title; font.bold: true; font.size: 16 } Text { + text: "Ingredients"; font.size: 12; font.bold: true opacity: wrapper.detailsOpacity - text: "Ingredients" - font.size: 12 - font.bold: true } Text { + text: ingredients; wrap: true; width: parent.width opacity: wrapper.detailsOpacity - text: ingredients - wrap: true - width: parent.width } } } Item { id: details - x: 10 - width: parent.width-20 - anchors.top: topLayout.bottom - anchors.topMargin: 10 - anchors.bottom: parent.bottom - anchors.bottomMargin: 10 + x: 10; width: parent.width-20 + anchors.top: topLayout.bottom; anchors.topMargin: 10 + anchors.bottom: parent.bottom; anchors.bottomMargin: 10 opacity: wrapper.detailsOpacity Text { id: methodTitle - text: "Method" - font.size: 12 - font.bold: true + text: "Method"; font.size: 12; font.bold: true anchors.top: parent.top } Flickable { id: flick - anchors.top: methodTitle.bottom - anchors.bottom: parent.bottom - width: parent.width - viewportHeight: methodText.height - clip: true - Text { - id: methodText - text: method - wrap: true - width: details.width - } + anchors.top: methodTitle.bottom; anchors.bottom: parent.bottom + width: parent.width; viewportHeight: methodText.height; clip: true + Text { id: methodText; text: method; wrap: true; width: details.width } } Image { - anchors.right: flick.right - anchors.top: flick.top - source: "content/pics/moreUp.png" - opacity: flick.atYBeginning ? 0 : 1 + anchors.right: flick.right; anchors.top: flick.top + source: "content/pics/moreUp.png"; opacity: flick.atYBeginning ? 0 : 1 } Image { - anchors.right: flick.right - anchors.bottom: flick.bottom - source: "content/pics/moreDown.png" - opacity: flick.atYEnd ? 0 : 1 + anchors.right: flick.right; anchors.bottom: flick.bottom + source: "content/pics/moreDown.png"; opacity: flick.atYEnd ? 0 : 1 } } // A button to close the detailed view, i.e. set the state back to default (''). MediaButton { - anchors.right: background.right - anchors.rightMargin: 5 - y: 10 - opacity: wrapper.detailsOpacity - text: "Close" - onClicked: { wrapper.state = '' } + anchors.right: background.right; anchors.rightMargin: 5 + y: 10; opacity: wrapper.detailsOpacity + text: "Close"; onClicked: { wrapper.state = '' } } // Make the default height equal the hight of the picture, plus margin. height: 68 states: [ State { name: "Details" - SetProperty { - target: background - property: "color" - value: "white" - } + SetProperty { target: background; property: "color"; value: "white" } // Make the picture bigger - SetProperties { - target: recipePic - width: 128 - height: 128 - } + SetProperties { target: recipePic; width: 128; height: 128 } // Make details visible - SetProperties { - target: wrapper - detailsOpacity: 1 - x: 0 - } + SetProperties { target: wrapper; detailsOpacity: 1; x: 0 } // Make the detailed view fill the entire list area - SetProperty { - target: wrapper - property: "height" - value: List.height - } + SetProperty { target: wrapper; property: "height"; value: List.height } // Move the list so that this item is at the top. SetProperty { target: wrapper.ListView.view - property: "yPosition" - value: wrapper.y + property: "yPosition"; value: wrapper.y } // Disallow flicking while we're in detailed view - SetProperty { - target: wrapper.ListView.view - property: "locked" - value: 1 - } + SetProperty { target: wrapper.ListView.view; property: "locked"; value: 1 } } ] transitions: [ Transition { // Make the state changes smooth ParallelAnimation { - ColorAnimation { - duration: 500 - } + ColorAnimation { duration: 500 } NumericAnimation { - duration: 300 - properties: "detailsOpacity,x,yPosition,height,width" + duration: 300; properties: "detailsOpacity,x,yPosition,height,width" } } } @@ -196,9 +130,7 @@ Rect { // The actual list ListView { id: List - model: Recipies - anchors.fill: parent - clip: true - delegate: recipeDelegate + model: Recipies; delegate: recipeDelegate + anchors.fill: parent; clip: true } } -- cgit v0.12 From c376633cba5c79ed1d842d9c6b7b68e31c646959 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 5 May 2009 11:01:56 +1000 Subject: Add not-yet-working Content example. --- doc/src/snippets/declarative/GroupBox.qml | 11 +++++++++++ doc/src/snippets/declarative/content.qml | 6 ++++++ 2 files changed, 17 insertions(+) create mode 100644 doc/src/snippets/declarative/GroupBox.qml create mode 100644 doc/src/snippets/declarative/content.qml diff --git a/doc/src/snippets/declarative/GroupBox.qml b/doc/src/snippets/declarative/GroupBox.qml new file mode 100644 index 0000000..a8ff5be --- /dev/null +++ b/doc/src/snippets/declarative/GroupBox.qml @@ -0,0 +1,11 @@ +ContentWrapper { + id: Container; width: parent.width + Rect { + width: parent.width; color: "white"; pen.width: 2; pen.color: "#adaeb0"; radius: 10 + clip: false; height: contents.height + VerticalLayout { + id: layout; width: parent.width + Content {} + } + } +} diff --git a/doc/src/snippets/declarative/content.qml b/doc/src/snippets/declarative/content.qml new file mode 100644 index 0000000..be04c6e --- /dev/null +++ b/doc/src/snippets/declarative/content.qml @@ -0,0 +1,6 @@ +GroupBox { + content: [ + Text { text: "First Item" } + Text { text: "Second Item" } + ] +} -- cgit v0.12 From c7a0cae7deb6e31c5b2e82c9a63ebe0a167fed09 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 11:17:15 +1000 Subject: Improve error handling consistency --- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlcompiler.cpp | 33 +++-- src/declarative/qml/qmlcompiler_p.h | 5 +- src/declarative/qml/qmlcomponent.cpp | 24 ++-- src/declarative/qml/qmlcomponent.h | 5 +- src/declarative/qml/qmlcomponent_p.h | 3 +- src/declarative/qml/qmlcompositetypemanager.cpp | 23 +-- src/declarative/qml/qmlcompositetypemanager_p.h | 4 +- src/declarative/qml/qmldom.cpp | 18 +-- src/declarative/qml/qmldom.h | 2 + src/declarative/qml/qmldom_p.h | 2 +- src/declarative/qml/qmlerror.cpp | 180 ++++++++++++++++++++++++ src/declarative/qml/qmlerror.h | 82 +++++++++++ src/declarative/qml/qmlparser.cpp | 8 +- src/declarative/qml/qmlparser_p.h | 3 + src/declarative/qml/qmlscriptparser.cpp | 104 +++++++------- src/declarative/qml/qmlscriptparser_p.h | 11 +- src/declarative/qml/qmlvme.cpp | 24 ++-- src/declarative/qml/qmlvme_p.h | 5 +- src/declarative/util/qfxview.cpp | 79 ++++++++++- src/declarative/util/qfxview.h | 3 +- tools/qmlviewer/qmlviewer.cpp | 8 ++ 22 files changed, 501 insertions(+), 131 deletions(-) create mode 100644 src/declarative/qml/qmlerror.cpp create mode 100644 src/declarative/qml/qmlerror.h diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 9067039..69a1461 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -22,7 +22,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlclassfactory.cpp \ qml/qmlparserstatus.cpp \ qml/qmlcompositetypemanager.cpp \ - qml/qmlinfo.cpp + qml/qmlinfo.cpp \ + qml/qmlerror.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -58,7 +59,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlcontext_p.h \ qml/qmlcompositetypemanager_p.h \ qml/qmllist.h \ - qml/qmldeclarativedata_p.h + qml/qmldeclarativedata_p.h \ + qml/qmlerror.h # for qtscript debugger QT += scripttools diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index c9bdfec..37d7fa1 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -147,7 +147,7 @@ int QmlCompiledData::indexForInt(int *data, int count) } QmlCompiler::QmlCompiler() -: exceptionLine(-1), output(0) +: exceptionLine(-1), exceptionColumn(-1), output(0) { } @@ -156,14 +156,19 @@ bool QmlCompiler::isError() const return exceptionLine != -1; } -qint64 QmlCompiler::errorLine() const +QList QmlCompiler::errors() const { - return exceptionLine; -} + QList rv; + + if(isError()) { + QmlError error; + error.setDescription(exceptionDescription); + error.setLine(exceptionLine); + error.setColumn(exceptionColumn); + rv << error; + } -QString QmlCompiler::errorDescription() const -{ - return exceptionDescription; + return rv; } bool QmlCompiler::isValidId(const QString &val) @@ -437,9 +442,19 @@ void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) cc->bytecode.clear(); } +#define COMPILE_EXCEPTION2(token, desc) \ + { \ + exceptionLine = token->line; \ + exceptionColumn = token->column; \ + QDebug d(&exceptionDescription); \ + d << desc; \ + return false; \ + } + #define COMPILE_EXCEPTION(desc) \ { \ exceptionLine = obj->line; \ + exceptionColumn = obj->column; \ QDebug d(&exceptionDescription); \ d << desc; \ return false; \ @@ -1215,10 +1230,10 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, //### we are restricted to a rather generic message here. If we can find a way to move // the exception into generateStoreInstruction we could potentially have better messages. // (the problem is that both compile and run exceptions can be generated, though) - COMPILE_EXCEPTION("Cannot assign value" << v->primitive << "to property" << obj->metaObject()->property(prop->index).name()); + COMPILE_EXCEPTION2(v, "Cannot assign value" << v->primitive << "to property" << obj->metaObject()->property(prop->index).name()); doassign = false; } else if (r == ReadOnly) { - COMPILE_EXCEPTION("Cannot assign value" << v->primitive << "to the read-only property" << obj->metaObject()->property(prop->index).name()); + COMPILE_EXCEPTION2(v, "Cannot assign value" << v->primitive << "to the read-only property" << obj->metaObject()->property(prop->index).name()); } else { doassign = true; } diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 9a0ce1c..cc1a9e9 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include class QStringList; @@ -115,8 +116,7 @@ public: bool compile(QmlEngine *, QmlCompositeTypeData *, QmlCompiledComponent *); bool isError() const; - qint64 errorLine() const; - QString errorDescription() const; + QList errors() const; static bool isValidId(const QString &); static bool isBinding(const QString &); @@ -176,6 +176,7 @@ private: QSet ids; qint64 exceptionLine; + qint64 exceptionColumn; QString exceptionDescription; QmlCompiledData *output; }; diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index c316f03..3b4d7b3 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -137,9 +137,7 @@ void QmlComponentPrivate::fromTypeData(QmlCompositeTypeData *data) if (!c) { Q_ASSERT(data->status == QmlCompositeTypeData::Error); - errorDescription = data->errorDescription; - qWarning().nospace() << "QmlComponent: " - << data->errorDescription.toLatin1().constData(); + errors = data->errors; } else { @@ -194,7 +192,7 @@ QmlComponent::Status QmlComponent::status() const return Loading; else if (d->engine && d->cc) return Ready; - else if (!d->errorDescription.isEmpty()) + else if (!d->errors.isEmpty()) return Error; else return Null; @@ -353,13 +351,13 @@ void QmlComponent::loadUrl(const QUrl &url) emit statusChanged(status()); } -QString QmlComponent::errorDescription() const +QList QmlComponent::errors() const { Q_D(const QmlComponent); if (isError()) - return d->errorDescription; + return d->errors; else - return QString(); + return QList(); } /*! @@ -448,7 +446,7 @@ QObject *QmlComponent::beginCreate(QmlContext *context) } if (!isReady()) { - qWarning("QmlComponent: Cannot create un-ready component"); + qWarning("QmlComponent: Component is not ready"); return 0; } @@ -466,15 +464,9 @@ QObject *QmlComponent::beginCreate(QmlContext *context) QmlVME vme; QObject *rv = vme.run(ctxt, d->cc, d->start, d->count); - if (vme.isError()) { - qWarning().nospace() -#ifdef QML_VERBOSEERRORS_ENABLED - << "QmlComponent: " -#endif - << vme.errorDescription().toLatin1().constData() << " @" - << d->url.toString().toLatin1().constData() << ":" << vme.errorLine(); - } + if (vme.isError()) + d->errors = vme.errors(); ctxt->deactivate(); diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h index 0493c1f..90f7467 100644 --- a/src/declarative/qml/qmlcomponent.h +++ b/src/declarative/qml/qmlcomponent.h @@ -46,7 +46,7 @@ #include #include #include - +#include QT_BEGIN_HEADER @@ -77,7 +77,8 @@ public: bool isReady() const; bool isError() const; bool isLoading() const; - QString errorDescription() const; + + QList errors() const; QUrl url() const; diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index bb5f7bb..0507958 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -47,6 +47,7 @@ #include #include "private/qobject_p.h" #include "private/qmlcompositetypemanager_p.h" +#include #include "qmlcomponent.h" class QmlComponent; class QmlEngine; @@ -68,7 +69,7 @@ public: void fromTypeData(QmlCompositeTypeData *data); - QString errorDescription; + QList errors; QUrl url; int start; diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index 7f2cc58..fbe40bf 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -105,10 +105,9 @@ QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) QmlCompiler compiler; if (!compiler.compile(engine, this, compiledComponent)) { status = Error; - errorDescription = compiler.errorDescription() + - QLatin1String("@") + - url + QLatin1String(":") + - QString::number(compiler.errorLine()); + errors = compiler.errors(); + for(int ii = 0; ii < errors.count(); ++ii) + errors[ii].setUrl(url); compiledComponent->release(); compiledComponent = 0; } @@ -188,7 +187,10 @@ void QmlCompositeTypeManager::replyFinished() reply->url().toString(); unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = errorDescription; + // ### FIXME + QmlError error; + error.setDescription(errorDescription); + unit->errors << error; doComplete(unit); } else { @@ -215,7 +217,10 @@ void QmlCompositeTypeManager::loadSource(QmlCompositeTypeData *unit) // ### - Fill in error errorDescription = QLatin1String("File error for URL ") + url.toString(); unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = errorDescription; + // ### FIXME + QmlError error; + error.setDescription(errorDescription); + unit->errors << error; doComplete(unit); } @@ -234,7 +239,7 @@ void QmlCompositeTypeManager::setData(QmlCompositeTypeData *unit, if (!unit->data.parse(data, url)) { unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = unit->data.errorDescription(); + unit->errors << unit->data.errors(); doComplete(unit); } else { @@ -273,7 +278,7 @@ void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit) if (u->status == QmlCompositeTypeData::Error) { unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = u->errorDescription; + unit->errors = u->errors; doComplete(unit); return; } else if (u->status == QmlCompositeTypeData::Waiting) { @@ -334,7 +339,7 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) case QmlCompositeTypeData::Invalid: case QmlCompositeTypeData::Error: unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = urlUnit->errorDescription; + unit->errors = urlUnit->errors; doComplete(unit); return; diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h index bc86fcf..e4028d5 100644 --- a/src/declarative/qml/qmlcompositetypemanager_p.h +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -45,6 +45,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -65,7 +66,8 @@ struct QmlCompositeTypeData : public QmlRefCount Waiting }; Status status; - QString errorDescription; + + QList errors; QString url; QList dependants; diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index cf0a2fb..239aa7b 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -152,11 +152,11 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) { Q_UNUSED(engine); - d->error = QString(); + d->errors.clear(); QmlScriptParser parser; if (!parser.parse(data)) { - d->error = parser.errorDescription(); + d->errors = parser.errors(); return false; } @@ -166,11 +166,13 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) QmlCompositeTypeData *td = ((QmlEnginePrivate *)QmlEnginePrivate::get(engine))->typeManager.getImmediate(data, QUrl());; if(td->status == QmlCompositeTypeData::Error) { - d->error = td->errorDescription; + d->errors = td->errors; td->release(); return false; } else if(td->status == QmlCompositeTypeData::Waiting) { - d->error = QLatin1String("QmlDomDocument supports local types only"); + QmlError error; + error.setDescription(QLatin1String("QmlDomDocument supports local types only")); + d->errors << error; td->release(); return false; } @@ -178,7 +180,7 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) compiler.compile(engine, td, &component); if (compiler.isError()) { - d->error = compiler.errorDescription(); + d->errors = compiler.errors(); td->release(); return false; } @@ -194,14 +196,14 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) /*! - Returns the last load error. The load error will be reset after a + Returns the last load errors. The load errors will be reset after a successful call to load(). \sa load() */ -QString QmlDomDocument::loadError() const +QList QmlDomDocument::errors() const { - return d->error; + return d->errors; } /*! diff --git a/src/declarative/qml/qmldom.h b/src/declarative/qml/qmldom.h index 47a89d9..74ed27c 100644 --- a/src/declarative/qml/qmldom.h +++ b/src/declarative/qml/qmldom.h @@ -44,6 +44,7 @@ #include #include +#include QT_BEGIN_HEADER @@ -71,6 +72,7 @@ public: int version() const; + QList errors() const; QString loadError() const; bool load(QmlEngine *, const QByteArray &); QByteArray save() const; diff --git a/src/declarative/qml/qmldom_p.h b/src/declarative/qml/qmldom_p.h index 8ea56bf..4c3ca44 100644 --- a/src/declarative/qml/qmldom_p.h +++ b/src/declarative/qml/qmldom_p.h @@ -57,7 +57,7 @@ public: QmlDomDocumentPrivate(const QmlDomDocumentPrivate &); ~QmlDomDocumentPrivate(); - QString error; + QList errors; QmlParser::Object *root; }; diff --git a/src/declarative/qml/qmlerror.cpp b/src/declarative/qml/qmlerror.cpp new file mode 100644 index 0000000..66c834f --- /dev/null +++ b/src/declarative/qml/qmlerror.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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$ +** +****************************************************************************/ + +#include "qmlerror.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlErrorPrivate +{ +public: + QmlErrorPrivate(); + + QUrl url; + QString description; + int line; + int column; +}; + +QmlErrorPrivate::QmlErrorPrivate() +: line(-1), column(-1) +{ +} + +QmlError::QmlError() +: d(new QmlErrorPrivate) +{ +} + +QmlError::QmlError(const QmlError &other) +: d(new QmlErrorPrivate) +{ + *this = other; +} + +QmlError &QmlError::operator=(const QmlError &other) +{ + d->url = other.d->url; + d->description = other.d->description; + d->line = other.d->line; + d->column = other.d->column; + return *this; +} + +QmlError::~QmlError() +{ + delete d; d = 0; +} + +QUrl QmlError::url() const +{ + return d->url; +} + +void QmlError::setUrl(const QUrl &url) +{ + d->url = url; +} + +QString QmlError::description() const +{ + return d->description; +} + +void QmlError::setDescription(const QString &description) +{ + d->description = description; +} + +int QmlError::line() const +{ + return d->line; +} + +void QmlError::setLine(int line) +{ + d->line = line; +} + +int QmlError::column() const +{ + return d->column; +} + +void QmlError::setColumn(int column) +{ + d->column = column; +} + +QDebug operator<<(QDebug debug, const QmlError &error) +{ + QUrl url = error.url(); + + QString output; + + output = url.toString() + QLatin1String(":") + + QString::number(error.line()); + + if(error.column() != -1) + output += QLatin1String(":") + QString::number(error.column()); + + output += QLatin1String(": ") + error.description(); + + debug << qPrintable(output) << "\n"; + + if (error.line() > 0 && error.column() > 0 && + url.scheme() == QLatin1String("file")) { + QString file = url.toLocalFile(); + QFile f(file); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QTextStream stream(data, QIODevice::ReadOnly); + const QString code = stream.readAll(); + const QStringList lines = code.split(QLatin1Char('\n')); + + if (lines.count() >= error.line()) { + const QString &line = lines.at(error.line() - 1); + debug << qPrintable(line) << "\n"; + + int column = qMax(0, error.column() - 1); + column = qMin(column, line.length()); + + QByteArray ind; + ind.reserve(column); + for (int i = 0; i < column; ++i) { + const QChar ch = line.at(i); + if (ch.isSpace()) + ind.append(ch.unicode()); + else + ind.append(' '); + } + ind.append('^'); + debug << ind.constData(); + } + } + } + return debug; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlerror.h b/src/declarative/qml/qmlerror.h new file mode 100644 index 0000000..57d2f8f --- /dev/null +++ b/src/declarative/qml/qmlerror.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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$ +** +****************************************************************************/ + +#ifndef QMLERROR_H +#define QMLERROR_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDebug; +class QmlErrorPrivate; +class Q_DECLARATIVE_EXPORT QmlError +{ +public: + QmlError(); + QmlError(const QmlError &); + QmlError &operator=(const QmlError &); + ~QmlError(); + + QUrl url() const; + void setUrl(const QUrl &); + QString description() const; + void setDescription(const QString &); + int line() const; + void setLine(int); + int column() const; + void setColumn(int); +private: + QmlErrorPrivate *d; +}; + +QDebug Q_DECLARATIVE_EXPORT operator<<(QDebug debug, const QmlError &error); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLERROR_H diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index ecb6f0b..87c8434 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; QmlParser::Object::Object() -: type(-1), metatype(0), extObject(0), defaultProperty(0), line(-1), +: type(-1), metatype(0), extObject(0), defaultProperty(0), line(-1), column(-1), dynamicPropertiesProperty(0), dynamicSignalsProperty(0) { } @@ -127,12 +127,12 @@ QmlParser::Object::DynamicSignal::DynamicSignal(const DynamicSignal &o) } QmlParser::Property::Property() -: type(0), index(-1), value(0), isDefault(true), line(-1) +: type(0), index(-1), value(0), isDefault(true), line(-1), column(-1) { } QmlParser::Property::Property(const QByteArray &n) -: type(0), index(-1), value(0), name(n), isDefault(false), line(-1) +: type(0), index(-1), value(0), name(n), isDefault(false), line(-1), column(-1) { } @@ -161,7 +161,7 @@ void QmlParser::Property::addValue(Value *v) } QmlParser::Value::Value() -: type(Unknown), object(0), line(-1) +: type(Unknown), object(0), line(-1), column(-1) { } diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index e29cdbf..17b367d6 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -103,6 +103,7 @@ namespace QmlParser QHash properties; qint64 line; + qint64 column; struct DynamicProperty { DynamicProperty(); @@ -167,6 +168,7 @@ namespace QmlParser Object *object; qint64 line; + qint64 column; }; class Property : public QmlRefCount @@ -197,6 +199,7 @@ namespace QmlParser bool isDefault; qint64 line; + qint64 column; }; } diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index 8039b5c..618eb2e 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -65,10 +65,12 @@ protected: Object *defineObjectBinding(int line, AST::UiQualifiedId *propertyName, const QString &objectType, + AST::SourceLocation typeLocation, AST::UiObjectInitializer *initializer = 0); Object *defineObjectBinding_helper(int line, AST::UiQualifiedId *propertyName, const QString &objectType, + AST::SourceLocation typeLocation, AST::UiObjectInitializer *initializer = 0); QString getPrimitive(const QByteArray &propertyName, AST::ExpressionNode *expr); void defineProperty(const QString &propertyName, int line, const QString &primitive); @@ -194,11 +196,17 @@ QString ProcessAST::asString(AST::UiQualifiedId *node) const Object *ProcessAST::defineObjectBinding_helper(int line, AST::UiQualifiedId *propertyName, const QString &objectType, + AST::SourceLocation typeLocation, AST::UiObjectInitializer *initializer) { bool isType = !objectType.isEmpty() && objectType.at(0).isUpper() && !objectType.contains(QLatin1Char('.')); + if (!isType) { - qWarning() << "bad name for a class"; // ### FIXME + QmlError error; + error.setDescription("Expected type name"); + error.setLine(typeLocation.startLine); + error.setColumn(typeLocation.startColumn); + _parser->_errors << error; return false; } @@ -235,7 +243,7 @@ Object *ProcessAST::defineObjectBinding_helper(int line, if (!_parser->scriptFile().isEmpty()) { _stateStack.pushObject(obj); - Object *scriptObject= defineObjectBinding(line, 0, QLatin1String("Script")); + Object *scriptObject= defineObjectBinding(line, 0, QLatin1String("Script"), AST::SourceLocation()); _stateStack.pushObject(scriptObject); defineProperty(QLatin1String("src"), line, _parser->scriptFile()); _stateStack.pop(); // scriptObject @@ -264,11 +272,12 @@ Object *ProcessAST::defineObjectBinding_helper(int line, Object *ProcessAST::defineObjectBinding(int line, AST::UiQualifiedId *qualifiedId, const QString &objectType, + AST::SourceLocation typeLocation, AST::UiObjectInitializer *initializer) { if (objectType == QLatin1String("Connection")) { - Object *obj = defineObjectBinding_helper(line, 0, QLatin1String("Connection")); + Object *obj = defineObjectBinding_helper(line, 0, objectType, typeLocation); _stateStack.pushObject(obj); @@ -297,7 +306,7 @@ Object *ProcessAST::defineObjectBinding(int line, return obj; } - return defineObjectBinding_helper(line, qualifiedId, objectType, initializer); + return defineObjectBinding_helper(line, qualifiedId, objectType, typeLocation, initializer); } void ProcessAST::defineProperty(const QString &propertyName, int line, const QString &primitive) @@ -372,7 +381,11 @@ bool ProcessAST::visit(AST::UiPublicMember *node) } if(!typeFound) { - qWarning() << "Unknown property type" << memberType; // ### FIXME + QmlError error; + error.setDescription("Expected property type"); + error.setLine(node->typeToken.startLine); + error.setColumn(node->typeToken.startColumn); + _parser->_errors << error; return false; } @@ -402,6 +415,7 @@ bool ProcessAST::visit(AST::UiObjectDefinition *node) defineObjectBinding(node->identifierToken.startLine, 0, node->name->asString(), + node->identifierToken, node->initializer); return false; @@ -414,6 +428,7 @@ bool ProcessAST::visit(AST::UiObjectBinding *node) defineObjectBinding(node->identifierToken.startLine, node->qualifiedId, node->name->asString(), + node->identifierToken, node->initializer); return false; @@ -476,7 +491,8 @@ bool ProcessAST::visit(AST::UiScriptBinding *node) Value *v = new Value; v->primitive = primitive; - v->line = node->colonToken.startLine; + v->line = node->statement->firstSourceLocation().startLine; + v->column = node->statement->firstSourceLocation().startColumn; prop->addValue(v); while (propertyCount--) @@ -535,7 +551,7 @@ bool ProcessAST::visit(AST::UiSourceElement *node) QmlScriptParser::QmlScriptParser() - : root(0), _errorLine(-1) +: root(0) { } @@ -556,8 +572,11 @@ bool QmlScriptParser::parse(const QByteArray &data, const QUrl &url) return true; } - _error = xmlParser.errorDescription(); - _errorLine = 0; // ### FIXME + QmlError error; + error.setUrl(url); + error.setDescription(xmlParser.errorDescription()); + _errors << error; + return false; } @@ -576,61 +595,34 @@ bool QmlScriptParser::parse(const QByteArray &data, const QUrl &url) lexer.setCode(code, /*line = */ 1); driver.setLexer(&lexer); - if (! parser.parse(&driver)) { - _error = parser.errorMessage(); - _errorLine = parser.errorLineNumber(); - - const QStringList lines = code.split(QLatin1Char('\n')); + if (! parser.parse(&driver) || !_errors.isEmpty()) { + // Extract errors from the parser foreach (const JavaScriptParser::DiagnosticMessage &m, parser.diagnosticMessages()) { if (m.isWarning()) continue; - qWarning().nospace() << qPrintable(fileName) << ":" - << m.line << ":" - << m.column << ": " - << "error: " - << qPrintable(m.message); - - const QString textLine = lines.at(m.line - 1); - - qWarning() << qPrintable(textLine); + QmlError error; + error.setUrl(url); + error.setDescription(m.message); + error.setLine(m.line); + error.setColumn(m.column); + _errors << error; - int column = qMax(0, m.column - 1); - column = qMin(column, textLine.length()); // paranoia check - - QByteArray ind; - ind.reserve(column); - - for (int i = 0; i < column; ++i) { - const QChar ch = textLine.at(i); - if (ch.isSpace()) - ind.append(ch.unicode()); - else - ind.append(' '); - } - ind.append('^'); - qWarning() << ind.constData(); } - - return false; } - ProcessAST process(this); - process(code, parser.ast()); + if (_errors.isEmpty()) { + ProcessAST process(this); + process(code, parser.ast()); - return true; -} - -QString QmlScriptParser::errorDescription() const -{ - return _error; -} + // Set the url for process errors + for(int ii = 0; ii < _errors.count(); ++ii) + _errors[ii].setUrl(url); + } -int QmlScriptParser::errorLine() const -{ - return _errorLine; + return _errors.isEmpty(); } QMap QmlScriptParser::nameSpacePaths() const @@ -648,6 +640,11 @@ Object *QmlScriptParser::tree() const return root; } +QList QmlScriptParser::errors() const +{ + return _errors; +} + void QmlScriptParser::clear() { if (root) { @@ -656,9 +653,8 @@ void QmlScriptParser::clear() } _nameSpacePaths.clear(); _typeNames.clear(); - _error.clear(); + _errors.clear(); _scriptFile.clear(); - _errorLine = 0; } int QmlScriptParser::findOrCreateTypeId(const QString &name) diff --git a/src/declarative/qml/qmlscriptparser_p.h b/src/declarative/qml/qmlscriptparser_p.h index 0d89268..4155bba 100644 --- a/src/declarative/qml/qmlscriptparser_p.h +++ b/src/declarative/qml/qmlscriptparser_p.h @@ -3,6 +3,7 @@ #include #include +#include #include QT_BEGIN_HEADER @@ -23,8 +24,6 @@ public: ~QmlScriptParser(); bool parse(const QByteArray &data, const QUrl &url = QUrl()); - QString errorDescription() const; - int errorLine() const; QMap nameSpacePaths() const; QStringList types() const; @@ -33,6 +32,8 @@ public: void clear(); + QList errors() const; + // ### private: int findOrCreateTypeId(const QString &name); void setTree(QmlParser::Object *tree); @@ -42,12 +43,12 @@ public: void addNamespacePath(const QString &path); -private: +// ### private: + QList _errors; + QMap _nameSpacePaths; QmlParser::Object *root; QStringList _typeNames; - QString _error; - int _errorLine; QString _scriptFile; }; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index e6235e4..a3bfd62 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -176,9 +176,14 @@ QmlVME::QmlVME() #define VME_EXCEPTION(desc) \ { \ - exceptionLine = instr.line; \ - QDebug d(&exceptionDescription); \ - d << desc; \ + QString str; \ + QDebug d(&str); \ + d << desc; \ + QmlError error; \ + error.setDescription(str); \ + error.setLine(instr.line); \ + error.setUrl(comp->url); \ + vmeErrors << error; \ break; \ } @@ -224,6 +229,8 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in QStack pushedProperties; QObject **savedObjects = 0; + vmeErrors.clear(); + if (start == -1) start = 0; if (count == -1) count = comp->bytecode.count(); @@ -1072,17 +1079,12 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in bool QmlVME::isError() const { - return exceptionLine != -1; -} - -qint64 QmlVME::errorLine() const -{ - return exceptionLine; + return !vmeErrors.isEmpty(); } -QString QmlVME::errorDescription() const +QList QmlVME::errors() const { - return exceptionDescription; + return vmeErrors; } void QmlVME::runStoreInstruction(QStack &stack, diff --git a/src/declarative/qml/qmlvme_p.h b/src/declarative/qml/qmlvme_p.h index 2a3be06..86cd040 100644 --- a/src/declarative/qml/qmlvme_p.h +++ b/src/declarative/qml/qmlvme_p.h @@ -44,6 +44,7 @@ #include #include +#include class QObject; QT_BEGIN_NAMESPACE @@ -60,13 +61,13 @@ public: QObject *run(QmlContext *, QmlCompiledComponent *, int start = -1, int end = -1); bool isError() const; - qint64 errorLine() const; - QString errorDescription() const; + QList errors() const; private: void runStoreInstruction(QStack &stack, QmlInstruction &, QmlCompiledData *); + QList vmeErrors; qint64 exceptionLine; QString exceptionDescription; }; diff --git a/src/declarative/util/qfxview.cpp b/src/declarative/util/qfxview.cpp index cac73a0..f71b87e 100644 --- a/src/declarative/util/qfxview.cpp +++ b/src/declarative/util/qfxview.cpp @@ -233,8 +233,6 @@ QmlContext* QFxView::rootContext() */ void QFxView::execute() { - rootContext()->activate(); - if (d->qml.isEmpty()) { d->component = new QmlComponent(&d->engine, d->source, this); } else { @@ -249,6 +247,45 @@ void QFxView::execute() } /*! + \internal +*/ +void QFxView::printErrorLine(const QmlError &error) +{ + QUrl url = error.url(); + if (error.line() > 0 && error.column() > 0 && + url.scheme() == QLatin1String("file")) { + QString file = url.toLocalFile(); + QFile f(file); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QTextStream stream(data, QIODevice::ReadOnly); + const QString code = stream.readAll(); + const QStringList lines = code.split(QLatin1Char('\n')); + + if (lines.count() >= error.line()) { + const QString &line = lines.at(error.line() - 1); + qWarning() << qPrintable(line); + + int column = qMax(0, error.column() - 1); + column = qMin(column, line.length()); + + QByteArray ind; + ind.reserve(column); + for (int i = 0; i < column; ++i) { + const QChar ch = line.at(i); + if (ch.isSpace()) + ind.append(ch.unicode()); + else + ind.append(' '); + } + ind.append('^'); + qWarning() << ind.constData(); + } + } + } +} + +/*! \internal */ void QFxView::continueExecute() @@ -260,8 +297,26 @@ void QFxView::continueExecute() return; } + if(d->component->isError()) { + QList errors = d->component->errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + + return; + } + QObject *obj = d->component->create(); - rootContext()->deactivate(); + + if(d->component->isError()) { + QList errors = d->component->errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + + return; + } + if (obj) { if (QFxItem *item = qobject_cast(obj)) { item->QSimpleCanvasItem::setParent(QSimpleCanvas::root()); @@ -330,7 +385,25 @@ QFxItem* QFxView::addItem(const QString &qml, QFxItem* parent) return 0; QmlComponent component(&d->engine, qml.toUtf8(), QUrl()); + if(d->component->isError()) { + QList errors = d->component->errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + + return 0; + } + QObject *obj = component.create(); + if(d->component->isError()) { + QList errors = d->component->errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + + return 0; + } + if (obj){ QFxItem *item = static_cast(obj); if (!parent) diff --git a/src/declarative/util/qfxview.h b/src/declarative/util/qfxview.h index d2cacf4..f575f27 100644 --- a/src/declarative/util/qfxview.h +++ b/src/declarative/util/qfxview.h @@ -57,7 +57,7 @@ QT_MODULE(Declarative) class QFxItem; class QmlEngine; class QmlContext; -class Canvas; +class QmlError; class QFxViewPrivate; class Q_DECLARATIVE_EXPORT QFxView : public QSimpleCanvas @@ -84,6 +84,7 @@ public: void dumpRoot(); + static void printErrorLine(const QmlError &); Q_SIGNALS: void sceneResized(QSize size); diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 3c52cfe..00cb7f1 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -85,6 +85,14 @@ void QmlViewer::openQml(const QString& fileName) QmlComponent comp(canvas->engine()); comp.setData(data, QUrl()); QObject *dummyData = comp.create(); + + if(comp.isError()) { + QList errors = comp.errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + } + if (dummyData) { qWarning() << "Loaded dummy data:" << dir.filePath(qml); qml.truncate(qml.length()-4); -- cgit v0.12 From f7573945387671cafaff14924905859e296b47f7 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 12:46:41 +1000 Subject: QmlError doc --- src/declarative/qml/qmlcomponent.cpp | 4 +++ src/declarative/qml/qmlerror.cpp | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 3b4d7b3..66440f5 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -351,6 +351,10 @@ void QmlComponent::loadUrl(const QUrl &url) emit statusChanged(status()); } +/*! + Return the list of errors that occured during the last compile or create + operation. An empty list is returned if isError() is not set. +*/ QList QmlComponent::errors() const { Q_D(const QmlComponent); diff --git a/src/declarative/qml/qmlerror.cpp b/src/declarative/qml/qmlerror.cpp index 66c834f..2ed3500 100644 --- a/src/declarative/qml/qmlerror.cpp +++ b/src/declarative/qml/qmlerror.cpp @@ -46,6 +46,10 @@ QT_BEGIN_NAMESPACE +/*! + \class QmlError + \brief The QmlError class encapsulates a QML error +*/ class QmlErrorPrivate { public: @@ -62,17 +66,26 @@ QmlErrorPrivate::QmlErrorPrivate() { } +/*! + Create an empty error object. +*/ QmlError::QmlError() : d(new QmlErrorPrivate) { } +/*! + Create a copy of \a other. +*/ QmlError::QmlError(const QmlError &other) : d(new QmlErrorPrivate) { *this = other; } +/*! + Assign \a other to this error object. +*/ QmlError &QmlError::operator=(const QmlError &other) { d->url = other.d->url; @@ -82,51 +95,85 @@ QmlError &QmlError::operator=(const QmlError &other) return *this; } +/*! + \internal +*/ QmlError::~QmlError() { delete d; d = 0; } +/*! + Return the url for the file that caused this error. +*/ QUrl QmlError::url() const { return d->url; } +/*! + Set the \a url for the file that caused this error. +*/ void QmlError::setUrl(const QUrl &url) { d->url = url; } +/*! + Return the error description. +*/ QString QmlError::description() const { return d->description; } +/*! + Set the error \a description. +*/ void QmlError::setDescription(const QString &description) { d->description = description; } +/*! + Return the error line number. +*/ int QmlError::line() const { return d->line; } +/*! + Set the error \a line number. +*/ void QmlError::setLine(int line) { d->line = line; } +/*! + Return the error column number. +*/ int QmlError::column() const { return d->column; } +/*! + Set the error \a column number. +*/ void QmlError::setColumn(int column) { d->column = column; } +/*! + \relates QmlError + \fn QDebug operator<<(QDebug debug, const QmlError &error) + + Output a human readable version of \a error to \a debug. +*/ + QDebug operator<<(QDebug debug, const QmlError &error) { QUrl url = error.url(); -- cgit v0.12 From caa1832f8dd6012ed3d44d7b822c500485ffb5ec Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 12:49:26 +1000 Subject: Mark DOM API as internal for now --- src/declarative/qml/qmldom.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index 3942375..08755b1 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -70,6 +70,7 @@ QmlDomDocumentPrivate::~QmlDomDocumentPrivate() /*! \class QmlDomDocument + \internal \brief The QmlDomDocument class represents the root of a QML document A QML document is a self-contained snippet of QML, usually contained in a @@ -251,6 +252,7 @@ QmlDomPropertyPrivate::~QmlDomPropertyPrivate() /*! \class QmlDomProperty + \internal \brief The QmlDomProperty class represents one property assignment in the QML DOM tree @@ -452,6 +454,7 @@ QmlDomObjectPrivate::properties(QmlParser::Property *property) const /*! \class QmlDomObject + \internal \brief The QmlDomObject class represents an object instantiation. Each object instantiated in a QML file has a corresponding QmlDomObject @@ -736,6 +739,7 @@ QmlDomBasicValuePrivate::~QmlDomBasicValuePrivate() /*! \class QmlDomValueLiteral + \internal \brief The QmlDomValueLiteral class represents a literal value. A literal value is a simple value, written inline with the QML. In the @@ -808,6 +812,7 @@ void QmlDomValueLiteral::setLiteral(const QString &value) /*! \class QmlDomValueBinding + \internal \brief The QmlDomValueBinding class represents a property binding. A property binding is an ECMAScript expression assigned to a property. In @@ -877,6 +882,7 @@ void QmlDomValueBinding::setBinding(const QString &expression) /*! \class QmlDomValueValueSource + \internal \brief The QmlDomValueValueSource class represents a value source assignment value. In QML, value sources are special value generating types that may be @@ -985,6 +991,7 @@ QmlDomValuePrivate::~QmlDomValuePrivate() /*! \class QmlDomValue + \internal \brief The QmlDomValue class represents a generic Qml value. QmlDomValue's can be assigned to QML \l {QmlDomProperty}{properties}. In @@ -1236,6 +1243,7 @@ QmlDomList QmlDomValue::toList() const /*! \class QmlDomList + \internal \brief The QmlDomList class represents a list of values assigned to a QML property. Lists of values can be assigned to properties. For example, the following @@ -1325,6 +1333,7 @@ void QmlDomList::setValues(const QList &values) /*! \class QmlDomComponent + \internal \brief The QmlDomComponent class represents sub-component within a QML document. Sub-components are QmlComponents defined within a QML document. The -- cgit v0.12 From ca737861c5b6459a3f5f33cafbbe371da5c113c4 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 5 May 2009 13:17:20 +1000 Subject: Minehunt switched to KDE smiley faces Minehunt example now meets minimum aesthetic requirements. --- examples/declarative/minehunt/minehunt.qml | 6 +++--- examples/declarative/minehunt/pics/face-sad.png | Bin 0 -> 14844 bytes examples/declarative/minehunt/pics/face-smile-big.png | Bin 0 -> 13810 bytes examples/declarative/minehunt/pics/face-smile.png | Bin 0 -> 15408 bytes examples/declarative/minehunt/pics/frown.png | Bin 1036 -> 0 bytes examples/declarative/minehunt/pics/glee.png | Bin 1082 -> 0 bytes examples/declarative/minehunt/pics/smile.png | Bin 1028 -> 0 bytes 7 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 examples/declarative/minehunt/pics/face-sad.png create mode 100644 examples/declarative/minehunt/pics/face-smile-big.png create mode 100644 examples/declarative/minehunt/pics/face-smile.png delete mode 100644 examples/declarative/minehunt/pics/frown.png delete mode 100644 examples/declarative/minehunt/pics/glee.png delete mode 100644 examples/declarative/minehunt/pics/smile.png diff --git a/examples/declarative/minehunt/minehunt.qml b/examples/declarative/minehunt/minehunt.qml index 58397b0..bf31c3d 100644 --- a/examples/declarative/minehunt/minehunt.qml +++ b/examples/declarative/minehunt/minehunt.qml @@ -148,9 +148,9 @@ Item { text: numFlags } Image { - x: 240 - y: 0 - source: if(isPlaying==true){'pics/smile.png'}else{if(hasWon==true){'pics/glee.png'}else{'pics/frown.png'}} + x: 280 + y: 10 + source: if(isPlaying==true){'pics/face-smile.png'}else{if(hasWon==true){'pics/face-smile-big.png'}else{'pics/face-sad.png'}} MouseRegion { anchors.fill: parent onClicked: { reset() } diff --git a/examples/declarative/minehunt/pics/face-sad.png b/examples/declarative/minehunt/pics/face-sad.png new file mode 100644 index 0000000..cf00aaf Binary files /dev/null and b/examples/declarative/minehunt/pics/face-sad.png differ diff --git a/examples/declarative/minehunt/pics/face-smile-big.png b/examples/declarative/minehunt/pics/face-smile-big.png new file mode 100644 index 0000000..f9c2335 Binary files /dev/null and b/examples/declarative/minehunt/pics/face-smile-big.png differ diff --git a/examples/declarative/minehunt/pics/face-smile.png b/examples/declarative/minehunt/pics/face-smile.png new file mode 100644 index 0000000..3d66d72 Binary files /dev/null and b/examples/declarative/minehunt/pics/face-smile.png differ diff --git a/examples/declarative/minehunt/pics/frown.png b/examples/declarative/minehunt/pics/frown.png deleted file mode 100644 index 52684b3..0000000 Binary files a/examples/declarative/minehunt/pics/frown.png and /dev/null differ diff --git a/examples/declarative/minehunt/pics/glee.png b/examples/declarative/minehunt/pics/glee.png deleted file mode 100644 index 59ea583..0000000 Binary files a/examples/declarative/minehunt/pics/glee.png and /dev/null differ diff --git a/examples/declarative/minehunt/pics/smile.png b/examples/declarative/minehunt/pics/smile.png deleted file mode 100644 index ccd52cd..0000000 Binary files a/examples/declarative/minehunt/pics/smile.png and /dev/null differ -- cgit v0.12 From d02cc90ec24fd30d1440e06eb443eafb221cdbe7 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 13:25:46 +1000 Subject: Fix QmlComponent::isError() after QmlComponent::create() --- src/declarative/qml/qmlcomponent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 66440f5..1e167d5 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -190,10 +190,10 @@ QmlComponent::Status QmlComponent::status() const if (d->typeData) return Loading; - else if (d->engine && d->cc) - return Ready; else if (!d->errors.isEmpty()) return Error; + else if (d->engine && d->cc) + return Ready; else return Null; } -- cgit v0.12 From 6089208e78bdcb0091c0ba0bc2fbd2a4fc0806de Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 13:48:29 +1000 Subject: Remove QML XML support --- src/declarative/qml/qml.pri | 2 - src/declarative/qml/qmlcomponent.cpp | 11 - src/declarative/qml/qmlcomponent_p.h | 1 - src/declarative/qml/qmlscriptparser.cpp | 19 -- src/declarative/qml/qmlxmlparser.cpp | 391 -------------------------- src/declarative/qml/qmlxmlparser_p.h | 89 ------ tools/qmlconv/qmlconv.cpp | 482 -------------------------------- tools/qmlconv/qmlconv.pro | 10 - 8 files changed, 1005 deletions(-) delete mode 100644 src/declarative/qml/qmlxmlparser.cpp delete mode 100644 src/declarative/qml/qmlxmlparser_p.h delete mode 100644 tools/qmlconv/qmlconv.cpp delete mode 100644 tools/qmlconv/qmlconv.pro diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 69a1461..5198264 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -8,7 +8,6 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlcontext.cpp \ qml/qmlcustomparser.cpp \ qml/qmlpropertyvaluesource.cpp \ - qml/qmlxmlparser.cpp \ qml/qmlproxymetaobject.cpp \ qml/qmlvme.cpp \ qml/qmlcompiler.cpp \ @@ -37,7 +36,6 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlcustomparser_p_p.h \ qml/qmlpropertyvaluesource.h \ qml/qmlboundsignal_p.h \ - qml/qmlxmlparser_p.h \ qml/qmlparserstatus.h \ qml/qmlproxymetaobject_p.h \ qml/qmlcompiledcomponent_p.h \ diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 1e167d5..b1beb9c 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -60,17 +60,6 @@ QT_BEGIN_NAMESPACE class QByteArray; -bool QmlComponentPrivate::isXml(const QByteArray &ba) -{ - for (int i = 0; i < ba.size(); ++i) { - char c = ba.at(i); - if (c == ' ' || c == '\n' || c == '\r' || c == '\t') - continue; - return (c == '<'); - } - return true; -} - /*! \class QmlComponent \brief The QmlComponent class encapsulates a QML component description. diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 0507958..6a5345e 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -82,7 +82,6 @@ public: QmlEngine *engine; void clear(); - static bool isXml(const QByteArray &); }; #endif // QMLCOMPONENT_P_H diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index 618eb2e..d0051ac 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -1,6 +1,5 @@ #include "qmlscriptparser_p.h" -#include "qmlxmlparser_p.h" #include "qmlparser_p.h" #include "parser/javascriptengine_p.h" @@ -562,24 +561,6 @@ QmlScriptParser::~QmlScriptParser() bool QmlScriptParser::parse(const QByteArray &data, const QUrl &url) { - if (QmlComponentPrivate::isXml(data)) { - // parse using the XML parser. - QmlXmlParser xmlParser; - if (xmlParser.parse(data, url)) { - _nameSpacePaths = xmlParser.nameSpacePaths(); - root = xmlParser.takeTree(); - _typeNames = xmlParser.types(); - return true; - } - - QmlError error; - error.setUrl(url); - error.setDescription(xmlParser.errorDescription()); - _errors << error; - - return false; - } - const QString fileName = url.toString(); QTextStream stream(data, QIODevice::ReadOnly); diff --git a/src/declarative/qml/qmlxmlparser.cpp b/src/declarative/qml/qmlxmlparser.cpp deleted file mode 100644 index 35d2c0e..0000000 --- a/src/declarative/qml/qmlxmlparser.cpp +++ /dev/null @@ -1,391 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -#include "qmlxmlparser_p.h" -#include "qmlcustomparser_p.h" -#include -#include -#include -#include "qmlparser_p.h" -#include -#include - -QT_BEGIN_NAMESPACE -using namespace QmlParser; - -struct QmlXmlParserState { - QmlXmlParserState() : object(0), property(0) {} - QmlXmlParserState(Object *o) : object(o), property(0) {} - QmlXmlParserState(Object *o, Property *p) : object(o), property(p) {} - - Object *object; - Property *property; -}; - -struct QmlXmlParserStateStack : public QStack -{ - void pushObject(Object *obj) - { - push(QmlXmlParserState(obj)); - } - - void pushProperty(const QString &name, int lineNumber) - { - const QmlXmlParserState &state = top(); - if (state.property) { - QmlXmlParserState s(state.property->getValue(), - state.property->getValue()->getProperty(name.toLatin1())); - s.property->line = lineNumber; - push(s); - } else { - QmlXmlParserState s(state.object, - state.object->getProperty(name.toLatin1())); - s.property->line = lineNumber; - push(s); - } - } -}; - -QmlXmlParser::~QmlXmlParser() -{ - if (root) - root->release(); -} - -QmlXmlParser::QmlXmlParser() -: root(0) -{ -} - -static QString flatXml(QXmlStreamReader& reader) -{ - QString result; - int depth=0; - QStringRef ns = reader.namespaceUri(); - while (depth>=0) { - switch (reader.tokenType()) { - case QXmlStreamReader::StartElement: - result += QLatin1Char('<'); - result += reader.name(); - if (reader.namespaceUri() != ns || depth==0) { - result += QLatin1String(" xmlns=\""); - result += reader.namespaceUri(); - result += QLatin1Char('"'); - } - foreach(QXmlStreamAttribute attr, reader.attributes()) { - result += QLatin1Char(' '); - result += attr.name(); - result += QLatin1String("=\""); - result += attr.value(); // XXX escape - result += QLatin1Char('"'); - } - result += QLatin1Char('>'); - ++depth; - break; - case QXmlStreamReader::EndElement: - result += QLatin1String("'); - --depth; - break; - case QXmlStreamReader::Characters: - result += reader.text(); - break; - default: - reader.raiseError(QLatin1String("Only StartElement, EndElement, and Characters permitted")); - break; - } - if (depth>=0) - reader.readNext(); - } - return result; -} - -bool QmlXmlParser::parse(const QByteArray &data, const QUrl &url) -{ -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer pt; -#endif - - QString fileDisplayName; - if (url.isEmpty()) { - fileDisplayName = QLatin1String(""); - } else if (url.scheme() == QLatin1String("file")) { - fileDisplayName = url.toLocalFile(); - } else { - fileDisplayName = url.toString(); - } - if (data.isEmpty()) { - _error = QLatin1String("No Qml was specified for parsing @") + fileDisplayName; - return false; - } - - QmlXmlParserStateStack states; - - QXmlStreamReader reader; - reader.addData(data); - - while(!reader.atEnd()) { - switch(reader.readNext()) { - case QXmlStreamReader::Invalid: - case QXmlStreamReader::NoToken: - case QXmlStreamReader::StartDocument: - case QXmlStreamReader::EndDocument: - break; - - case QXmlStreamReader::StartElement: - { - QString name = reader.name().toString(); - QString nameSpace = reader.namespaceUri().toString(); - int line = reader.lineNumber(); - bool isType = name.at(0).isUpper() && !name.contains(QLatin1Char('.')); - QString qualifiedname; - if (!nameSpace.isEmpty()) { - qualifiedname = nameSpace; - qualifiedname += QLatin1Char('/'); - } - qualifiedname += name; - QByteArray qualifiednameL1 = qualifiedname.toLatin1(); - QXmlStreamAttributes attrs = reader.attributes(); - - if (isType) { - // Class - int typeId = _typeNames.indexOf(qualifiedname); - if (typeId == -1) { - typeId = _typeNames.count(); - _typeNames.append(qualifiedname); - } - - Object *obj = new Object; - obj->type = typeId; - obj->typeName = qualifiednameL1; - obj->line = line; - - QmlCustomParser *customparser = QmlMetaType::customParser(qualifiednameL1); - if (customparser) { - bool ok; - obj->custom = customparser->compile(reader, &ok); - if (reader.tokenType() != QXmlStreamReader::EndElement) { - reader.raiseError(QLatin1String("Parser for ") + qualifiedname + QLatin1String(" did not end on end element")); - ok = false; - } - if (!ok) { - delete obj; - break; - } - } - - - if (!root) { - root = obj; - states.pushObject(obj); - } else { - const QmlXmlParserState &state = states.top(); - Value *v = new Value; - v->object = obj; - v->line = line; - if (state.property) - state.property->addValue(v); - else - state.object->getDefaultProperty()->addValue(v); - states.pushObject(obj); - } - } else { - // Property - if (!root) { - reader.raiseError(QLatin1String("Can't have a property with no object")); - break; - } - QStringList str = name.split(QLatin1Char('.')); - for (int ii = 0; ii < str.count(); ++ii) { - QString s = str.at(ii); - states.pushProperty(s, line); - } - if (!nameSpace.isEmpty()) { - // Pass non-QML as flat text property value - const QmlXmlParserState &state = states.top(); - Value *v = new Value; - v->primitive = flatXml(reader); - v->line = line; - state.property->addValue(v); - } - } - - // (even custom parsed content gets properties set) - foreach(QXmlStreamAttribute attr, attrs) { - QStringList str = attr.name().toString().split(QLatin1Char('.')); - - for (int ii = 0; ii < str.count(); ++ii) { - QString s = str.at(ii); - states.pushProperty(s, line); - } - - const QmlXmlParserState &state = states.top(); - Value *v = new Value; - v->primitive = attr.value().toString(); - v->line = reader.lineNumber(); - state.property->addValue(v); - - for (int ii = str.count() - 1; ii >= 0; --ii) - states.pop(); - } - } - - // Custom parsers and namespaced properties move - // the reader to the end element, so we handle that - // BEFORE continuing. - // - if (reader.tokenType()!=QXmlStreamReader::EndElement) - break; - // ELSE fallthrough to EndElement... - case QXmlStreamReader::EndElement: - { - QString name = reader.name().toString(); - Q_ASSERT(!name.isEmpty()); - if (name.at(0).isUpper() && !name.contains(QLatin1Char('.'))) { - // Class - states.pop(); - } else { - // Property - QStringList str = name.split(QLatin1Char('.')); - for (int ii = 0; ii < str.count(); ++ii) - states.pop(); - } - } - break; - case QXmlStreamReader::Characters: - if (!reader.isWhitespace()) { - const QmlXmlParserState &state = states.top(); - Value *v = new Value; - v->primitive = reader.text().toString(); - v->line = reader.lineNumber(); - if (state.property) - state.property->addValue(v); - else - state.object->getDefaultProperty()->addValue(v); - } - break; - - case QXmlStreamReader::Comment: - case QXmlStreamReader::DTD: - case QXmlStreamReader::EntityReference: - break; - case QXmlStreamReader::ProcessingInstruction: - if (reader.processingInstructionTarget() == QLatin1String("qtfx")) { - QString str = reader.processingInstructionData().toString(); - QString token, data; - int idx = str.indexOf(QLatin1Char(':')); - if (-1 != idx) { - token = str.left(idx); - data = str.mid(idx + 1); - } else { - token = str; - } - token = token.trimmed(); - data = data.trimmed(); - - // - - if (token == QLatin1String("namespacepath")) { - int eq=data.indexOf(QLatin1Char('=')); - if (eq>=0) { - _nameSpacePaths.insertMulti(data.left(eq),data.mid(eq+1)); - } - } else { - str = str.trimmed(); - qWarning().nospace() << "Unknown processing instruction " << str.toLatin1().constData() << " @" << fileDisplayName.toLatin1().constData() << ":" << reader.lineNumber(); - } - } - break; - } - } - - if (reader.hasError()) { - if (root) { - root->release(); - root = 0; - } - _error = reader.errorString() + QLatin1String(" @") + fileDisplayName + - QLatin1String(":") + QString::number(reader.lineNumber()); - } - - return root != 0; -} - -QMap QmlXmlParser::nameSpacePaths() const -{ - return _nameSpacePaths; -} - -QStringList QmlXmlParser::types() const -{ - return _typeNames; -} - -QmlParser::Object *QmlXmlParser::tree() const -{ - return root; -} - -QmlParser::Object *QmlXmlParser::takeTree() -{ - QmlParser::Object *r = root; - root = 0; - return r; -} - -QString QmlXmlParser::errorDescription() const -{ - return _error; -} - -void QmlXmlParser::clear() -{ - if (root) { - root->release(); - root = 0; - } - _nameSpacePaths.clear(); - _typeNames.clear(); - _error.clear(); -} - -QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlxmlparser_p.h b/src/declarative/qml/qmlxmlparser_p.h deleted file mode 100644 index 9b45e28..0000000 --- a/src/declarative/qml/qmlxmlparser_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -#ifndef QMLXMLPARSER_P_H -#define QMLXMLPARSER_P_H - -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -namespace QmlParser { - class Object; -} - -class QByteArray; -class QmlXmlParser -{ -public: - QmlXmlParser(); - ~QmlXmlParser(); - - bool parse(const QByteArray &data, const QUrl &url=QUrl()); - QString errorDescription() const; - - QMap nameSpacePaths() const; - QStringList types() const; - - QmlParser::Object *tree() const; - QmlParser::Object *takeTree(); - - void clear(); - -private: - QMap _nameSpacePaths; - QmlParser::Object *root; - QStringList _typeNames; - QString _error; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QMLXMLPARSER_P_H - diff --git a/tools/qmlconv/qmlconv.cpp b/tools/qmlconv/qmlconv.cpp deleted file mode 100644 index 6e89530..0000000 --- a/tools/qmlconv/qmlconv.cpp +++ /dev/null @@ -1,482 +0,0 @@ -#include -#include -#include -#include -#include -#include - - -static bool optionInPlace = false; - -class Reader -{ - QString outString; - QTextStream out; - QXmlStreamReader xml; - int depth; - bool supressIndent; - - QStringList knownListProperties; - inline QString depthString() {if (supressIndent) { supressIndent = false; return QString(); } - return QString(depth*4, QLatin1Char(' '));} - -public: - Reader(QIODevice *in) - :xml(in) { - - knownListProperties << "states" << "transitions" << "children" << "resources" - << "transform" << "notes"; - depth = 0; - supressIndent = false; - - out.setString(&outString); - - loop(); - - out.flush(); - - if (! optionInPlace) { - QTextStream print(stdout); - print << outString; - } - } - - QString output() const - { - return outString; - } - - void comment() - { - if (xml.isComment()) { - out << depthString() << "// " - << xml.text().toString().trimmed().replace(QRegExp("\n\\s*"),"\n"+depthString()+"// ") - << endl; - } - } - - void emptyLoop() { - while (!xml.atEnd()) { - xml.readNext(); - comment(); - if (xml.tokenType() == QXmlStreamReader::EndElement) - return; - } - } - - void loop() - { - while (!xml.atEnd()) { - xml.readNext(); - if (xml.tokenType() == QXmlStreamReader::EndElement) - return; - else if (xml.tokenType() == QXmlStreamReader::StartElement) - startElement(); - else if (xml.tokenType() == QXmlStreamReader::ProcessingInstruction) { - if (xml.processingInstructionTarget() == QLatin1String("qtfx")) { - QString data = xml.processingInstructionData().toString().trimmed(); - if (data.startsWith(QLatin1String("namespacepath:="))) { - outString.prepend( QLatin1String("import \"") + data.mid(data.indexOf(QLatin1Char('='))+1) + QLatin1String("\"\n")); - } - } - } - comment(); - } - } - - void startElement() { - - if (!propertyChangeSet.isEmpty() - && xml.name() != "SetProperties" - && xml.name() != "SetProperty") { - clearPropertyChangeSet(); - } - - if (false && xml.name() == "properties") - startDeclareProperties(); - else if (false && xml.name() == "signals") - startDeclareSignals(); - else if (false && xml.name() == "states") - loop(); // ignore - else if (false && xml.name() == "transitions") - loop(); // ignore - else if (knownListProperties.contains(xml.name().toString())) - startList(); - else if (false && xml.name() == "SetProperties") - startSetProperties(); - else if (false && xml.name() == "SetProperty") - startSetProperty(); - else if (false && xml.name() == "ParentChange") - startParentChange(); - else if (true && xml.name() == "Connection") - startConnection(); - else if (false && xml.name() == "Script") - startScript(); - else if (xml.name().at(0).isLower() && xml.attributes().isEmpty()) - startObjectProperty(); - else - startItem(); - } - - static void possiblyRemoveBraces(QString *s) { - if (s->startsWith('{') && s->endsWith('}')) - *s = s->mid(1, s->length() - 2); - } - - static bool isNumber(const QString &s) { - bool ok = true; - s.toFloat(&ok); - return ok; - } - - static bool isSignalHandler(const QString &s) { - return s.size() > 3 - && s.startsWith("on") - && s.at(2).isUpper(); - } - - static bool isEnum(const QString &property, const QString &value) { - return !value.contains(' ') && (property == "vAlign" || property == "hAlign" - || property == "style"); - } - - static bool isIdentifier(const QString &s) { - if (s.isEmpty()) - return false; - if (!s.at(1).isLetter()) - return false; - for (int i = 1; i < s.size(); ++i) { - QChar c = s.at(i); - if (c.isLetterOrNumber() - || c == QLatin1Char('_') - || c == QLatin1Char('-')) - continue; - return false; - } - return true; - } - - - void setProperty(const QString &property, const QString &value, bool newline = true) { - QString v = value.trimmed(); - if (v.startsWith('{')) { - possiblyRemoveBraces(&v); - } else if (v == "true" - || v == "false" - || isNumber(v) - || property == "id" - || isEnum(property, value) - ) { - ; - } else if (isSignalHandler(property)) { - // if not a function name, create an anonymous function - if (!isIdentifier(v)) { - v.prepend("{ "); - v.append(" }"); - } - } else - - // if (property == "text" || property == "name" || value.contains(' ') - // || value.contains("/") || value.startsWith('#') - // || property == "filename" || property == "source" || property == "src" - // || property == "title" || property == "movieTitle" || property == "movieDescription" - // || property == "properties" || property == "fromState" || property == "toState" - // ) - { - v.prepend('\"'); - v.append('\"'); - } - -// QByteArray semiColon = ";"; -// if (v.endsWith(QLatin1Char('}')) || v.endsWith(QLatin1Char(';'))) -// semiColon.clear(); - - if (!newline) - out << property << ": " << v /* << semiColon.constData() */; - else - out << depthString() << property << ": " << v /* << semiColon.constData() */ << endl; - } - - - typedef QPair StringPair; - QList propertyChangeSet; - void startItem(bool inList = false) { - - QString name = xml.name().toString(); - - out << depthString() << name << " {" << endl; - ++depth; - - foreach (QXmlStreamAttribute attribute, xml.attributes()) { - setProperty(attribute.name().toString(), attribute.value().toString()); - } - - if (name == "Script") { - QString text = xml.readElementText(); - if (!text.trimmed().isEmpty()) { - out << text << endl; - } - } else { - loop(); - } - - if (name == "State") - clearPropertyChangeSet(); - - --depth; - out << depthString() << "}"; - if (!inList) - out << endl; - } - - void clearPropertyChangeSet() { - if (propertyChangeSet.isEmpty()) - return; - - out << depthString() << "PropertyChangeSet" << " {" << endl; - ++depth; - foreach(StringPair pair, propertyChangeSet) - setProperty(pair.first, pair.second); - --depth; - out << depthString() << "}" << endl; - propertyChangeSet.clear(); - } - - void startObjectProperty() { - - QString name = xml.name().toString(); - bool hasElements = false; - while (!xml.atEnd()) { - xml.readNext(); - if (xml.tokenType() == QXmlStreamReader::EndElement) - break; - if (xml.tokenType() == QXmlStreamReader::StartElement) { - hasElements = true; - out << depthString() << name << ": "; - supressIndent = true; - startElement(); - } else if (!hasElements && xml.tokenType() == QXmlStreamReader::Characters) { - if (!xml.text().toString().trimmed().isEmpty()) { - setProperty(name, xml.text().toString()); - } - } - comment(); - } - } - - void startDeclareProperty() { - out << depthString() << "public property "; - - if (xml.attributes().hasAttribute("type")) - out << "/* " << xml.attributes().value("type").toString() << " */ "; - - QString name = xml.attributes().value("name").toString(); - - if (xml.attributes().hasAttribute("value")) - setProperty(name, xml.attributes().value("value").toString(), false); - else out << name; - - QMap attributes; - foreach (QXmlStreamAttribute attribute, xml.attributes()) { - if (attribute.name() == "name" || attribute.name() == "value") - continue; - attributes.insert(attribute.name().toString(), attribute.value().toString()); - } - out << endl; - emptyLoop(); - } - - void startDeclareProperties() { - while (!xml.atEnd()) { - xml.readNext(); - if (xml.tokenType() == QXmlStreamReader::EndElement) - return; - if (xml.tokenType() == QXmlStreamReader::StartElement) { - if (xml.name() == "Property") - startDeclareProperty(); - } - comment(); - } - } - - void startDeclareSignal() { - out << depthString() << "public signal " << xml.attributes().value("name").toString() << endl; - emptyLoop(); - } - - void startDeclareSignals() { - while (!xml.atEnd()) { - xml.readNext(); - if (xml.tokenType() == QXmlStreamReader::EndElement) - return; - if (xml.tokenType() == QXmlStreamReader::StartElement) { - if (xml.name() == "Signal") - startDeclareSignal(); - } - comment(); - } - } - - - void startSetProperties() { - QString target = xml.attributes().value("target").toString(); - possiblyRemoveBraces(&target); - foreach (QXmlStreamAttribute attribute, xml.attributes()) { - if (attribute.name() == "target") - continue; - propertyChangeSet += StringPair(target + "." + attribute.name().toString(), attribute.value().toString()); - } - emptyLoop(); - } - - void startSetProperty() { - QString target = xml.attributes().value("target").toString(); - possiblyRemoveBraces(&target); - propertyChangeSet += StringPair(target + "." + xml.attributes().value("property").toString(), - xml.attributes().value("value").toString()); - - emptyLoop(); - } - - void startParentChange() { - QString target = xml.attributes().value("target").toString(); - possiblyRemoveBraces(&target); - - out << depthString() << "ParentChangeSet" << " {" << endl; - ++depth; - setProperty(target + ".parent", xml.attributes().value("parent").toString()); - --depth; - out << depthString() << "}" << endl; - -// propertyChangeSet += StringPair(target + ".moveToParent", xml.attributes().value("parent").toString()); - - emptyLoop(); - } - - void startConnection() { - QString sender = xml.attributes().value("sender").toString(); - possiblyRemoveBraces(&sender); - out << depthString() << "Connection {" << endl; - ++depth; - if (! sender.isEmpty()) - out << depthString() << "sender: " << sender << endl; - if (xml.attributes().hasAttribute("signal")) - out << depthString() << "signal: \"" << xml.attributes().value("signal").toString() << '"' << endl; - if (xml.attributes().hasAttribute("script")) { - out << depthString() << "script: { " << xml.attributes().value("script").toString() << " }" << endl; - --depth; - out << depthString() << "}" << endl; - } else { - QString text; - while (!xml.atEnd()) { - xml.readNext(); - if (xml.tokenType() == QXmlStreamReader::EndElement) - break; - else if (xml.tokenType() == QXmlStreamReader::Characters) - text.append(xml.text()); - } - - out << depthString() << "script: {" << endl; - foreach (QString line, text.split(QLatin1Char('\n'))) { - out << depthString() << line << endl; - } - out << depthString() << "}" << endl; - --depth; - out << depthString() << "}" << endl; - } - emptyLoop(); - } - - void startScript() { - if (xml.attributes().hasAttribute(QLatin1String("src"))) { - /* - QString import; - QTextStream ts(&import); - ts << "import \""; - ts << xml.attributes().value(QLatin1String("src")).toString(); - ts << "\"" << endl; - ts.flush(); - outString.prepend(import); - */ - } - QString text = xml.readElementText(); - if (!text.trimmed().isEmpty()) { - out << text << endl; - } - if (xml.tokenType() != QXmlStreamReader::EndElement) - emptyLoop(); - } - - void startList() - { - out << depthString() << xml.name().toString() << ": [" << endl; - ++depth; - bool needComma = false; - - while (!xml.atEnd()) { - xml.readNext(); - if (xml.tokenType() == QXmlStreamReader::EndElement) - break; - if (xml.tokenType() == QXmlStreamReader::StartElement) { - if (needComma) - out << "," << endl; - startItem(true); - needComma = true; - } - comment(); - } - - out << endl; - --depth; - out << depthString() << "]" << endl; - } - -}; - - - -int main(int argc, char *argv[]) -{ - QCoreApplication a(argc, argv); - - QStringList args = a.arguments(); - args.removeFirst(); - - if (!args.isEmpty() && args.first() == QLatin1String("-i")) { - optionInPlace = true; - args.removeFirst(); - } - - if (args.isEmpty() && optionInPlace) { - qWarning() << "Usage: qmlconv [ [-i] filename ]"; - exit(1); - } - - const QString fileName = args.isEmpty() ? QString("-") : args.first(); - - QFile file(fileName); - if (fileName == "-") { - file.open(0,QIODevice::ReadOnly); - } else { - if (! file.open(QIODevice::ReadOnly)) { - qWarning() << "qmlconv: no input file"; - exit(1); - } - } - - Reader r(&file); - file.close(); - - if (optionInPlace) { - if (! file.open(QFile::WriteOnly)) { - qWarning() << "qmlconv: cannot open file" << qPrintable(fileName); - exit(1); - } - - QTextStream out(&file); - out << r.output(); - file.close(); - } - - return 0; -} diff --git a/tools/qmlconv/qmlconv.pro b/tools/qmlconv/qmlconv.pro deleted file mode 100644 index 331f4ee..0000000 --- a/tools/qmlconv/qmlconv.pro +++ /dev/null @@ -1,10 +0,0 @@ -DESTDIR = ../../bin -QT -= gui -# Input -SOURCES += qmlconv.cpp - -target.path=$$[QT_INSTALL_BINS] -INSTALLS += target - -CONFIG += console -macx:CONFIG -= app_bundle -- cgit v0.12 From f062be7569804461dad94d5b80dc0b87298fd5eb Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 14:00:03 +1000 Subject: Remove XML custom parser support --- .../phonebrowser/dummydata/PhonesModel.qml | 2 +- .../declarative/pathview/dummydata/MenuModel.qml | 2 +- .../contacts/dummydata/contactModel.qml | 2 +- examples/declarative/easing/easing.qml | 2 +- .../declarative/listview/dummydata/MyPetsModel.qml | 2 +- .../declarative/listview/dummydata/Recipies.qml | 2 +- examples/declarative/velocity/velocity.qml | 2 +- src/declarative/qml/qmlcompiler.cpp | 26 +-- src/declarative/qml/qmlcustomparser_p.h | 17 -- src/declarative/qml/qmlinstruction.cpp | 3 - src/declarative/qml/qmlinstruction_p.h | 5 - src/declarative/qml/qmlvme.cpp | 21 --- src/declarative/util/qmllistmodel.cpp | 180 +-------------------- 13 files changed, 17 insertions(+), 249 deletions(-) diff --git a/demos/declarative/phonebrowser/dummydata/PhonesModel.qml b/demos/declarative/phonebrowser/dummydata/PhonesModel.qml index eb68fdb..8d9ed97 100644 --- a/demos/declarative/phonebrowser/dummydata/PhonesModel.qml +++ b/demos/declarative/phonebrowser/dummydata/PhonesModel.qml @@ -1,4 +1,4 @@ -ListModel2 { +ListModel { id: "PhonesModel" ListElement { diff --git a/doc/src/snippets/declarative/pathview/dummydata/MenuModel.qml b/doc/src/snippets/declarative/pathview/dummydata/MenuModel.qml index 5b973d7..44cdaf0 100644 --- a/doc/src/snippets/declarative/pathview/dummydata/MenuModel.qml +++ b/doc/src/snippets/declarative/pathview/dummydata/MenuModel.qml @@ -1,4 +1,4 @@ -ListModel2 { +ListModel { id: MenuModel ListElement { name: "Bill Jones" diff --git a/examples/declarative/contacts/dummydata/contactModel.qml b/examples/declarative/contacts/dummydata/contactModel.qml index 48b2fd9..53f6b7b 100644 --- a/examples/declarative/contacts/dummydata/contactModel.qml +++ b/examples/declarative/contacts/dummydata/contactModel.qml @@ -1,4 +1,4 @@ -ListModel2 { +ListModel { ListElement { firstName: "Aaron" lastName: "Kennedy" diff --git a/examples/declarative/easing/easing.qml b/examples/declarative/easing/easing.qml index 32c1b9b..af675d1 100644 --- a/examples/declarative/easing/easing.qml +++ b/examples/declarative/easing/easing.qml @@ -4,7 +4,7 @@ Rect { height: Layout.height color: "white" - ListModel2 { + ListModel { id: EasingTypes ListElement { type: "easeLinear" } ListElement { type: "easeInQuad" } diff --git a/examples/declarative/listview/dummydata/MyPetsModel.qml b/examples/declarative/listview/dummydata/MyPetsModel.qml index 1c96b7f..4d76ff4 100644 --- a/examples/declarative/listview/dummydata/MyPetsModel.qml +++ b/examples/declarative/listview/dummydata/MyPetsModel.qml @@ -1,6 +1,6 @@ // ListModel allows free form list models to be defined and populated. // Be sure to name the file the same as the id. -ListModel2 { +ListModel { id: MyListElementsModel ListElement { name: "Polly" diff --git a/examples/declarative/listview/dummydata/Recipies.qml b/examples/declarative/listview/dummydata/Recipies.qml index 8f464da..3f2ab48 100644 --- a/examples/declarative/listview/dummydata/Recipies.qml +++ b/examples/declarative/listview/dummydata/Recipies.qml @@ -1,4 +1,4 @@ -ListModel2 { +ListModel { id: Recipies ListElement { title: "Pancakes" diff --git a/examples/declarative/velocity/velocity.qml b/examples/declarative/velocity/velocity.qml index ff95527..786f364 100644 --- a/examples/declarative/velocity/velocity.qml +++ b/examples/declarative/velocity/velocity.qml @@ -2,7 +2,7 @@ Rect { color: "lightSteelBlue" width: 800 height: 600 - ListModel2 { + ListModel { id: List ListElement { name: "Sunday" diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 37d7fa1..ec5903e 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -569,25 +569,13 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) } int createInstrIdx = output->bytecode.count(); - if (obj->type != -1 && output->types.at(obj->type).parser) { - QByteArray data = obj->custom; - int ref = output->indexForByteArray(data); - - QmlInstruction create; - create.type = QmlInstruction::CreateCustomObject; - create.line = obj->line; - create.createCustom.type = obj->type; - create.createCustom.data = ref; - output->bytecode << create; - } else { - // Create the object - QmlInstruction create; - create.type = QmlInstruction::CreateObject; - create.line = obj->line; - create.create.data = -1; - create.create.type = obj->type; - output->bytecode << create; - } + // Create the object + QmlInstruction create; + create.type = QmlInstruction::CreateObject; + create.line = obj->line; + create.create.data = -1; + create.create.type = obj->type; + output->bytecode << create; COMPILE_CHECK(compileDynamicPropertiesAndSignals(obj)); diff --git a/src/declarative/qml/qmlcustomparser_p.h b/src/declarative/qml/qmlcustomparser_p.h index 0e6a619..e4e6089 100644 --- a/src/declarative/qml/qmlcustomparser_p.h +++ b/src/declarative/qml/qmlcustomparser_p.h @@ -98,26 +98,9 @@ class Q_DECLARATIVE_EXPORT QmlCustomParser public: virtual ~QmlCustomParser() {} - virtual QByteArray compile(QXmlStreamReader&, bool *ok)=0; virtual QByteArray compile(const QList &, bool *ok); - virtual QVariant create(const QByteArray &)=0; virtual void setCustomData(QObject *, const QByteArray &); - - struct Register { - Register(const char *name, QmlCustomParser *parser) { - qmlRegisterCustomParser(name, parser); - } - }; - template - struct Define { - static Register instance; - }; }; -#define QML_DEFINE_CUSTOM_PARSER(name, parserClass) \ - template<> QmlCustomParser::Register QmlCustomParser::Define::instance(# name, new parserClass); -#define QML_DEFINE_CUSTOM_PARSER_NS(namespacestring, name, parserClass) \ - template<> QmlCustomParser::Register QmlCustomParser::Define::instance(namespacestring "/" # name, new parserClass); - #define QML_DEFINE_CUSTOM_TYPE(TYPE, NAME, CUSTOMTYPE) \ template<> QmlPrivate::InstanceType QmlPrivate::Define::instance(qmlRegisterCustomType(#NAME, #TYPE, new CUSTOMTYPE)); diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 82924c8..52677c2 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -58,9 +58,6 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::CreateObject: qWarning() << idx << "\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; break; - case QmlInstruction::CreateCustomObject: - qWarning() << idx << "\t" << line << "\t" << "CREATE_CUSTOM\t\t" << instr->createCustom.type << "\t" << instr->createCustom.data << "\t\t" << types.at(instr->create.type).className; - break; case QmlInstruction::SetId: qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t" << instr->setId.save << "\t\t" << primitives.at(instr->setId.value); break; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 922fc61..462f9e4 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -63,7 +63,6 @@ public: // top of the stack. Init, /* init */ CreateObject, /* create */ - CreateCustomObject, /* createCustom */ SetId, /* setId */ SetDefault, CreateComponent, /* createComponent */ @@ -180,10 +179,6 @@ public: int data; } storeMeta; struct { - int type; - int data; - } createCustom; - struct { int value; int save; } setId; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index a3bfd62..ad3d1d5 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -277,27 +277,6 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in } break; - case QmlInstruction::CreateCustomObject: - { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxCompilerTimer cc; -#endif - QVariant v = - types.at(instr.createCustom.type).parser->create(datas.at(instr.createCustom.data)); - // XXX - QObject *o = QmlMetaType::toQObject(v); - if (!o) - VME_EXCEPTION("Unable to create" << types.at(instr.create.type).className); - QmlEngine::setContextForObject(o, QmlContext::activeContext()); - - if (!stack.isEmpty()) { - QObject *parent = stack.top(); - o->setParent(parent); - } - stack.push(o); - } - break; - case QmlInstruction::SetId: { #ifdef Q_ENABLE_PERFORMANCE_LOG diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 4837180..6ad0cb9 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -190,8 +190,6 @@ ModelObject::ModelObject(ModelNode *node) { } -QML_DECLARE_TYPE(ListModel); -QML_DEFINE_TYPE(ListModel,ListModel); ListModel::ListModel(QObject *parent) : QListModelInterface(parent), _rolesOk(false), _root(0) { @@ -304,14 +302,10 @@ int ListModel::count() const class ListModelParser : public QmlCustomParser { public: - virtual QByteArray compile(QXmlStreamReader& reader, bool *); QByteArray compile(const QList &, bool *ok); - virtual QVariant create(const QByteArray &); - bool compileProperty(const QmlCustomParserProperty &prop, QList &instr, QByteArray &data); void setCustomData(QObject *, const QByteArray &); }; -QML_DEFINE_CUSTOM_PARSER(ListModel, ListModelParser); bool ListModelParser::compileProperty(const QmlCustomParserProperty &prop, QList &instr, QByteArray &data) { @@ -462,13 +456,10 @@ void ListModelParser::setCustomData(QObject *obj, const QByteArray &d) } } -class ListModel2 : public ListModel -{ -Q_OBJECT -}; -QML_DECLARE_TYPE(ListModel2); -QML_DEFINE_CUSTOM_TYPE(ListModel2, ListModel2, ListModelParser); +QML_DECLARE_TYPE(ListModel); +QML_DEFINE_CUSTOM_TYPE(ListModel, ListModel, ListModelParser); +// ### FIXME class ListElement : public QObject { Q_OBJECT @@ -512,170 +503,5 @@ ModelNode::~ModelNode() if (modelCache) { delete modelCache; modelCache = 0; } } -QByteArray ListModelParser::compile(QXmlStreamReader& reader, bool *ok) -{ - *ok = true; - - QByteArray data; - QList instr; - int depth=0; - - while(!reader.atEnd() && depth >= 0) { - switch(reader.readNext()) { - case QXmlStreamReader::StartElement: - { - QStringRef name = reader.name(); - bool isType = name.at(0).isUpper(); - - if (isType) { - ListInstruction li; - li.type = ListInstruction::Push; - li.dataIdx = -1; - instr << li; - - for (int i = 0; i < reader.attributes().count(); ++i) { - const QXmlStreamAttribute &attr = reader.attributes().at(i); - QStringRef attrName = attr.name(); - QStringRef attrValue = attr.value(); - - ListInstruction li; - int ref = data.count(); - data.append(attrName.toString().toLatin1()); - data.append('\0'); - li.type = ListInstruction::Set; - li.dataIdx = ref; - instr << li; - - ref = data.count(); - data.append(attrValue.toString().toLatin1()); - data.append('\0'); - li.type = ListInstruction::Value; - li.dataIdx = ref; - instr << li; - - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; - } - } else { - ListInstruction li; - int ref = data.count(); - data.append(name.toString().toLatin1()); - data.append('\0'); - li.type = ListInstruction::Set; - li.dataIdx = ref; - instr << li; - } - } - ++depth; - break; - case QXmlStreamReader::EndElement: - { - ListInstruction li; - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; - --depth; - } - break; - case QXmlStreamReader::Characters: - if (!reader.isWhitespace()) { - int ref = data.count(); - QByteArray d = reader.text().toString().toLatin1(); - d.append('\0'); - data.append(d); - - ListInstruction li; - li.type = ListInstruction::Value; - li.dataIdx = ref; - instr << li; - } - break; - - case QXmlStreamReader::Invalid: - case QXmlStreamReader::NoToken: - case QXmlStreamReader::StartDocument: - case QXmlStreamReader::EndDocument: - case QXmlStreamReader::Comment: - case QXmlStreamReader::DTD: - case QXmlStreamReader::EntityReference: - case QXmlStreamReader::ProcessingInstruction: - break; - } - } - - if (reader.hasError()) - *ok = true; - - if (!*ok) - return QByteArray(); - - int size = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction) + - data.count(); - - QByteArray rv; - rv.resize(size); - - ListModelData *lmd = (ListModelData *)rv.data(); - lmd->dataOffset = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction); - lmd->instrCount = instr.count(); - for (int ii = 0; ii < instr.count(); ++ii) - lmd->instructions()[ii] = instr.at(ii); - ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count()); - - return rv; -} - -QVariant ListModelParser::create(const QByteArray &d) -{ - ListModel *rv = new ListModel; - ModelNode *root = new ModelNode; - rv->_root = root; - QStack nodes; - nodes << root; - - const ListModelData *lmd = (const ListModelData *)d.constData(); - const char *data = ((const char *)lmd) + lmd->dataOffset; - - for (int ii = 0; ii < lmd->instrCount; ++ii) { - const ListInstruction &instr = lmd->instructions()[ii]; - - switch(instr.type) { - case ListInstruction::Push: - { - ModelNode *n = nodes.top(); - ModelNode *n2 = new ModelNode; - n->values << qVariantFromValue(n2); - nodes.push(n2); - } - break; - - case ListInstruction::Pop: - nodes.pop(); - break; - - case ListInstruction::Value: - { - ModelNode *n = nodes.top(); - n->values.append(QByteArray(data + instr.dataIdx)); - } - break; - - case ListInstruction::Set: - { - ModelNode *n = nodes.top(); - ModelNode *n2 = new ModelNode; - n->properties.insert(QLatin1String(data + instr.dataIdx), n2); - nodes.push(n2); - } - break; - } - } - - return QVariant::fromValue(rv); -} - QT_END_NAMESPACE #include "qmllistmodel.moc" -- cgit v0.12 From d778d86065e08cf55fdf70a491f17c61ff93705c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 14:05:03 +1000 Subject: Remove magic "properties" and "signals" property support New properties and signals should be defined using the QML syntax: [default] property [: ] signal --- src/declarative/qml/qmlcompiler.cpp | 238 +----------------------------------- src/declarative/qml/qmlcompiler_p.h | 5 - src/declarative/qml/qmlparser.cpp | 5 +- src/declarative/qml/qmlparser_p.h | 4 - 4 files changed, 3 insertions(+), 249 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index ec5903e..b8f3921 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -64,17 +64,6 @@ #include "qmlscriptparser_p.h" QT_BEGIN_NAMESPACE -/* - New properties and signals can be added to any QObject type from QML. - - - - metatype && obj->metatype->indexOfProperty(PROPERTIES_NAME) != -1) - ignoreProperties = true; - if (obj->metatype && obj->metatype->indexOfProperty(SIGNALS_NAME) != -1) - ignoreSignals = true; - - Property *propertiesProperty = ignoreProperties?0:obj->getProperty(PROPERTIES_NAME, false); - Property *signalsProperty = ignoreSignals?0:obj->getProperty(SIGNALS_NAME, false); - - if (propertiesProperty) { - obj->dynamicPropertiesProperty = propertiesProperty; - obj->properties.remove(PROPERTIES_NAME); - } - if (signalsProperty) { - obj->dynamicSignalsProperty = signalsProperty; - obj->properties.remove(SIGNALS_NAME); - } - int createInstrIdx = output->bytecode.count(); // Create the object QmlInstruction create; @@ -602,9 +570,7 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) QList customProps; foreach(Property *prop, obj->properties) { - if (!ignoreProperties && prop->name == PROPERTIES_NAME) { - } else if (!ignoreSignals && prop->name == SIGNALS_NAME) { - } else if (prop->name.length() >= 3 && prop->name.startsWith("on") && + if (prop->name.length() >= 3 && prop->name.startsWith("on") && ('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) { if (!isCustomParser) { COMPILE_CHECK(compileSignal(prop, obj)); @@ -1246,209 +1212,9 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, return true; } -bool QmlCompiler::findDynamicProperties(QmlParser::Property *prop, - QmlParser::Object *obj) -{ - QList definedProperties; - - struct TypeNameToType { - const char *name; - Object::DynamicProperty::Type type; - } propTypeNameToTypes[] = { - { "", Object::DynamicProperty::Variant }, - { "int", Object::DynamicProperty::Int }, - { "bool", Object::DynamicProperty::Bool }, - { "double", Object::DynamicProperty::Real }, - { "real", Object::DynamicProperty::Real }, - { "string", Object::DynamicProperty::String }, - { "color", Object::DynamicProperty::Color }, - { "date", Object::DynamicProperty::Date }, - { "variant", Object::DynamicProperty::Variant } - }; - const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / - sizeof(propTypeNameToTypes[0]); - - - if (prop->value) - COMPILE_EXCEPTION("Invalid property specification"); - - bool seenDefault = false; - for (int ii = 0; ii < prop->values.count(); ++ii) { - QmlParser::Value *val = prop->values.at(ii); - if (!val->object) - COMPILE_EXCEPTION("Invalid property specification"); - - QmlParser::Object *obj = val->object; - if (obj->type == -1 || output->types.at(obj->type).className != "Property") - COMPILE_EXCEPTION("Use Property tag to specify properties"); - - - enum Seen { None = 0, Name = 0x01, - Type = 0x02, Value = 0x04, - ValueChanged = 0x08, - Default = 0x10 } seen = None; - - Object::DynamicProperty propDef; - - for (QHash::ConstIterator iter = - obj->properties.begin(); - iter != obj->properties.end(); - ++iter) { - - QmlParser::Property *property = *iter; - if (property->name == "name") { - if (seen & Name) - COMPILE_EXCEPTION("May only specify Property name once"); - seen = (Seen)(seen | Name); - - if (property->value || property->values.count() != 1 || - property->values.at(0)->object) - COMPILE_EXCEPTION("Invalid Property name"); - - propDef.name = property->values.at(0)->primitive.toLatin1(); - - } else if (property->name == "type") { - if (seen & Type) - COMPILE_EXCEPTION("May only specify Property type once"); - seen = (Seen)(seen | Type); - - if (property->value || property->values.count() != 1 || - property->values.at(0)->object) - COMPILE_EXCEPTION("Invalid Property type"); - - QString type = property->values.at(0)->primitive.toLower(); - bool found = false; - for (int ii = 0; !found && ii < propTypeNameToTypesCount; ++ii) { - if (type == QLatin1String(propTypeNameToTypes[ii].name)){ - found = true; - propDef.type = propTypeNameToTypes[ii].type; - } - - } - - if (!found) - COMPILE_EXCEPTION("Invalid Property type"); - - } else if (property->name == "value") { - if (seen & Value) - COMPILE_EXCEPTION("May only specify Property value once"); - seen = (Seen)(seen | Value); - - propDef.defaultValue = property; - } else if (property->name == "onValueChanged") { - if (seen & ValueChanged) - COMPILE_EXCEPTION("May only specify Property onValueChanged once"); - seen = (Seen)(seen | ValueChanged); - - if (property->value || property->values.count() != 1 || - property->values.at(0)->object) - COMPILE_EXCEPTION("Invalid Property onValueChanged"); - - propDef.onValueChanged = property->values.at(0)->primitive; - - } else if (property->name == "default") { - if (seen & Default) - COMPILE_EXCEPTION("May only specify Property default once"); - seen = (Seen)(seen | Default); - if (property->value || property->values.count() != 1 || - property->values.at(0)->object) - COMPILE_EXCEPTION("Invalid Property default"); - - bool defaultValue = - QmlStringConverters::boolFromString(property->values.at(0)->primitive); - propDef.isDefaultProperty = defaultValue; - if (defaultValue) { - if (seenDefault) - COMPILE_EXCEPTION("Only one property may be the default"); - seenDefault = true; - } - - } else { - COMPILE_EXCEPTION("Invalid Property property"); - } - - } - if (obj->defaultProperty) { - if (seen & Value) - COMPILE_EXCEPTION("May only specify Property value once"); - - seen = (Seen)(seen | Value); - propDef.defaultValue = obj->defaultProperty; - } - - if (!(seen & Name)) - COMPILE_EXCEPTION("Must specify Property name"); - - definedProperties << propDef; - } - - obj->dynamicProperties << definedProperties; - return true; -} - -bool QmlCompiler::findDynamicSignals(QmlParser::Property *sigs, - QmlParser::Object *obj) -{ - QList definedSignals; - - if (sigs->value) - COMPILE_EXCEPTION("Invalid signal specification"); - - for (int ii = 0; ii < sigs->values.count(); ++ii) { - QmlParser::Value *val = sigs->values.at(ii); - if (!val->object) - COMPILE_EXCEPTION("Invalid signal specification"); - - QmlParser::Object *obj = val->object; - if (obj->type == -1 || output->types.at(obj->type).className != "Signal") - COMPILE_EXCEPTION("Use Signal tag to specify signals"); - - enum Seen { None = 0, Name = 0x01 } seen = None; - Object::DynamicSignal sigDef; - - for (QHash::ConstIterator iter = - obj->properties.begin(); - iter != obj->properties.end(); - ++iter) { - - QmlParser::Property *property = *iter; - if (property->name == "name") { - if (seen & Name) - COMPILE_EXCEPTION("May only specify Signal name once"); - seen = (Seen)(seen | Name); - - if (property->value || property->values.count() != 1 || - property->values.at(0)->object) - COMPILE_EXCEPTION("Invalid Signal name"); - - sigDef.name = property->values.at(0)->primitive.toLatin1(); - - } else { - COMPILE_EXCEPTION("Invalid Signal property"); - } - - } - - if (obj->defaultProperty) - COMPILE_EXCEPTION("Invalid Signal property"); - - if (!(seen & Name)) - COMPILE_EXCEPTION("Must specify Signal name"); - - definedSignals << sigDef; - } - - obj->dynamicSignals << definedSignals; - return true; -} - bool QmlCompiler::compileDynamicPropertiesAndSignals(QmlParser::Object *obj) { - if (obj->dynamicPropertiesProperty) - findDynamicProperties(obj->dynamicPropertiesProperty, obj); - if (obj->dynamicSignalsProperty) - findDynamicSignals(obj->dynamicSignalsProperty, obj); - + // ### FIXME - Check that there is only one default property etc. if (obj->dynamicProperties.isEmpty() && obj->dynamicSignals.isEmpty()) return true; diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index cc1a9e9..4acdcfa 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -163,11 +163,6 @@ private: QmlParser::Value *value, int ctxt); - bool findDynamicProperties(QmlParser::Property *prop, - QmlParser::Object *obj); - bool findDynamicSignals(QmlParser::Property *sigs, - QmlParser::Object *obj); - bool compileDynamicPropertiesAndSignals(QmlParser::Object *obj); void compileBinding(const QString &, QmlParser::Property *prop, int ctxt, const QMetaObject *, qint64); diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 87c8434..d862315 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -63,8 +63,7 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; QmlParser::Object::Object() -: type(-1), metatype(0), extObject(0), defaultProperty(0), line(-1), column(-1), - dynamicPropertiesProperty(0), dynamicSignalsProperty(0) +: type(-1), metatype(0), extObject(0), defaultProperty(0), line(-1), column(-1) { } @@ -73,8 +72,6 @@ QmlParser::Object::~Object() if (defaultProperty) defaultProperty->release(); foreach(Property *prop, properties) prop->release(); - if (dynamicPropertiesProperty) dynamicPropertiesProperty->release(); - if (dynamicSignalsProperty) dynamicSignalsProperty->release(); } const QMetaObject *Object::metaObject() const diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 17b367d6..aeacee8 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -124,10 +124,6 @@ namespace QmlParser QByteArray name; }; - // The "properties" property - Property *dynamicPropertiesProperty; - // The "signals" property - Property *dynamicSignalsProperty; // The list of dynamic properties described in the "properties" property QList dynamicProperties; // The list of dynamic signals described in the "signals" property -- cgit v0.12 From 0725ca189ad30ec54a2a7a054404a50f20e2bfed Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 14:55:09 +1000 Subject: Add warning text --- src/declarative/qml/qmlscriptparser.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index d0051ac..81315c3 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -522,7 +522,11 @@ bool ProcessAST::visit(AST::UiSourceElement *node) { QmlParser::Object *obj = currentObject(); if (! (obj && obj->typeName == "Script")) { - // ### warning + QmlError error; + error.setDescription("JavaScript declaration outside Script element"); + error.setLine(node->firstSourceLocation().startLine); + error.setColumn(node->firstSourceLocation().startColumn); + _parser->_errors << error; return false; } -- cgit v0.12 From e8f2cc813ba4faf41677f65c51a990eea5df4308 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 5 May 2009 14:58:06 +1000 Subject: Improve QML documentation viewing in Assistant. The element pages now load correctly. A separate QML 'book' is also generated, which will be targeted at non-C++ programmers. --- doc/doc.pri | 5 ++- doc/src/declarative/qmlfordesign.qdoc | 42 ------------------- doc/src/declarative/qmlreference.qdoc | 41 +++++++++++++++++++ tools/qdoc3/helpprojectwriter.cpp | 3 ++ tools/qdoc3/test/qml.qdocconf | 77 +++++++++++++++++++++++++++++++++++ tools/qdoc3/tree.cpp | 9 +++- 6 files changed, 131 insertions(+), 46 deletions(-) delete mode 100644 doc/src/declarative/qmlfordesign.qdoc create mode 100644 doc/src/declarative/qmlreference.qdoc create mode 100644 tools/qdoc3/test/qml.qdocconf diff --git a/doc/doc.pri b/doc/doc.pri index a4c77fe..367ef29 100644 --- a/doc/doc.pri +++ b/doc/doc.pri @@ -32,13 +32,14 @@ macx { ADP_DOCS_QDOCCONF_FILE = qt-build-docs.qdocconf } QT_DOCUMENTATION = ($$QDOC qt-api-only.qdocconf assistant.qdocconf designer.qdocconf \ - linguist.qdocconf qmake.qdocconf) && \ + linguist.qdocconf qmake.qdocconf qml.qdocconf) && \ (cd $$QT_BUILD_TREE && \ $$GENERATOR doc-build/html-qt/qt.qhp -o doc/qch/qt.qch && \ $$GENERATOR doc-build/html-assistant/assistant.qhp -o doc/qch/assistant.qch && \ $$GENERATOR doc-build/html-designer/designer.qhp -o doc/qch/designer.qch && \ $$GENERATOR doc-build/html-linguist/linguist.qhp -o doc/qch/linguist.qch && \ - $$GENERATOR doc-build/html-qmake/qmake.qhp -o doc/qch/qmake.qch \ + $$GENERATOR doc-build/html-qmake/qmake.qhp -o doc/qch/qmake.qch && \ + $$GENERATOR doc-build/html-qml/qml.qhp -o doc/qch/qml.qch \ ) win32-g++:isEmpty(QMAKE_SH) { diff --git a/doc/src/declarative/qmlfordesign.qdoc b/doc/src/declarative/qmlfordesign.qdoc deleted file mode 100644 index 35e47df..0000000 --- a/doc/src/declarative/qmlfordesign.qdoc +++ /dev/null @@ -1,42 +0,0 @@ -/*! - \page qmlfordesigners.html - \title Qt Declarative for Designers - - \target qtdeclarativemainpage - - The Qt Declarative module provides a declarative framework for building - highly dynamic and fluid applications. It is targetted at the sorts of user - interface (and the sorts of hardware) in embedded devices such as phones, media - players, and set-top boxes. It is also appropriate for highly custom desktop - user-interfaces, or special elements in more traditional desktop - user-interfaces. - - Building fluid applications is done declaratively, rather than procedurally. - That is, you specify \e what the UI should look like and how it should behave - rather than specifying step-by-step \e how to build it. Specifying a UI declaratively - does not just include the layout of the interface items, but also the way each - individual item looks and behaves and the overall flow of the application. - - Getting Started: - \list - \o \l {qmlexamples}{Examples} - \o \l {tutorial}{Tutorial: 'Hello World'} - \o \l {tutorials-declarative-contacts.html}{Tutorial: 'Introduction to QML'} - \endlist - - Core 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} - \endlist - - QML Reference: - \list - \o \l {elements}{Qml Elements} - \endlist -*/ diff --git a/doc/src/declarative/qmlreference.qdoc b/doc/src/declarative/qmlreference.qdoc new file mode 100644 index 0000000..9a63e50 --- /dev/null +++ b/doc/src/declarative/qmlreference.qdoc @@ -0,0 +1,41 @@ +/*! + \page qmlreference.html + \title Qml Reference + + \target qtdeclarativemainpage + + QML is a language for building highly dynamic and fluid applications. It is targetted at the sorts of user + interface (and the sorts of hardware) in embedded devices such as phones, media + players, and set-top boxes. It is also appropriate for highly custom desktop + user-interfaces, or special elements in more traditional desktop + user-interfaces. + + Building fluid applications is done declaratively, rather than procedurally. + That is, you specify \e what the UI should look like and how it should behave + rather than specifying step-by-step \e how to build it. Specifying a UI declaratively + does not just include the layout of the interface items, but also the way each + individual item looks and behaves and the overall flow of the application. + + Getting Started: + \list + \o \l {qmlexamples}{Examples} + \o \l {tutorial}{Tutorial: 'Hello World'} + \o \l {tutorials-declarative-contacts.html}{Tutorial: 'Introduction to QML'} + \endlist + + Core 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} + \endlist + + QML Reference: + \list + \o \l {elements}{Qml Elements} + \endlist +*/ diff --git a/tools/qdoc3/helpprojectwriter.cpp b/tools/qdoc3/helpprojectwriter.cpp index 85bd898..16ee5f2 100644 --- a/tools/qdoc3/helpprojectwriter.cpp +++ b/tools/qdoc3/helpprojectwriter.cpp @@ -126,6 +126,9 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList subTypeHash["module"] = Node::Module; subTypeHash["page"] = Node::Page; subTypeHash["externalpage"] = Node::ExternalPage; +#ifdef QDOC_QML + subTypeHash["qmlclass"] = Node::QmlClass; +#endif QSet allSubTypes = QSet::fromList(subTypeHash.values()); diff --git a/tools/qdoc3/test/qml.qdocconf b/tools/qdoc3/test/qml.qdocconf new file mode 100644 index 0000000..3a7d76a --- /dev/null +++ b/tools/qdoc3/test/qml.qdocconf @@ -0,0 +1,77 @@ +include(compat.qdocconf) +include(macros.qdocconf) +include(qt-cpp-ignore.qdocconf) +include(qt-html-templates.qdocconf) +include(qt-defines.qdocconf) + +project = Qml +description = Qml Reference Documentation +url = http://doc.qtsoftware.com/4.6 + +edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \ + QtXmlPatterns QtTest +edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtSql QtSvg \ + QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \ + QtDesigner QtAssistant QAxContainer Phonon \ + QAxServer QtUiTools QtTest QtDBus +edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest +edition.DesktopLight.groups = -graphicsview-api + +qhp.projects = Qml + +qhp.Qml.file = qml.qhp +qhp.Qml.namespace = com.trolltech.qml.460 +qhp.Qml.virtualFolder = qdoc +qhp.Qml.indexTitle = Qml Reference + +# Files not referenced in any qdoc file +# See also extraimages.HTML +qhp.Qml.extraFiles = classic.css \ + images/qt-logo.png + +qhp.Qml.filterAttributes = qt 4.6.0 qtrefdoc +qhp.Qml.customFilters.Qt.name = Qt 4.6.0 +qhp.Qml.customFilters.Qt.filterAttributes = qt 4.6.0 +qhp.Qml.subprojects = classes +qhp.Qml.subprojects.classes.title = Elements +qhp.Qml.subprojects.classes.indexTitle = Qml Elements +qhp.Qml.subprojects.classes.selectors = fake:qmlclass +qhp.Qml.subprojects.classes.sortPages = true + +language = Cpp + +headerdirs = $QT_SOURCE_TREE/src/declarative +sourcedirs = $QT_SOURCE_TREE/src/declarative \ + $QT_SOURCE_TREE/doc/src/declarative + +sources += $QT_SOURCE_TREE/doc/src/tutorials/declarative.qdoc + +sources.fileextensions = "*.cpp *.qdoc" +examples.fileextensions = "*.cpp *.h *.js *.qml" + +exampledirs = $QT_SOURCE_TREE/doc/src \ + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/examples/tutorials \ + $QT_SOURCE_TREE \ + $QT_SOURCE_TREE/qmake/examples \ + $QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/doc/src/declarative/pics +outputdir = $QT_BUILD_TREE/doc-build/html-qml +tagfile = $QT_BUILD_TREE/doc-build/html-qml/qt.tags +base = file:$QT_BUILD_TREE/doc/html-qml + +HTML.stylesheets = classic.css + +HTML.postheader = "\n" \ + "\n" \ + "\n" \ + "" \ + "\n" \ + "
" \ + "" \ + "  " \ + "" \ + "Home" \ + "
" diff --git a/tools/qdoc3/tree.cpp b/tools/qdoc3/tree.cpp index 539db51..b91de65 100644 --- a/tools/qdoc3/tree.cpp +++ b/tools/qdoc3/tree.cpp @@ -1901,9 +1901,14 @@ QString Tree::fullDocumentLocation(const Node *node) const else return ""; } - else if (node->type() == Node::Fake) + else if (node->type() == Node::Fake) { +#ifdef QDOC_QML + if (node->subType() == Node::QmlClass) + return "qml-" + node->fileBase() + ".html"; + else +#endif return node->fileBase() + ".html"; - else if (node->fileBase().isEmpty()) + } else if (node->fileBase().isEmpty()) return ""; QString parentName; -- cgit v0.12 From 415708f85341448c6f30bbca6e31e48dbfde72a5 Mon Sep 17 00:00:00 2001 From: Ian Walters Date: Tue, 5 May 2009 15:16:30 +1000 Subject: Remove Painted, have WebView use ImageItem Reducing duplicated code and functionality. Removing QFxPainted as it isn't used and has less features than QFxImageItem, which fufills the same roles. Have QFxWebView use QFxImageItem as a base to reduce duplicated caching code. Minimal risk given that QFxImageItem is based of QFxWebView. --- src/declarative/fx/fx.pri | 3 - src/declarative/fx/qfxpainted.cpp | 194 -------------------------------------- src/declarative/fx/qfxpainted.h | 87 ----------------- src/declarative/fx/qfxpainted_p.h | 84 ----------------- src/declarative/fx/qfxwebview.cpp | 143 ++++------------------------ src/declarative/fx/qfxwebview.h | 16 +--- 6 files changed, 24 insertions(+), 503 deletions(-) delete mode 100644 src/declarative/fx/qfxpainted.cpp delete mode 100644 src/declarative/fx/qfxpainted.h delete mode 100644 src/declarative/fx/qfxpainted_p.h diff --git a/src/declarative/fx/fx.pri b/src/declarative/fx/fx.pri index ef059c7..7e04459 100644 --- a/src/declarative/fx/fx.pri +++ b/src/declarative/fx/fx.pri @@ -28,8 +28,6 @@ HEADERS += \ fx/qfxlayouts_p.h \ fx/qfxmouseregion.h \ fx/qfxmouseregion_p.h \ - fx/qfxpainted.h \ - fx/qfxpainted_p.h \ fx/qfxparticles.h \ fx/qfxpath.h \ fx/qfxpath_p.h \ @@ -73,7 +71,6 @@ SOURCES += \ fx/qfxkeyproxy.cpp \ fx/qfxlayouts.cpp \ fx/qfxmouseregion.cpp \ - fx/qfxpainted.cpp \ fx/qfxparticles.cpp \ fx/qfxpath.cpp \ fx/qfxpathview.cpp \ diff --git a/src/declarative/fx/qfxpainted.cpp b/src/declarative/fx/qfxpainted.cpp deleted file mode 100644 index 68918c3..0000000 --- a/src/declarative/fx/qfxpainted.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -#include "qfxpainted.h" -#include "qfxpainted_p.h" - - -QT_BEGIN_NAMESPACE -/*! - \internal - \class QFxPainted - \brief The QFxPainted class is an abstract base class for QFxView items that want cached painting. - - \ingroup group_coreitems - - This is a convenience class allowing easy use of cached painting within a custom item. - The contents of the item are cached behind the scenes. Any time you change the contents - you should call markDirty to make sure the cache is refreshed the next time painting occurs. - - \code - class GradientRect : public QFxPainted - { - Q_OBJECT - public: - GradientRect() : QFxPainted() - { - connect(this, SIGNAL(widthChanged()), this, SLOT(markDirty())); - connect(this, SIGNAL(heightChanged()), this, SLOT(markDirty())); - } - - void paint(QPainter *painter) - { - painter->fillRect(0, 0, width(), height(), QBrush(QLinearGradient(0,0,width(),height()))); - } - }; - \endcode - - \warning Dirty is only ever automatically set by QFxPainted at construction. Any other changes (including resizes) to the item need to be handled by the subclass (as in the example above). - \warning Frequent calls to markDirty will result in sub-optimal painting performance. -*/ - -/*! - Constructs a painted item with parent object \a parent. -*/ -QFxPainted::QFxPainted(QFxItem *parent) - : QFxItem(*(new QFxPaintedPrivate), parent) -{ - //### what options do we need to set? - setOptions(HasContents, true); -} - -/*! - Destroys the item. -*/ -QFxPainted::~QFxPainted() -{ -} - -/*! \internal -*/ -QFxPainted::QFxPainted(QFxPaintedPrivate &dd, QFxItem *parent) - : QFxItem(dd, parent) -{ - setOptions(HasContents, true); -} - -/*! - \fn QFxPainted::paint(QPainter *painter) - - Implement this method to paint the item using \a painter. - The painting will be cached and paint() will only be called again - if \l markDirty() has been called. - - \sa markDirty() -*/ - -/*! - The contents of the item are cached behind the scenes. Any time you change the contents - you should call markDirty to make sure the cache is refreshed the next time painting occurs. -*/ -void QFxPainted::markDirty() -{ - Q_D(QFxPainted); - if (d->dirty) - return; - d->dirty = true; - - // release cache memory (will be reallocated upon paintContents, if visible) -#if defined(QFX_RENDER_QPAINTER) - d->cachedImage = QImage(); -#elif defined(QFX_RENDER_OPENGL) - d->cachedTexture.clear(); -#endif - - update(); -} - -#if defined(QFX_RENDER_QPAINTER) -void QFxPainted::paintContents(QPainter &p) -{ - Q_D(QFxPainted); - if (d->dirty) { - d->cachedImage = QImage(width(), height(), QImage::Format_ARGB32_Premultiplied); - d->cachedImage.fill(0); - QPainter painter(&(d->cachedImage)); - paint(&painter); - d->dirty = false; - } - p.drawImage(0, 0, d->cachedImage); -} -#elif defined(QFX_RENDER_OPENGL2) -void QFxPainted::paintGLContents(GLPainter &painter) -{ - Q_D(QFxPainted); - if (d->dirty) { - QImage img = QImage(width(), height(), QImage::Format_ARGB32); - img.fill(0); - QPainter p(&(img)); - paint(&p); - d->cachedTexture.setImage(img); - d->dirty = false; - } - - //### mainly copied from QFxImage code - QGLShaderProgram *shader = painter.useTextureShader(); - - GLfloat vertices[8]; - GLfloat texVertices[8]; - GLTexture *tex = &d->cachedTexture; - - float widthV = d->cachedTexture.width(); - float heightV = d->cachedTexture.height(); - - vertices[0] = 0; vertices[1] = heightV; - vertices[2] = widthV; vertices[3] = heightV; - vertices[4] = 0; vertices[5] = 0; - vertices[6] = widthV; vertices[7] = 0; - - texVertices[0] = 0; texVertices[1] = 0; - texVertices[2] = 1; texVertices[3] = 0; - texVertices[4] = 0; texVertices[5] = 1; - texVertices[6] = 1; texVertices[7] = 1; - - shader->setAttributeArray(SingleTextureShader::Vertices, vertices, 2); - shader->setAttributeArray(SingleTextureShader::TextureCoords, texVertices, 2); - - glBindTexture(GL_TEXTURE_2D, tex->texture()); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - shader->disableAttributeArray(SingleTextureShader::Vertices); - shader->disableAttributeArray(SingleTextureShader::TextureCoords); -} - -#endif - -QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxpainted.h b/src/declarative/fx/qfxpainted.h deleted file mode 100644 index 1f22414..0000000 --- a/src/declarative/fx/qfxpainted.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -#ifndef QFXPAINTED_H -#define QFXPAINTED_H - -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) -/* -WARNING: INTENDED TO MERGE WITH QFxImageItem -*/ - -class QFxPaintedPrivate; -class Q_DECLARATIVE_EXPORT QFxPainted : public QFxItem -{ -Q_OBJECT -public: - QFxPainted(QFxItem *parent); - ~QFxPainted(); - - virtual void paint(QPainter *painter) = 0; - -#if defined(QFX_RENDER_QPAINTER) - void paintContents(QPainter &painter); -#elif defined(QFX_RENDER_OPENGL2) - void paintGLContents(GLPainter &); -#endif - -protected Q_SLOTS: - void markDirty(); - -protected: - QFxPainted(QFxPaintedPrivate &dd, QFxItem *parent); - -private: - Q_DISABLE_COPY(QFxPainted) - Q_DECLARE_PRIVATE(QFxPainted) -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QFXPAINTED_H diff --git a/src/declarative/fx/qfxpainted_p.h b/src/declarative/fx/qfxpainted_p.h deleted file mode 100644 index 68ac83e..0000000 --- a/src/declarative/fx/qfxpainted_p.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -#ifndef QFXPAINTED_P_H -#define QFXPAINTED_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qfxitem_p.h" -#if defined(QFX_RENDER_OPENGL) -#include "gltexture.h" -#endif - -QT_BEGIN_NAMESPACE - -class QFxPaintedPrivate : public QFxItemPrivate -{ - Q_DECLARE_PUBLIC(QFxPainted) - -public: - QFxPaintedPrivate() - : dirty(true) - { - } - - bool dirty; - -#if defined(QFX_RENDER_QPAINTER) - QSimpleCanvasConfig::Image cachedImage; -#elif defined(QFX_RENDER_OPENGL) - GLTexture cachedTexture; -#endif -}; - -QT_END_NAMESPACE - -#endif // QFXPAINTED_P_H diff --git a/src/declarative/fx/qfxwebview.cpp b/src/declarative/fx/qfxwebview.cpp index dac8ced..9b18a9e 100644 --- a/src/declarative/fx/qfxwebview.cpp +++ b/src/declarative/fx/qfxwebview.cpp @@ -68,7 +68,7 @@ #include "qfxwebview.h" #include -#include +#include QT_BEGIN_NAMESPACE QML_DEFINE_TYPE(QFxWebView,WebView); @@ -142,14 +142,14 @@ public: }; -class QFxWebViewPrivate : public QFxItemPrivate +class QFxWebViewPrivate : public QFxImageItemPrivate { Q_DECLARE_PUBLIC(QFxWebView) public: QFxWebViewPrivate() - : page(0), idealwidth(0), idealheight(0), interactive(true), lastPress(0), lastRelease(0), mouseX(0), mouseY(0), - smooth(true), max_imagecache_size(100000), progress(1.0), pending(PendingNone) + : QFxImageItemPrivate(), page(0), idealwidth(0), idealheight(0), interactive(true), lastPress(0), lastRelease(0), mouseX(0), mouseY(0), + max_imagecache_size(100000), progress(1.0), pending(PendingNone) { } @@ -189,7 +189,6 @@ public: bool interactive; QMouseEvent *lastPress, *lastRelease; int mouseX, mouseY; - bool smooth; int max_imagecache_size; qreal progress; QBasicTimer dcTimer; @@ -254,13 +253,13 @@ public: */ QFxWebView::QFxWebView(QFxItem *parent) - : QFxItem(*(new QFxWebViewPrivate), parent) + : QFxImageItem(*(new QFxWebViewPrivate), parent) { init(); } QFxWebView::QFxWebView(QFxWebViewPrivate &dd, QFxItem *parent) - : QFxItem(dd, parent) + : QFxImageItem(dd, parent) { init(); } @@ -284,7 +283,7 @@ void QFxWebView::init() void QFxWebView::componentComplete() { - QFxItem::componentComplete(); + QFxImageItem::componentComplete(); Q_D(QFxWebView); switch (d->pending) { case QFxWebViewPrivate::PendingUrl: @@ -460,28 +459,6 @@ void QFxWebView::setInteractive(bool i) emit interactiveChanged(); } -/*! - \qmlproperty bool WebView::smooth - This property holds hints as to whether the item should be drawn anti-aliased. -*/ -/*! - \property QFxWebView::smooth - \brief hints as to whether the item should be drawn anti-aliased. -*/ -bool QFxWebView::smooth() const -{ - Q_D(const QFxWebView); - return d->smooth; -} - -void QFxWebView::setSmooth(bool i) -{ - Q_D(QFxWebView); - if (d->smooth == i) return; - d->smooth = i; - update(); -} - void QFxWebView::updateCacheForVisibility() { Q_D(QFxWebView); @@ -514,13 +491,15 @@ void QFxWebView::geometryChanged(const QRectF &newGeometry, { if (newGeometry.size() != oldGeometry.size()) expandToWebPage(); - QFxItem::geometryChanged(newGeometry, oldGeometry); + QFxImageItem::geometryChanged(newGeometry, oldGeometry); } void QFxWebView::paintPage(const QRect& r) { Q_D(QFxWebView); - d->dirtyCache(r); + if (d->page->mainFrame()->contentsSize() != contentsSize()) + setContentsSize(d->page->mainFrame()->contentsSize()); + dirtyCache(r); update(); } @@ -575,96 +554,12 @@ void QFxWebView::dump(int depth) { QByteArray ba(depth * 4, ' '); qWarning() << ba.constData() << "url:" << url(); - QFxItem::dump(depth); + QFxImageItem::dump(depth); } -#if defined(QFX_RENDER_QPAINTER) -void QFxWebView::paintContents(QPainter &p) -#elif defined(QFX_RENDER_OPENGL) -void QFxWebView::paintGLContents(GLPainter &p) -#else -#error "What render?" -#endif +void QFxWebView::drawContents(QPainter *p, const QRect &r) { - Q_D(QFxWebView); - QWebFrame *frame = page()->mainFrame(); - const QRect content(QPoint(0,0),frame->contentsSize()); - - if (content.width() <= 0 || content.height() <= 0) - return; - -#if defined(QFX_RENDER_QPAINTER) - bool wasAA = p.testRenderHint(QPainter::Antialiasing); - bool wasSM = p.testRenderHint(QPainter::SmoothPixmapTransform); - p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); - QRectF clipf = p.clipRegion().boundingRect(); - const QRect clip = p.clipRegion().isEmpty() ? content : clipf.toRect(); -#elif defined(QFX_RENDER_OPENGL) - const QRectF clipf = p.sceneClipRect; - const QRect clip = mapFromScene(clipf).toRect(); -#endif - - QRegion topaint(clip); - topaint &= content; - QRegion uncached(content); - - int cachesize=0; - for (int i=0; iimagecache.count(); ++i) { - QRect area = d->imagecache[i]->area; - if (topaint.contains(area)) { - p.drawImage(area, d->imagecache[i]->image); - topaint -= area; - d->imagecache[i]->age=0; - } else { - d->imagecache[i]->age++; - } - cachesize += area.width()*area.height(); - uncached -= area; - } - - if (!topaint.isEmpty()) { - // Find a sensible larger area, otherwise will paint lots of tiny images. - QRect biggerrect = topaint.boundingRect().adjusted(-64,-64,128,128); - cachesize += biggerrect.width() * biggerrect.height(); - while (d->imagecache.count() && cachesize > d->max_imagecache_size) { - int oldest=-1; - int age=-1; - for (int i=0; iimagecache.count(); ++i) { - int a = d->imagecache[i]->age; - if (a > age) { - oldest = i; - age = a; - } - } - cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height(); - uncached += d->imagecache[oldest]->area; - d->imagecache.removeAt(oldest); - } - const QRegion bigger = QRegion(biggerrect) & uncached; - const QVector rects = bigger.rects(); - foreach (QRect r, rects) { - QImage img(r.size(),QImage::Format_ARGB32_Premultiplied); - img.fill(0); - { - QPainter qp(&img); - qp.translate(-r.x(),-r.y()); - frame->render(&qp,r); - } - QFxWebViewPrivate::ImageCacheItem *newitem = new QFxWebViewPrivate::ImageCacheItem; - newitem->area = r; -#if defined(QFX_RENDER_QPAINTER) - newitem->image = QSimpleCanvasConfig::Image(QSimpleCanvasConfig::toImage(img)); -#else - newitem->image.setImage(img); -#endif - d->imagecache.append(newitem); - p.drawImage(r, newitem->image); - } - } -#if defined(QFX_RENDER_QPAINTER) - p.setRenderHints(QPainter::Antialiasing, wasAA); - p.setRenderHints(QPainter::SmoothPixmapTransform, wasSM); -#endif + page()->mainFrame()->render(p,r); } QString QFxWebView::propertyInfo() const @@ -761,7 +656,7 @@ void QFxWebView::mousePressEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(false); } if (!event->isAccepted()) - QFxItem::mousePressEvent(event); + QFxImageItem::mousePressEvent(event); } void QFxWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) @@ -775,7 +670,7 @@ void QFxWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(false); } if (!event->isAccepted()) - QFxItem::mouseReleaseEvent(event); + QFxImageItem::mouseReleaseEvent(event); } void QFxWebView::mouseMoveEvent(QGraphicsSceneMouseEvent *event) @@ -796,7 +691,7 @@ void QFxWebView::mouseMoveEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(false); } if (!event->isAccepted()) - QFxItem::mouseMoveEvent(event); + QFxImageItem::mouseMoveEvent(event); } void QFxWebView::keyPressEvent(QKeyEvent* event) @@ -805,7 +700,7 @@ void QFxWebView::keyPressEvent(QKeyEvent* event) if (d->interactive) page()->event(event); if (!event->isAccepted()) - QFxItem::keyPressEvent(event); + QFxImageItem::keyPressEvent(event); } void QFxWebView::keyReleaseEvent(QKeyEvent* event) @@ -814,7 +709,7 @@ void QFxWebView::keyReleaseEvent(QKeyEvent* event) if (d->interactive) page()->event(event); if (!event->isAccepted()) - QFxItem::keyReleaseEvent(event); + QFxImageItem::keyReleaseEvent(event); } /*! diff --git a/src/declarative/fx/qfxwebview.h b/src/declarative/fx/qfxwebview.h index 6ba4601..17037ca 100644 --- a/src/declarative/fx/qfxwebview.h +++ b/src/declarative/fx/qfxwebview.h @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include @@ -74,7 +74,7 @@ private: }; -class Q_DECLARATIVE_EXPORT QFxWebView : public QFxItem +class Q_DECLARATIVE_EXPORT QFxWebView : public QFxImageItem { Q_OBJECT @@ -91,7 +91,6 @@ class Q_DECLARATIVE_EXPORT QFxWebView : public QFxItem Q_PROPERTY(int idealWidth READ idealWidth WRITE setIdealWidth NOTIFY idealWidthChanged) Q_PROPERTY(int idealHeight READ idealHeight WRITE setIdealHeight NOTIFY idealHeightChanged) Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged) - Q_PROPERTY(bool smooth READ smooth WRITE setSmooth) Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) Q_PROPERTY(bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged) @@ -128,9 +127,6 @@ public: int mouseX() const; int mouseY() const; - bool smooth() const; - void setSmooth(bool); - int idealWidth() const; void setIdealWidth(int); int idealHeight() const; @@ -146,11 +142,6 @@ public: virtual void dump(int depth); virtual QString propertyInfo() const; -#if defined(QFX_RENDER_QPAINTER) - void paintContents(QPainter &painter); -#elif defined(QFX_RENDER_OPENGL) - void paintGLContents(GLPainter &); -#endif QWebPage *page() const; void setPage(QWebPage *page); @@ -197,6 +188,9 @@ private Q_SLOTS: protected: QFxWebView(QFxWebViewPrivate &dd, QFxItem *parent); + + void drawContents(QPainter *, const QRect &); + void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); -- cgit v0.12 From c248a3c68fdce3387bec61e3b19bdf766ae93ed0 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 15:16:43 +1000 Subject: Add parser support for object slot declarations --- src/declarative/qml/qmlparser.cpp | 9 +++++ src/declarative/qml/qmlparser_p.h | 13 ++++++- src/declarative/qml/qmlscriptparser.cpp | 65 ++++++++++++++++++++++----------- 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index d862315..a943c4d 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -123,6 +123,15 @@ QmlParser::Object::DynamicSignal::DynamicSignal(const DynamicSignal &o) { } +QmlParser::Object::DynamicSlot::DynamicSlot() +{ +} + +QmlParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o) +: name(o.name), body(o.body) +{ +} + QmlParser::Property::Property() : type(0), index(-1), value(0), isDefault(true), line(-1), column(-1) { diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index aeacee8..676e25e 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -123,11 +123,20 @@ namespace QmlParser QByteArray name; }; + struct DynamicSlot { + DynamicSlot(); + DynamicSlot(const DynamicSlot &); - // The list of dynamic properties described in the "properties" property + QByteArray name; + QString body; + }; + + // The list of dynamic properties QList dynamicProperties; - // The list of dynamic signals described in the "signals" property + // The list of dynamic signals QList dynamicSignals; + // The list of dynamic slots + QList dynamicSlots; }; class Value : public QmlRefCount diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index 81315c3..22ff4a5 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -521,31 +521,54 @@ bool ProcessAST::visit(AST::UiArrayBinding *node) bool ProcessAST::visit(AST::UiSourceElement *node) { QmlParser::Object *obj = currentObject(); - if (! (obj && obj->typeName == "Script")) { - QmlError error; - error.setDescription("JavaScript declaration outside Script element"); - error.setLine(node->firstSourceLocation().startLine); - error.setColumn(node->firstSourceLocation().startColumn); - _parser->_errors << error; - return false; - } - QString source; + bool isScript = (obj && obj->typeName == "Script"); - int line = 0; - if (AST::FunctionDeclaration *funDecl = AST::cast(node->sourceElement)) { - line = funDecl->functionToken.startLine; - source = asString(funDecl); - } else if (AST::VariableStatement *varStmt = AST::cast(node->sourceElement)) { - // ignore variable declarations - line = varStmt->declarationKindToken.startLine; - } + if (!isScript) { - Value *value = new Value; - value->primitive = source; - value->line = line; + if (AST::FunctionDeclaration *funDecl = AST::cast(node->sourceElement)) { + + if(funDecl->formals) { + QmlError error; + error.setDescription("Slot declarations must be parameterless"); + error.setLine(funDecl->lparenToken.startLine); + error.setColumn(funDecl->lparenToken.startColumn); + _parser->_errors << error; + return false; + } + + QString body = textAt(funDecl->lbraceToken, funDecl->rbraceToken); + Object::DynamicSlot slot; + slot.name = funDecl->name->asString().toUtf8(); + slot.body = body; + obj->dynamicSlots << slot; + } else { + QmlError error; + error.setDescription("JavaScript declaration outside Script element"); + error.setLine(node->firstSourceLocation().startLine); + error.setColumn(node->firstSourceLocation().startColumn); + _parser->_errors << error; + } + return false; - obj->getDefaultProperty()->addValue(value); + } else { + QString source; + + int line = 0; + if (AST::FunctionDeclaration *funDecl = AST::cast(node->sourceElement)) { + line = funDecl->functionToken.startLine; + source = asString(funDecl); + } else if (AST::VariableStatement *varStmt = AST::cast(node->sourceElement)) { + // ignore variable declarations + line = varStmt->declarationKindToken.startLine; + } + + Value *value = new Value; + value->primitive = source; + value->line = line; + + obj->getDefaultProperty()->addValue(value); + } return false; } -- cgit v0.12 From f39ccc5ed802ee8461122b8b067c8faa9aae8f8a Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 15:27:04 +1000 Subject: QtScript must respect dynamic metaobject's when installed --- src/script/qscriptextqobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/qscriptextqobject.cpp b/src/script/qscriptextqobject.cpp index 4522807..802653a 100644 --- a/src/script/qscriptextqobject.cpp +++ b/src/script/qscriptextqobject.cpp @@ -736,7 +736,7 @@ static void callQtMethod(QScriptContextPrivate *context, QMetaMethod::MethodType meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params); } else { Q_ASSERT(thisQObject != 0); - thisQObject->qt_metacall(QMetaObject::InvokeMetaMethod, chosenIndex, params); + QMetaObject::metacall(thisQObject, QMetaObject::InvokeMetaMethod, chosenIndex, params); } if (scriptable) -- cgit v0.12 From 132830854a1b547666c1c65c7db1c6c089399637 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 5 May 2009 15:35:38 +1000 Subject: More doc conversion and cleanup. --- doc/src/declarative/anchor-layout.qdoc | 30 +++---- doc/src/declarative/animation.qdoc | 126 ++++++++++++++++++++--------- doc/src/declarative/basictypes.qdoc | 46 +++++------ doc/src/declarative/binding.qdoc | 20 ++--- doc/src/declarative/components.qdoc | 42 +++++++--- doc/src/declarative/cppitem.qdoc | 2 +- src/declarative/fx/qfxflipable.cpp | 4 +- src/declarative/fx/qfximage.cpp | 4 +- src/declarative/fx/qfxitem.cpp | 2 +- src/declarative/fx/qfxparticles.cpp | 18 ++--- src/declarative/fx/qfxreflectionfilter.cpp | 12 +-- src/declarative/fx/qfxshadowfilter.cpp | 2 +- src/declarative/fx/qfxtransform.cpp | 12 +-- 13 files changed, 191 insertions(+), 129 deletions(-) diff --git a/doc/src/declarative/anchor-layout.qdoc b/doc/src/declarative/anchor-layout.qdoc index 2b1f081..9ff902ee 100644 --- a/doc/src/declarative/anchor-layout.qdoc +++ b/doc/src/declarative/anchor-layout.qdoc @@ -10,8 +10,8 @@ In additional to the more traditional Fx layouts GridLayout, HorizontalLayout, a The Fx anchoring system allows you to define relationships between the anchor lines of different items. For example, you can write: \code - - +Rect { id: rect1; ... } +Rect { id: rect2; anchors.left: rect1.right; ... } \endcode In this case, the left edge of \e rect2 is bound to the right edge of rect1, producing the following: @@ -25,8 +25,8 @@ The anchoring system also allows you to specify margins and offsets. Margins spe The following example specifies a left margin: \code - - +Rect { id: rect1; ... } +Rect { id: rect2; anchors.left: rect1.right; anchors.leftMargin: 5; ... } \endcode In this case, a margin of 5 pixels is reserved to the left of \e rect2, producing the following: @@ -36,8 +36,8 @@ In this case, a margin of 5 pixels is reserved to the left of \e rect2, producin You can specify multiple anchors. For example: \code - - +Rect { id: rect1; ... } +Rect { id: rect2; anchors.left: rect1.right; anchors.top: rect1.bottom; ... } \endcode \image edge3.png @@ -45,9 +45,9 @@ You can specify multiple anchors. For example: By specifying multiple horizontal or vertical anchors you can control the size of an item. For example: \code - - - +Rect { id: rect1; x: 0; ... } +Rect { id: rect2; anchors.left: rect1.right; anchors.right: rect3.left; ... } +Rect { id: rect3; x: 150; ... } \endcode \image edge4.png @@ -57,12 +57,12 @@ By specifying multiple horizontal or vertical anchors you can control the size o For performance reasons, you can only anchor an item to its siblings and direct parent. For example, the following anchor would be considered invalid and would produce a warning: \code - - - - - - +Item { id: group1 } + Rect { id: rect1; ... } +} +Item id: group2"> + Rect { id: rect2; anchors.left: rect1.right; ... } // invalid anchor! +} \endcode */ diff --git a/doc/src/declarative/animation.qdoc b/doc/src/declarative/animation.qdoc index cd7d1b9..fb14fdc 100644 --- a/doc/src/declarative/animation.qdoc +++ b/doc/src/declarative/animation.qdoc @@ -29,19 +29,30 @@ The simplest form of animation is using \c <NumericAnimation/> The following example creates a bouncing effect: \code - - - - - - - - - - +Rect { + id: rect + width: 120 + height: 200 + color: "white" + Image { + id: img + source: "pics/qtlogo.png" + x: 60-img.width/2 + y: 200-img.height + y: SequentialAnimation { + running: true + repeat: true + NumericAnimation { + to: 200-img.height + easing: "easeOutBounce(amplitude:100)" + duration: 2000 + } + PauseAnimation { + duration: 1000 + } + } + } +} \endcode \image propanim.gif @@ -76,15 +87,28 @@ In QML: The following example shows a simple use of states. In the default state \c myrect is positioned at 0,0. In the 'moved' state it is positioned at 50,50. \code - - - - - - - - - +Item { + Rect { + id: myrect + width: 100 + height: 100 + } + states: [ + State { + name: "moved" + SetProperty { + target: myrect + property: "x" + value: 50 + } + SetProperty { + target: myrect + property: "y" + value: 50 + } + } + ] +} \endcode \section2 Transitions @@ -94,34 +118,56 @@ QML transitions describe animations to perform when state changes occur. For the previous example, a transition could describe how \c myrect moved from its initial position to its new position: \code - - - - - +transitions: [ + Transition { + NumericAnimation { + properties: "x,y" + easing: "easeOutBounce" + duration: 200 + } + } +] \endcode QML transitions can use selectors to determine which state changes a transition should apply to: \code - -... - +Transition { + fromState: "*" + toState: "Details" + ... +} \endcode Transitions can happen in parallel, in sequence, or in any combination of the two:; \code - - - - - - - - - - +Transition { + fromState: "*" + toState: "MyState" + reversible: true + SequentialAnimation { + ColorAnimation { + duration: 1000 + } + PauseAnimation { + duration: 1000 + } + ParallelAnimation { + NumericAnimation { + duration: 1000 + easing: "easeOutBounce" + target: box1 + properties: "x,y" + } + NumericAnimation { + duration: 1000 + target: box2 + properties: "x,y" + } + } + } +} \endcode \section1 Property Behaviors diff --git a/doc/src/declarative/basictypes.qdoc b/doc/src/declarative/basictypes.qdoc index 0000c37..f7eee50 100644 --- a/doc/src/declarative/basictypes.qdoc +++ b/doc/src/declarative/basictypes.qdoc @@ -23,7 +23,7 @@ Setting ints looks like this: \code - + Item { width: 100; height:200 } \endcode \target basicqmlbool @@ -39,7 +39,7 @@ Setting bools looks like this: \code - + Item { focusable: true; clip: false } \endcode \note Technically bool treats an empty string, "false" and "0" as false and @@ -58,7 +58,7 @@ Setting reals looks like this: \code - + Item { x: -10; y: 100.8 } \endcode \note In QML all reals are stored in single precision, \l {http://en.wikipedia.org/wiki/IEEE_754}{IEEE floating point} format. @@ -76,7 +76,7 @@ Setting a string looks like this: \code - + Text { text: "Hello world!" } \endcode \raw HTML @@ -101,9 +101,9 @@ Setting a color looks like this: \code - - - + Rect { color: "steelblue" } + Rect { color: "#FF0000" } + Rect { color: "#800000FF" } \endcode \target basicqmlpoint @@ -118,7 +118,7 @@ Setting a point looks like this: \code - + Widget { pos: "50,50" } \endcode \target basicqmlsize @@ -133,7 +133,7 @@ Setting a size looks like this: \code - + Widget { size: "50x50" } \endcode \target basicqmlrectangle @@ -148,7 +148,7 @@ Setting a rectangle looks like this: \code - + Widget { geometry: "50,50,100x100" } \endcode \target basicqmldate @@ -163,7 +163,7 @@ Setting a date looks like this: \code - + DatePicker { minDate: "2000-01-01"; maxDate: "2020-12-31" } \endcode \target basicqmltime @@ -178,7 +178,7 @@ Setting a time looks like this: \code - + TimePicker { time: "14:22:15" } \endcode \target basicqmlfont @@ -199,7 +199,7 @@ Setting a font looks like this: \code - + Text { font.family: "Helvetica"; font.size: 13; font.bold: true } \endcode \target basicqmlaction @@ -220,9 +220,9 @@ Actions are used like this: \code - - - + MouseRegion { onClicked: someitem.someaction.trigger() } + State { name: "enabled"; when: someitem.someaction.enabled=='true' } + Text { text: someitem.someaction.text } \endcode \target basicqmlany @@ -252,13 +252,13 @@ For example, the \l Item class has a children list property that can be used like this: \code - - - - - - - + Item { + children [ + Item { id: child1 }, + Rect { id: child2 }, + Text { id: child3 } + ] + } \endcode \c child1, \c child2 and \c child3 will all be added to the children list in the order in which they appear. diff --git a/doc/src/declarative/binding.qdoc b/doc/src/declarative/binding.qdoc index 1d4f9a1..2920d51 100644 --- a/doc/src/declarative/binding.qdoc +++ b/doc/src/declarative/binding.qdoc @@ -5,23 +5,23 @@ Data binding provides a declarative way of specifying the data associated with objects, as well as the relationship between data of different objects. For example, you could bind the text of a label to the value of a slider: as the value of the slider changed, the label would be automatically updated with the new value. -Bindings are indicated in Qml through the use of brackets: \c {}. For example, the following produces two Rects of equal size (\c rect2 is bound to the size of \c rect1): +Bindings are created in Qml when an expression is assigned to a property. For example, the following produces two Rects of equal size (\c rect2 is bound to the size of \c rect1): \code - - +Rect { id: rect1; width: 100; height: 100 } +Rect { id: rect2; width: rect1.width; height: rect1.height } \endcode -There is also a special \c element, which is typically used to bind from the UI to the underlying UI model (see \l {Passing Data Between C++ and Qml} for an example of this). The bindings above could be expressed using the \c element as: +There is also a special \l Bind element, which is typically used to bind from the UI to the underlying UI model (see \l {Passing Data Between C++ and Qml} for an example of this). The bindings above could be expressed using the \l Bind element as: \code - - +Bind { target: rect2; property: "width"; value: rect1.width } +Bind { target: rect2; property: "height"; value: rect1.height } \endcode In addition to binding directly to a property, you can also bind to the results of expressions involving properties. For example: \code - - +Text { text: contact.firstname + ' ' + contact.lastname } +Image { source: if (contact.gender == "female") {"pics/female.png"} else {"pics/male.png"} } \endcode Relevant items can also be bound to the contents of a model - see \l ListView for an example of this. @@ -101,8 +101,8 @@ view->execute(); Finally, in Qml you can make the appropriate bindings, so in \c "MyUI.qml": \code - - +Slider { value: screen.brightness } +Bind { target: screen; property: "brightness"; value: slider.value } \endcode The \l QBindableMap class provides a convenient way to make data visible to the bind engine. diff --git a/doc/src/declarative/components.qdoc b/doc/src/declarative/components.qdoc index 9a6f2dd..db59b61 100644 --- a/doc/src/declarative/components.qdoc +++ b/doc/src/declarative/components.qdoc @@ -23,10 +23,18 @@ 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: @@ -36,12 +44,20 @@ For the next release, you plan to add 'Cancel' and 'Reset' buttons. Rather than \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. @@ -49,11 +65,11 @@ The \a label property and \a click signal that were added effectively become par \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 diff --git a/doc/src/declarative/cppitem.qdoc b/doc/src/declarative/cppitem.qdoc index 959bc6d..534b32b 100644 --- a/doc/src/declarative/cppitem.qdoc +++ b/doc/src/declarative/cppitem.qdoc @@ -76,7 +76,7 @@ For example: QML_DECLARE_TYPE(MyCircle); QML_DEFINE_TYPE(MyCircle,Circle); \endcode -would make the \e MyCircle class accessable though the \c tag in QML. +would make the \e MyCircle class accessable though the \c Circle type in QML. \section1 Creating a new 'Fx' item in C++ diff --git a/src/declarative/fx/qfxflipable.cpp b/src/declarative/fx/qfxflipable.cpp index db390d2..24ae428 100644 --- a/src/declarative/fx/qfxflipable.cpp +++ b/src/declarative/fx/qfxflipable.cpp @@ -80,8 +80,8 @@ Flipable { endX: 20 endY: 40 } - front: Image { src: "front.png" } - back: Image { src: "back.png" } + front: Image { source: "front.png" } + back: Image { source: "back.png" } states: [ State { name: "back" diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp index 53c6137..838da30 100644 --- a/src/declarative/fx/qfximage.cpp +++ b/src/declarative/fx/qfximage.cpp @@ -203,8 +203,8 @@ QFxScaleGrid *QFxImage::scaleGrid() \qml Item { Image { source: "tile.png" } - Image { x: 80; width: 100; height: 100; src: "tile.png" } - Image { x: 190; width: 100; height: 100; tile: true; src: "tile.png" } + Image { x: 80; width: 100; height: 100; source: "tile.png" } + Image { x: 190; width: 100; height: 100; tile: true; source: "tile.png" } } \endqml \image declarative-image_tile.png diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index 84dc484..ecc2d65 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -448,7 +448,7 @@ QFxItem::~QFxItem() This example scales an image about its center. \qml Image { - src: "myimage.png" + source: "myimage.png" transformOrigin: "Center" scale: 4 } diff --git a/src/declarative/fx/qfxparticles.cpp b/src/declarative/fx/qfxparticles.cpp index 45de1a3..0ac537a 100644 --- a/src/declarative/fx/qfxparticles.cpp +++ b/src/declarative/fx/qfxparticles.cpp @@ -251,7 +251,7 @@ Rect { y: 0 width: parent.width height: 30 - src: "star.png" + source: "star.png" lifeSpan: 5000 count: 50 angle: 70 @@ -543,7 +543,7 @@ Rect { y: 0 width: parent.width height: 30 - src: "star.png" + source: "star.png" lifeSpan: 5000 count: 50 angle: 70 @@ -560,7 +560,7 @@ Rect { x: 120 width: 1 height: 1 - src: "star.png" + source: "star.png" lifeSpan: 5000 count: 200 angle: 270 @@ -698,7 +698,7 @@ void QFxParticles::setCount(int cnt) \qml Particles { - src: "star.png" + source: "star.png" lifeSpan: 200 lifeSpanDeviation: 100 } @@ -735,7 +735,7 @@ void QFxParticles::setLifeSpan(int ls) \qml Particles { - src: "star.png" + source: "star.png" lifeSpan: 200 lifeSpanDeviation: 100 } @@ -813,7 +813,7 @@ void QFxParticles::setFadeOutDuration(int dur) \qml Particles { - src: "star.png" + source: "star.png" angle: 60 angleDeviation: 90 } @@ -848,7 +848,7 @@ void QFxParticles::setAngle(qreal angle) \qml Particles { - src: "star.png" + source: "star.png" angle: 60 angleDeviation: 90 } @@ -880,7 +880,7 @@ void QFxParticles::setAngleDeviation(qreal dev) \qml Particles { - src: "star.png" + source: "star.png" velocity: 50 velocityDeviation: 20 } @@ -915,7 +915,7 @@ void QFxParticles::setVelocity(qreal velocity) \qml Particles { - src: "star.png" + source: "star.png" velocity: 50 velocityDeviation: 20 } diff --git a/src/declarative/fx/qfxreflectionfilter.cpp b/src/declarative/fx/qfxreflectionfilter.cpp index a55f374..0bc01a7 100644 --- a/src/declarative/fx/qfxreflectionfilter.cpp +++ b/src/declarative/fx/qfxreflectionfilter.cpp @@ -72,23 +72,23 @@ public: \qml HorizontalLayout { Image { - src: "icon.png" + source: "icon.png" filter: Reflection { } } Image { - src: "icon.png" + source: "icon.png" filter: Reflection { offset: 1 } } Image { - src: "icon.png" + source: "icon.png" filter: Reflection { offset: 1; alpha: 0.5 } } Image { - src: "icon.png" + source: "icon.png" filter: Reflection { offset: 1; alpha: 0.5; height: 50 } } Image { - src: "icon.png" + source: "icon.png" filter: Reflection { offset: 1; alpha: 0.5; height: 50; scale: 0.5 } } } @@ -147,7 +147,7 @@ void QFxReflectionFilter::setAlpha(qreal a) \qml Image { id: myImage - src: "album.png" + source: "album.png" filter: Reflection { height: myImage.height * 0.5 } diff --git a/src/declarative/fx/qfxshadowfilter.cpp b/src/declarative/fx/qfxshadowfilter.cpp index 4d34f74..83c1b47 100644 --- a/src/declarative/fx/qfxshadowfilter.cpp +++ b/src/declarative/fx/qfxshadowfilter.cpp @@ -86,7 +86,7 @@ Rect { } Image { - src: "pics/qtlogo.png" + source: "pics/qtlogo.png" filter: Shadow { yOffset: 8 xOffset: 8 diff --git a/src/declarative/fx/qfxtransform.cpp b/src/declarative/fx/qfxtransform.cpp index 1fe02d1..71ca716 100644 --- a/src/declarative/fx/qfxtransform.cpp +++ b/src/declarative/fx/qfxtransform.cpp @@ -322,7 +322,7 @@ void QFxRotation3D::update() The following example translates the image to 10, 3. \qml Image { - src: "logo.png" + source: "logo.png" transform: [ Translation3D { axis.startX: 0 @@ -520,9 +520,9 @@ QMatrix4x4 QFxPerspective::transform() const HorizontalLayout { margin: 10 spacing: 10 - Image { src: "qt.png" } + Image { source: "qt.png" } Image { - src: "qt.png" + source: "qt.png" transform: Squish { x:0; y:0; width:60; height:60 topLeftX:0; topLeftY:0 @@ -532,7 +532,7 @@ QMatrix4x4 QFxPerspective::transform() const } } Image { - src: "qt.png" + source: "qt.png" transform: Squish { x:0; y:0; width:60; height:60 topLeftX:0; topLeftY:0 @@ -542,7 +542,7 @@ QMatrix4x4 QFxPerspective::transform() const } } Image { - src: "qt.png" + source: "qt.png" transform: Squish { x:0; y:0; width:60; height:60 topLeftX:0; topLeftY:10 @@ -552,7 +552,7 @@ QMatrix4x4 QFxPerspective::transform() const } } Image { - src: "qt.png" + source: "qt.png" transform: Squish { x:0; y:0; width:60; height:60 topLeftX:10; topLeftY:0 -- cgit v0.12 From d1bb572b9fb5b0286df992c8ae560d91c9dc3388 Mon Sep 17 00:00:00 2001 From: Ian Walters Date: Tue, 5 May 2009 15:46:31 +1000 Subject: Rename QFxImageItem to QFxPaintedItem. Done to avoid confusion with QFxImage and QFxAnimatedImage(Item) --- src/declarative/fx/fx.pri | 6 +- src/declarative/fx/qfximageitem.cpp | 346 ---------------------------------- src/declarative/fx/qfximageitem.h | 100 ---------- src/declarative/fx/qfximageitem_p.h | 95 ---------- src/declarative/fx/qfxpainteditem.cpp | 346 ++++++++++++++++++++++++++++++++++ src/declarative/fx/qfxpainteditem.h | 97 ++++++++++ src/declarative/fx/qfxpainteditem_p.h | 95 ++++++++++ src/declarative/fx/qfxtextedit.cpp | 20 +- src/declarative/fx/qfxtextedit.h | 4 +- src/declarative/fx/qfxtextedit_p.h | 4 +- src/declarative/fx/qfxwebview.cpp | 26 +-- src/declarative/fx/qfxwebview.h | 4 +- 12 files changed, 570 insertions(+), 573 deletions(-) delete mode 100644 src/declarative/fx/qfximageitem.cpp delete mode 100644 src/declarative/fx/qfximageitem.h delete mode 100644 src/declarative/fx/qfximageitem_p.h create mode 100644 src/declarative/fx/qfxpainteditem.cpp create mode 100644 src/declarative/fx/qfxpainteditem.h create mode 100644 src/declarative/fx/qfxpainteditem_p.h diff --git a/src/declarative/fx/fx.pri b/src/declarative/fx/fx.pri index 7e04459..90820fa 100644 --- a/src/declarative/fx/fx.pri +++ b/src/declarative/fx/fx.pri @@ -17,8 +17,8 @@ HEADERS += \ fx/qfxgridview.h \ fx/qfxhighlightfilter.h \ fx/qfximage.h \ - fx/qfximageitem.h \ - fx/qfximageitem_p.h \ + fx/qfxpainteditem.h \ + fx/qfxpainteditem_p.h \ fx/qfximage_p.h \ fx/qfxitem.h \ fx/qfxitem_p.h \ @@ -65,7 +65,7 @@ SOURCES += \ fx/qfxgridview.cpp \ fx/qfxhighlightfilter.cpp \ fx/qfximage.cpp \ - fx/qfximageitem.cpp \ + fx/qfxpainteditem.cpp \ fx/qfxitem.cpp \ fx/qfxkeyactions.cpp \ fx/qfxkeyproxy.cpp \ diff --git a/src/declarative/fx/qfximageitem.cpp b/src/declarative/fx/qfximageitem.cpp deleted file mode 100644 index d751845..0000000 --- a/src/declarative/fx/qfximageitem.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -#include "qfximageitem.h" -#include "qfximageitem_p.h" - -#include -#include -#include -#include -#include -#include - -#if defined(QFX_RENDER_OPENGL2) -#include -#include -#endif - -QT_BEGIN_NAMESPACE - -/*! - \class QFxImageItem - \brief The QFxImageItem class is an abstract base class for QFxView items that want cached painting. - \ingroup group_coreitems - - This is a convenience class allowing easy use of cached painting within a custom - item. The contents of the item are are cached behind the scenes. - The dirtyCache() function should be called if the contents change to - ensure the cache is refreshed the next time painting occurs. - - To subclass QFxImageItem, you must reimplement drawContents() to draw - the contents of the item. -*/ - -/*! - \fn void QFxImageItem::drawContents(QPainter *painter, const QRect &rect) - - This function is called when the cache needs to be refreshed. When - sub-classing QFxImageItem this function should be implemented so as to - paint the contents of the item using the given \a painter for the - area of the contents specified by \a rect. -*/ - -/*! - \property QFxImageItem::contentsSize - \brief The size of the contents - - The contents size is the size of the item in regards to how it is painted - using the drawContents() function. This is distinct from the size of the - item in regards to height() and width(). -*/ - -/*! - \property QFxImageItem::smooth - \brief Setting for whether smooth scaling is enabled. -*/ - -/*! - Marks areas of the cache that intersect with the given \a rect as dirty and - in need of being refreshed. - - \sa clearCache() -*/ -void QFxImageItem::dirtyCache(const QRect& rect) -{ - Q_D(QFxImageItem); - for (int i=0; i < d->imagecache.count(); ) { - if (d->imagecache[i]->area.intersects(rect)) { - d->imagecache.removeAt(i); - } else { - ++i; - } - } -} - -/*! - Marks the entirety of the contents cache as dirty. - - \sa dirtyCache() -*/ -void QFxImageItem::clearCache() -{ - Q_D(QFxImageItem); - qDeleteAll(d->imagecache); - d->imagecache.clear(); -} - -/*! - Returns if smooth scaling of the cache contents is enabled. - - \sa setSmooth() -*/ -bool QFxImageItem::isSmooth() const -{ - Q_D(const QFxImageItem); - return d->smooth; -} - -/*! - Returns the size of the contents. - - \sa setContentsSize() -*/ -QSize QFxImageItem::contentsSize() const -{ - Q_D(const QFxImageItem); - return d->contentsSize; -} - -/*! - If \a smooth is true sets the image item to enable smooth scaling of - the cache contents. - - \sa isSmooth() -*/ -void QFxImageItem::setSmooth(bool smooth) -{ - Q_D(QFxImageItem); - if (d->smooth == smooth) return; - d->smooth = smooth; - clearCache(); - update(); -} - -/*! - Sets the size of the contents to the given \a size. - - \sa contentsSize() -*/ -void QFxImageItem::setContentsSize(const QSize &size) -{ - Q_D(QFxImageItem); - if (d->contentsSize == size) return; - d->contentsSize = size; - clearCache(); - update(); -} - -/*! - Constructs a new QFxImageItem with the given \a parent. -*/ -QFxImageItem::QFxImageItem(QFxItem *parent) - : QFxItem(*(new QFxImageItemPrivate), parent) -{ - init(); -} - -/*! - \internal - Constructs a new QFxImageItem with the given \a parent and - initialized private data member \a dd. -*/ -QFxImageItem::QFxImageItem(QFxImageItemPrivate &dd, QFxItem *parent) - : QFxItem(dd, parent) -{ - init(); -} - -/*! - Destroys the image item. -*/ -QFxImageItem::~QFxImageItem() -{ -} - -/*! - \internal -*/ -void QFxImageItem::init() -{ - connect(this,SIGNAL(widthChanged()),this,SLOT(clearCache())); - connect(this,SIGNAL(heightChanged()),this,SLOT(clearCache())); - connect(this,SIGNAL(visibleChanged()),this,SLOT(clearCache())); -} - -#if defined(QFX_RENDER_QPAINTER) -/*! - \reimp -*/ -void QFxImageItem::paintContents(QPainter &p) -#elif defined(QFX_RENDER_OPENGL) -/*! - \reimp -*/ -void QFxImageItem::paintGLContents(GLPainter &p) -#else -#error "What render?" -#endif -{ - Q_D(QFxImageItem); - const QRect content(QPoint(0,0),d->contentsSize); - if (content.width() <= 0 || content.height() <= 0) - return; - -#if defined(QFX_RENDER_QPAINTER) - bool oldAntiAliasing = p.testRenderHint(QPainter::Antialiasing); - bool oldSmoothPixmap = p.testRenderHint(QPainter::SmoothPixmapTransform); - if (d->smooth) { - p.setRenderHints(QPainter::Antialiasing, true); - p.setRenderHints(QPainter::SmoothPixmapTransform, true); - } - QRectF clipf = p.clipRegion().boundingRect(); - if (clipf.isEmpty()) - clipf = mapToScene(content); // ### Inefficient: Maps toScene and then fromScene - else - clipf = mapToScene(clipf); - -#elif defined(QFX_RENDER_OPENGL2) - p.useTextureShader(); - const QRectF clipf = p.sceneClipRect; - -#elif defined(QFX_RENDER_OPENGL1) - p.useTextureShader(); - const QRectF clipf = p.sceneClipRect; -#endif - - qreal hscale = widthValid() ? qreal(width()) / content.width() : heightValid() ? qreal(height()) / content.height() : 1.0; - qreal vscale = heightValid() ? qreal(height()) / content.height() : widthValid() ? qreal(width()) / content.width() : 1.0; - const QRect clip = mapFromScene(QRectF(clipf.x()/hscale,clipf.y()/vscale,clipf.width()/hscale,clipf.height()/vscale)).toRect(); - - QRegion topaint(clip); - topaint &= content; - QRegion uncached(content); - -#if defined(QFX_RENDER_OPENGL2) - glEnableVertexAttribArray(SingleTextureShader::Vertices); - glEnableVertexAttribArray(SingleTextureShader::TextureCoords); -#elif defined(QFX_RENDER_OPENGL1) - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); -#endif - - int cachesize=0; - for (int i=0; iimagecache.count(); ++i) { - QRect area = d->imagecache[i]->area; - if (topaint.contains(area)) { - QRectF target(area.x()*hscale, area.y()*vscale, area.width()*hscale, area.height()*vscale); - p.drawImage(target.toRect(), d->imagecache[i]->image); - topaint -= area; - d->imagecache[i]->age=0; - } else { - d->imagecache[i]->age++; - } - cachesize += area.width()*area.height(); - uncached -= area; - } - - if (!topaint.isEmpty()) { - // Find a sensible larger area, otherwise will paint lots of tiny images. - QRect biggerrect = topaint.boundingRect().adjusted(-64,-64,128,128); - cachesize += biggerrect.width() * biggerrect.height(); - while (d->imagecache.count() && cachesize > d->max_imagecache_size) { - int oldest=-1; - int age=-1; - for (int i=0; iimagecache.count(); ++i) { - int a = d->imagecache[i]->age; - if (a > age) { - oldest = i; - age = a; - } - } - cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height(); - uncached += d->imagecache[oldest]->area; - d->imagecache.removeAt(oldest); - } - const QRegion bigger = QRegion(biggerrect) & uncached; - const QVector rects = bigger.rects(); - for (int i = 0; i < rects.count(); ++i) { - const QRect &r = rects.at(i); -#if defined(QFX_RENDER_QPAINTER) - QImage img(r.size(),QImage::Format_ARGB32_Premultiplied); -#else - QImage img(r.size(),QImage::Format_ARGB32); -#endif - img.fill(0); - { - QPainter qp(&img); - qp.translate(-r.x(),-r.y()); - drawContents(&qp, r); - } - QFxImageItemPrivate::ImageCacheItem *newitem = new QFxImageItemPrivate::ImageCacheItem; - newitem->area = r; -#if defined(QFX_RENDER_QPAINTER) - newitem->image = QSimpleCanvasConfig::Image(QSimpleCanvasConfig::toImage(img)); -#else - newitem->image.setImage(img); -#endif - d->imagecache.append(newitem); - QRectF target(r.x()*hscale, r.y()*vscale, r.width()*hscale, r.height()*vscale); - p.drawImage(target.toRect(), newitem->image); - } - } -#if defined(QFX_RENDER_OPENGL2) - glDisableVertexAttribArray(SingleTextureShader::Vertices); - glDisableVertexAttribArray(SingleTextureShader::TextureCoords); -#elif defined(QFX_RENDER_OPENGL1) - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); -#endif -#if defined(QFX_RENDER_QPAINTER) - if (d->smooth) { - p.setRenderHints(QPainter::Antialiasing, oldAntiAliasing); - p.setRenderHints(QPainter::SmoothPixmapTransform, oldSmoothPixmap); - } -#endif -} - -QT_END_NAMESPACE diff --git a/src/declarative/fx/qfximageitem.h b/src/declarative/fx/qfximageitem.h deleted file mode 100644 index 9ffd44e..0000000 --- a/src/declarative/fx/qfximageitem.h +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -#ifndef QFXIMAGEITEM_H -#define QFXIMAGEITEM_H - -#include -#include - - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) -/* -WARNING: SHORT TERM CLASS. INTENDED TO MERGE INTO QFxPainted -*/ - -class QFxImageItemPrivate; -class Q_DECLARATIVE_EXPORT QFxImageItem : public QFxItem -{ - Q_OBJECT -public: - QFxImageItem(QFxItem *parent=0); - ~QFxImageItem(); - - Q_PROPERTY(QSize contentsSize READ contentsSize WRITE setContentsSize); - Q_PROPERTY(bool smooth READ isSmooth WRITE setSmooth); - -#if defined(QFX_RENDER_QPAINTER) - void paintContents(QPainter &painter); -#elif defined(QFX_RENDER_OPENGL) - void paintGLContents(GLPainter &); -#endif - - bool isSmooth() const; - QSize contentsSize() const; - - void setSmooth(bool); - void setContentsSize(const QSize &); -protected: - QFxImageItem(QFxImageItemPrivate &dd, QFxItem *parent); - - virtual void drawContents(QPainter *p, const QRect &) = 0; - -protected Q_SLOTS: - void dirtyCache(const QRect &); - void clearCache(); - -private: - void init(); - Q_DISABLE_COPY(QFxImageItem) - Q_DECLARE_PRIVATE(QFxImageItem) -}; -QML_DECLARE_TYPE(QFxImageItem); - - -QT_END_NAMESPACE - -QT_END_HEADER -#endif diff --git a/src/declarative/fx/qfximageitem_p.h b/src/declarative/fx/qfximageitem_p.h deleted file mode 100644 index 80450ec..0000000 --- a/src/declarative/fx/qfximageitem_p.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -#ifndef QFXIMAGEITEM_P_H -#define QFXIMAGEITEM_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qfxitem_p.h" -#include - -#if defined(QFX_RENDER_OPENGL) -#include "gltexture.h" -#endif - -QT_BEGIN_NAMESPACE - -class QFxImageItemPrivate : public QFxItemPrivate -{ - Q_DECLARE_PUBLIC(QFxImageItem) - -public: - QFxImageItemPrivate() - : max_imagecache_size(1000*1000), smooth(false) - { - } - - struct ImageCacheItem { - ImageCacheItem() : age(0) {} - ~ImageCacheItem() { } - int age; - QRect area; -#if defined(QFX_RENDER_QPAINTER) - QSimpleCanvasConfig::Image image; -#else - GLTexture image; -#endif - }; - - QList imagecache; - - const int max_imagecache_size; - bool smooth; - QSize contentsSize; -}; - -QT_END_NAMESPACE -#endif diff --git a/src/declarative/fx/qfxpainteditem.cpp b/src/declarative/fx/qfxpainteditem.cpp new file mode 100644 index 0000000..950b468 --- /dev/null +++ b/src/declarative/fx/qfxpainteditem.cpp @@ -0,0 +1,346 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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$ +** +****************************************************************************/ + +#include "qfxpainteditem.h" +#include "qfxpainteditem_p.h" + +#include +#include +#include +#include +#include +#include + +#if defined(QFX_RENDER_OPENGL2) +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QFxPaintedItem + \brief The QFxPaintedItem class is an abstract base class for QFxView items that want cached painting. + \ingroup group_coreitems + + This is a convenience class for implementing items that paint their contents + using a QPainter. The contents of the item are are cached behind the scenes. + The dirtyCache() function should be called if the contents change to + ensure the cache is refreshed the next time painting occurs. + + To subclass QFxPaintedItem, you must reimplement drawContents() to draw + the contents of the item. +*/ + +/*! + \fn void QFxPaintedItem::drawContents(QPainter *painter, const QRect &rect) + + This function is called when the cache needs to be refreshed. When + sub-classing QFxPaintedItem this function should be implemented so as to + paint the contents of the item using the given \a painter for the + area of the contents specified by \a rect. +*/ + +/*! + \property QFxPaintedItem::contentsSize + \brief The size of the contents + + The contents size is the size of the item in regards to how it is painted + using the drawContents() function. This is distinct from the size of the + item in regards to height() and width(). +*/ + +/*! + \property QFxPaintedItem::smooth + \brief Setting for whether smooth scaling is enabled. +*/ + +/*! + Marks areas of the cache that intersect with the given \a rect as dirty and + in need of being refreshed. + + \sa clearCache() +*/ +void QFxPaintedItem::dirtyCache(const QRect& rect) +{ + Q_D(QFxPaintedItem); + for (int i=0; i < d->imagecache.count(); ) { + if (d->imagecache[i]->area.intersects(rect)) { + d->imagecache.removeAt(i); + } else { + ++i; + } + } +} + +/*! + Marks the entirety of the contents cache as dirty. + + \sa dirtyCache() +*/ +void QFxPaintedItem::clearCache() +{ + Q_D(QFxPaintedItem); + qDeleteAll(d->imagecache); + d->imagecache.clear(); +} + +/*! + Returns if smooth scaling of the cache contents is enabled. + + \sa setSmooth() +*/ +bool QFxPaintedItem::isSmooth() const +{ + Q_D(const QFxPaintedItem); + return d->smooth; +} + +/*! + Returns the size of the contents. + + \sa setContentsSize() +*/ +QSize QFxPaintedItem::contentsSize() const +{ + Q_D(const QFxPaintedItem); + return d->contentsSize; +} + +/*! + If \a smooth is true sets the image item to enable smooth scaling of + the cache contents. + + \sa isSmooth() +*/ +void QFxPaintedItem::setSmooth(bool smooth) +{ + Q_D(QFxPaintedItem); + if (d->smooth == smooth) return; + d->smooth = smooth; + clearCache(); + update(); +} + +/*! + Sets the size of the contents to the given \a size. + + \sa contentsSize() +*/ +void QFxPaintedItem::setContentsSize(const QSize &size) +{ + Q_D(QFxPaintedItem); + if (d->contentsSize == size) return; + d->contentsSize = size; + clearCache(); + update(); +} + +/*! + Constructs a new QFxPaintedItem with the given \a parent. +*/ +QFxPaintedItem::QFxPaintedItem(QFxItem *parent) + : QFxItem(*(new QFxPaintedItemPrivate), parent) +{ + init(); +} + +/*! + \internal + Constructs a new QFxPaintedItem with the given \a parent and + initialized private data member \a dd. +*/ +QFxPaintedItem::QFxPaintedItem(QFxPaintedItemPrivate &dd, QFxItem *parent) + : QFxItem(dd, parent) +{ + init(); +} + +/*! + Destroys the image item. +*/ +QFxPaintedItem::~QFxPaintedItem() +{ +} + +/*! + \internal +*/ +void QFxPaintedItem::init() +{ + connect(this,SIGNAL(widthChanged()),this,SLOT(clearCache())); + connect(this,SIGNAL(heightChanged()),this,SLOT(clearCache())); + connect(this,SIGNAL(visibleChanged()),this,SLOT(clearCache())); +} + +#if defined(QFX_RENDER_QPAINTER) +/*! + \reimp +*/ +void QFxPaintedItem::paintContents(QPainter &p) +#elif defined(QFX_RENDER_OPENGL) +/*! + \reimp +*/ +void QFxPaintedItem::paintGLContents(GLPainter &p) +#else +#error "What render?" +#endif +{ + Q_D(QFxPaintedItem); + const QRect content(QPoint(0,0),d->contentsSize); + if (content.width() <= 0 || content.height() <= 0) + return; + +#if defined(QFX_RENDER_QPAINTER) + bool oldAntiAliasing = p.testRenderHint(QPainter::Antialiasing); + bool oldSmoothPixmap = p.testRenderHint(QPainter::SmoothPixmapTransform); + if (d->smooth) { + p.setRenderHints(QPainter::Antialiasing, true); + p.setRenderHints(QPainter::SmoothPixmapTransform, true); + } + QRectF clipf = p.clipRegion().boundingRect(); + if (clipf.isEmpty()) + clipf = mapToScene(content); // ### Inefficient: Maps toScene and then fromScene + else + clipf = mapToScene(clipf); + +#elif defined(QFX_RENDER_OPENGL2) + p.useTextureShader(); + const QRectF clipf = p.sceneClipRect; + +#elif defined(QFX_RENDER_OPENGL1) + p.useTextureShader(); + const QRectF clipf = p.sceneClipRect; +#endif + + qreal hscale = widthValid() ? qreal(width()) / content.width() : heightValid() ? qreal(height()) / content.height() : 1.0; + qreal vscale = heightValid() ? qreal(height()) / content.height() : widthValid() ? qreal(width()) / content.width() : 1.0; + const QRect clip = mapFromScene(QRectF(clipf.x()/hscale,clipf.y()/vscale,clipf.width()/hscale,clipf.height()/vscale)).toRect(); + + QRegion topaint(clip); + topaint &= content; + QRegion uncached(content); + +#if defined(QFX_RENDER_OPENGL2) + glEnableVertexAttribArray(SingleTextureShader::Vertices); + glEnableVertexAttribArray(SingleTextureShader::TextureCoords); +#elif defined(QFX_RENDER_OPENGL1) + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +#endif + + int cachesize=0; + for (int i=0; iimagecache.count(); ++i) { + QRect area = d->imagecache[i]->area; + if (topaint.contains(area)) { + QRectF target(area.x()*hscale, area.y()*vscale, area.width()*hscale, area.height()*vscale); + p.drawImage(target.toRect(), d->imagecache[i]->image); + topaint -= area; + d->imagecache[i]->age=0; + } else { + d->imagecache[i]->age++; + } + cachesize += area.width()*area.height(); + uncached -= area; + } + + if (!topaint.isEmpty()) { + // Find a sensible larger area, otherwise will paint lots of tiny images. + QRect biggerrect = topaint.boundingRect().adjusted(-64,-64,128,128); + cachesize += biggerrect.width() * biggerrect.height(); + while (d->imagecache.count() && cachesize > d->max_imagecache_size) { + int oldest=-1; + int age=-1; + for (int i=0; iimagecache.count(); ++i) { + int a = d->imagecache[i]->age; + if (a > age) { + oldest = i; + age = a; + } + } + cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height(); + uncached += d->imagecache[oldest]->area; + d->imagecache.removeAt(oldest); + } + const QRegion bigger = QRegion(biggerrect) & uncached; + const QVector rects = bigger.rects(); + for (int i = 0; i < rects.count(); ++i) { + const QRect &r = rects.at(i); +#if defined(QFX_RENDER_QPAINTER) + QImage img(r.size(),QImage::Format_ARGB32_Premultiplied); +#else + QImage img(r.size(),QImage::Format_ARGB32); +#endif + img.fill(0); + { + QPainter qp(&img); + qp.translate(-r.x(),-r.y()); + drawContents(&qp, r); + } + QFxPaintedItemPrivate::ImageCacheItem *newitem = new QFxPaintedItemPrivate::ImageCacheItem; + newitem->area = r; +#if defined(QFX_RENDER_QPAINTER) + newitem->image = QSimpleCanvasConfig::Image(QSimpleCanvasConfig::toImage(img)); +#else + newitem->image.setImage(img); +#endif + d->imagecache.append(newitem); + QRectF target(r.x()*hscale, r.y()*vscale, r.width()*hscale, r.height()*vscale); + p.drawImage(target.toRect(), newitem->image); + } + } +#if defined(QFX_RENDER_OPENGL2) + glDisableVertexAttribArray(SingleTextureShader::Vertices); + glDisableVertexAttribArray(SingleTextureShader::TextureCoords); +#elif defined(QFX_RENDER_OPENGL1) + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +#endif +#if defined(QFX_RENDER_QPAINTER) + if (d->smooth) { + p.setRenderHints(QPainter::Antialiasing, oldAntiAliasing); + p.setRenderHints(QPainter::SmoothPixmapTransform, oldSmoothPixmap); + } +#endif +} + +QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxpainteditem.h b/src/declarative/fx/qfxpainteditem.h new file mode 100644 index 0000000..015a035 --- /dev/null +++ b/src/declarative/fx/qfxpainteditem.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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$ +** +****************************************************************************/ + +#ifndef QFXIMAGEITEM_H +#define QFXIMAGEITEM_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QFxPaintedItemPrivate; +class Q_DECLARATIVE_EXPORT QFxPaintedItem : public QFxItem +{ + Q_OBJECT +public: + QFxPaintedItem(QFxItem *parent=0); + ~QFxPaintedItem(); + + Q_PROPERTY(QSize contentsSize READ contentsSize WRITE setContentsSize); + Q_PROPERTY(bool smooth READ isSmooth WRITE setSmooth); + +#if defined(QFX_RENDER_QPAINTER) + void paintContents(QPainter &painter); +#elif defined(QFX_RENDER_OPENGL) + void paintGLContents(GLPainter &); +#endif + + bool isSmooth() const; + QSize contentsSize() const; + + void setSmooth(bool); + void setContentsSize(const QSize &); +protected: + QFxPaintedItem(QFxPaintedItemPrivate &dd, QFxItem *parent); + + virtual void drawContents(QPainter *p, const QRect &) = 0; + +protected Q_SLOTS: + void dirtyCache(const QRect &); + void clearCache(); + +private: + void init(); + Q_DISABLE_COPY(QFxPaintedItem) + Q_DECLARE_PRIVATE(QFxPaintedItem) +}; +QML_DECLARE_TYPE(QFxPaintedItem); + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/fx/qfxpainteditem_p.h b/src/declarative/fx/qfxpainteditem_p.h new file mode 100644 index 0000000..b0432ac --- /dev/null +++ b/src/declarative/fx/qfxpainteditem_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module 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$ +** +****************************************************************************/ + +#ifndef QFXIMAGEITEM_P_H +#define QFXIMAGEITEM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qfxitem_p.h" +#include + +#if defined(QFX_RENDER_OPENGL) +#include "gltexture.h" +#endif + +QT_BEGIN_NAMESPACE + +class QFxPaintedItemPrivate : public QFxItemPrivate +{ + Q_DECLARE_PUBLIC(QFxPaintedItem) + +public: + QFxPaintedItemPrivate() + : max_imagecache_size(1000*1000), smooth(false) + { + } + + struct ImageCacheItem { + ImageCacheItem() : age(0) {} + ~ImageCacheItem() { } + int age; + QRect area; +#if defined(QFX_RENDER_QPAINTER) + QSimpleCanvasConfig::Image image; +#else + GLTexture image; +#endif + }; + + QList imagecache; + + const int max_imagecache_size; + bool smooth; + QSize contentsSize; +}; + +QT_END_NAMESPACE +#endif diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 84e209b..a1b5484 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -103,7 +103,7 @@ TextEdit { Constructs a new QFxTextEdit. */ QFxTextEdit::QFxTextEdit(QFxItem *parent) -: QFxImageItem(*(new QFxTextEditPrivate), parent) +: QFxPaintedItem(*(new QFxTextEditPrivate), parent) { Q_D(QFxTextEdit); d->init(); @@ -113,7 +113,7 @@ QFxTextEdit::QFxTextEdit(QFxItem *parent) \internal */ QFxTextEdit::QFxTextEdit(QFxTextEditPrivate &dd, QFxItem *parent) - : QFxImageItem(dd, parent) + : QFxPaintedItem(dd, parent) { Q_D(QFxTextEdit); d->init(); @@ -383,7 +383,7 @@ void QFxTextEdit::geometryChanged(const QRectF &newGeometry, { if (newGeometry.width() != oldGeometry.width()) updateSize(); - QFxImageItem::geometryChanged(newGeometry, oldGeometry); + QFxPaintedItem::geometryChanged(newGeometry, oldGeometry); } /*! @@ -393,7 +393,7 @@ void QFxTextEdit::dump(int depth) { QByteArray ba(depth * 4, ' '); qWarning() << ba.constData() << propertyInfo(); - QFxImageItem::dump(depth); + QFxPaintedItem::dump(depth); } /*! @@ -412,7 +412,7 @@ QString QFxTextEdit::propertyInfo() const void QFxTextEdit::componentComplete() { Q_D(QFxTextEdit); - QFxImageItem::componentComplete(); + QFxPaintedItem::componentComplete(); if (d->dirty) { updateSize(); d->dirty = false; @@ -588,7 +588,7 @@ Handles the given focus \a event. void QFxTextEdit::focusInEvent(QFocusEvent *event) { Q_D(QFxTextEdit); - QFxImageItem::focusInEvent(event); + QFxPaintedItem::focusInEvent(event); d->control->processEvent(event, QPointF(0, 0)); } @@ -599,7 +599,7 @@ Handles the given focus \a event. void QFxTextEdit::focusOutEvent(QFocusEvent *event) { Q_D(QFxTextEdit); - QFxImageItem::focusOutEvent(event); + QFxPaintedItem::focusOutEvent(event); d->control->processEvent(event, QPointF(0, 0)); } @@ -638,7 +638,7 @@ void QFxTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(me->isAccepted()); delete me; if (!event->isAccepted()) - QFxImageItem::mousePressEvent(event); + QFxPaintedItem::mousePressEvent(event); } /*! @@ -653,7 +653,7 @@ void QFxTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(me->isAccepted()); delete me; if (!event->isAccepted()) - QFxImageItem::mousePressEvent(event); + QFxPaintedItem::mousePressEvent(event); } /*! @@ -668,7 +668,7 @@ void QFxTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(me->isAccepted()); delete me; if (!event->isAccepted()) - QFxImageItem::mousePressEvent(event); + QFxPaintedItem::mousePressEvent(event); } /*! diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h index be84a3c..b017635 100644 --- a/src/declarative/fx/qfxtextedit.h +++ b/src/declarative/fx/qfxtextedit.h @@ -43,7 +43,7 @@ #define QFXTEXTEDIT_H #include -#include +#include #include #include @@ -60,7 +60,7 @@ QT_MODULE(Declarative) WARNING: SHORT TERM CLASS. INTENDED TO MERGE INTO QFxTextItem */ class QFxTextEditPrivate; -class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxImageItem +class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxPaintedItem { Q_OBJECT Q_ENUMS(VAlignment) diff --git a/src/declarative/fx/qfxtextedit_p.h b/src/declarative/fx/qfxtextedit_p.h index aa07484..b583dbe 100644 --- a/src/declarative/fx/qfxtextedit_p.h +++ b/src/declarative/fx/qfxtextedit_p.h @@ -54,7 +54,7 @@ // #include "qfxitem.h" -#include "qfximageitem_p.h" +#include "qfxpainteditem_p.h" #include "qml.h" @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE class QTextLayout; class QTextDocument; class QTextControl; -class QFxTextEditPrivate : public QFxImageItemPrivate +class QFxTextEditPrivate : public QFxPaintedItemPrivate { Q_DECLARE_PUBLIC(QFxTextEdit) diff --git a/src/declarative/fx/qfxwebview.cpp b/src/declarative/fx/qfxwebview.cpp index 9b18a9e..3f05846 100644 --- a/src/declarative/fx/qfxwebview.cpp +++ b/src/declarative/fx/qfxwebview.cpp @@ -68,7 +68,7 @@ #include "qfxwebview.h" #include -#include +#include QT_BEGIN_NAMESPACE QML_DEFINE_TYPE(QFxWebView,WebView); @@ -142,13 +142,13 @@ public: }; -class QFxWebViewPrivate : public QFxImageItemPrivate +class QFxWebViewPrivate : public QFxPaintedItemPrivate { Q_DECLARE_PUBLIC(QFxWebView) public: QFxWebViewPrivate() - : QFxImageItemPrivate(), page(0), idealwidth(0), idealheight(0), interactive(true), lastPress(0), lastRelease(0), mouseX(0), mouseY(0), + : QFxPaintedItemPrivate(), page(0), idealwidth(0), idealheight(0), interactive(true), lastPress(0), lastRelease(0), mouseX(0), mouseY(0), max_imagecache_size(100000), progress(1.0), pending(PendingNone) { } @@ -253,13 +253,13 @@ public: */ QFxWebView::QFxWebView(QFxItem *parent) - : QFxImageItem(*(new QFxWebViewPrivate), parent) + : QFxPaintedItem(*(new QFxWebViewPrivate), parent) { init(); } QFxWebView::QFxWebView(QFxWebViewPrivate &dd, QFxItem *parent) - : QFxImageItem(dd, parent) + : QFxPaintedItem(dd, parent) { init(); } @@ -283,7 +283,7 @@ void QFxWebView::init() void QFxWebView::componentComplete() { - QFxImageItem::componentComplete(); + QFxPaintedItem::componentComplete(); Q_D(QFxWebView); switch (d->pending) { case QFxWebViewPrivate::PendingUrl: @@ -491,7 +491,7 @@ void QFxWebView::geometryChanged(const QRectF &newGeometry, { if (newGeometry.size() != oldGeometry.size()) expandToWebPage(); - QFxImageItem::geometryChanged(newGeometry, oldGeometry); + QFxPaintedItem::geometryChanged(newGeometry, oldGeometry); } void QFxWebView::paintPage(const QRect& r) @@ -554,7 +554,7 @@ void QFxWebView::dump(int depth) { QByteArray ba(depth * 4, ' '); qWarning() << ba.constData() << "url:" << url(); - QFxImageItem::dump(depth); + QFxPaintedItem::dump(depth); } void QFxWebView::drawContents(QPainter *p, const QRect &r) @@ -656,7 +656,7 @@ void QFxWebView::mousePressEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(false); } if (!event->isAccepted()) - QFxImageItem::mousePressEvent(event); + QFxPaintedItem::mousePressEvent(event); } void QFxWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) @@ -670,7 +670,7 @@ void QFxWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(false); } if (!event->isAccepted()) - QFxImageItem::mouseReleaseEvent(event); + QFxPaintedItem::mouseReleaseEvent(event); } void QFxWebView::mouseMoveEvent(QGraphicsSceneMouseEvent *event) @@ -691,7 +691,7 @@ void QFxWebView::mouseMoveEvent(QGraphicsSceneMouseEvent *event) event->setAccepted(false); } if (!event->isAccepted()) - QFxImageItem::mouseMoveEvent(event); + QFxPaintedItem::mouseMoveEvent(event); } void QFxWebView::keyPressEvent(QKeyEvent* event) @@ -700,7 +700,7 @@ void QFxWebView::keyPressEvent(QKeyEvent* event) if (d->interactive) page()->event(event); if (!event->isAccepted()) - QFxImageItem::keyPressEvent(event); + QFxPaintedItem::keyPressEvent(event); } void QFxWebView::keyReleaseEvent(QKeyEvent* event) @@ -709,7 +709,7 @@ void QFxWebView::keyReleaseEvent(QKeyEvent* event) if (d->interactive) page()->event(event); if (!event->isAccepted()) - QFxImageItem::keyReleaseEvent(event); + QFxPaintedItem::keyReleaseEvent(event); } /*! diff --git a/src/declarative/fx/qfxwebview.h b/src/declarative/fx/qfxwebview.h index 17037ca..afd5b0f 100644 --- a/src/declarative/fx/qfxwebview.h +++ b/src/declarative/fx/qfxwebview.h @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include @@ -74,7 +74,7 @@ private: }; -class Q_DECLARATIVE_EXPORT QFxWebView : public QFxImageItem +class Q_DECLARATIVE_EXPORT QFxWebView : public QFxPaintedItem { Q_OBJECT -- cgit v0.12 From 3a22e470165e990bc43a07529077372df53dcad4 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 15:49:32 +1000 Subject: Remove qmlconv --- tools/tools.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tools.pro b/tools/tools.pro index 2c83580..2ff0214 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -24,7 +24,7 @@ mac { SUBDIRS += kmap2qmap -contains(QT_CONFIG, declarative):SUBDIRS += qmlviewer qmlconv +contains(QT_CONFIG, declarative):SUBDIRS += qmlviewer contains(QT_CONFIG, dbus):SUBDIRS += qdbus !wince*:contains(QT_CONFIG, xmlpatterns): SUBDIRS += xmlpatterns embedded: SUBDIRS += makeqpf -- cgit v0.12 From 1b6e74a2bf4d4b1470e4e6447995cb286520f271 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 15:54:48 +1000 Subject: Very basic slot declaration support Currently only parameterless slots are supported. They are declared inline with the object: Rect { function mySlot() { print("Hello world!"); } } --- src/declarative/qml/qmlcompiler.cpp | 17 +++- src/declarative/qml/qmlcompiler_p.h | 2 +- src/declarative/qml/qmlinstruction.cpp | 2 +- src/declarative/qml/qmlinstruction_p.h | 1 + src/declarative/qml/qmlvme.cpp | 2 +- src/declarative/qml/qmlvmemetaobject.cpp | 132 +++++++++++++++++++------------ src/declarative/qml/qmlvmemetaobject_p.h | 6 +- 7 files changed, 106 insertions(+), 56 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index b8f3921..d4003ab 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -545,7 +545,7 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) create.create.type = obj->type; output->bytecode << create; - COMPILE_CHECK(compileDynamicPropertiesAndSignals(obj)); + COMPILE_CHECK(compileDynamicMeta(obj)); if (obj->type != -1) { if (output->types.at(obj->type).component) { @@ -1212,10 +1212,12 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, return true; } -bool QmlCompiler::compileDynamicPropertiesAndSignals(QmlParser::Object *obj) +bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) { // ### FIXME - Check that there is only one default property etc. - if (obj->dynamicProperties.isEmpty() && obj->dynamicSignals.isEmpty()) + if (obj->dynamicProperties.isEmpty() && + obj->dynamicSignals.isEmpty() && + obj->dynamicSlots.isEmpty()) return true; QMetaObjectBuilder builder; @@ -1263,6 +1265,14 @@ bool QmlCompiler::compileDynamicPropertiesAndSignals(QmlParser::Object *obj) builder.addSignal(s.name + "()"); } + int slotStart = obj->dynamicSlots.isEmpty()?-1:output->primitives.count(); + + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); + builder.addSlot(s.name + "()"); + output->primitives << s.body; + } + if (obj->metatype) builder.setSuperClass(obj->metatype); @@ -1272,6 +1282,7 @@ bool QmlCompiler::compileDynamicPropertiesAndSignals(QmlParser::Object *obj) QmlInstruction store; store.type = QmlInstruction::StoreMetaObject; store.storeMeta.data = output->mos.count() - 1; + store.storeMeta.slotData = slotStart; store.line = obj->line; output->bytecode << store; diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 4acdcfa..e2b8388 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -163,7 +163,7 @@ private: QmlParser::Value *value, int ctxt); - bool compileDynamicPropertiesAndSignals(QmlParser::Object *obj); + bool compileDynamicMeta(QmlParser::Object *obj); void compileBinding(const QString &, QmlParser::Property *prop, int ctxt, const QMetaObject *, qint64); diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 52677c2..0617913 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -68,7 +68,7 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) qWarning() << idx << "\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; break; case QmlInstruction::StoreMetaObject: - qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data; + qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data << "\t" << instr->storeMeta.slotData; break; case QmlInstruction::StoreReal: qWarning() << idx << "\t" << line << "\t" << "STORE_REAL\t\t" << instr->storeReal.propertyIndex << "\t" << instr->storeReal.value; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 462f9e4..01bdfdd 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -177,6 +177,7 @@ public: } create; struct { int data; + int slotData; } storeMeta; struct { int value; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index ad3d1d5..ee7a881 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -320,7 +320,7 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in QFxCompilerTimer cc; #endif QObject *target = stack.top(); - new QmlVMEMetaObject(target, mos.at(instr.storeMeta.data), comp); + new QmlVMEMetaObject(target, mos.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, comp); } break; diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index f7d2635..58708cf 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -44,13 +44,18 @@ #include #include #include +#include +#include +#include QT_BEGIN_NAMESPACE QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, - const QMetaObject *other, - QmlRefCount *rc) -: object(obj), ref(rc) + const QMetaObject *other, + QList *strData, + int slotData, + QmlRefCount *rc) +: object(obj), ref(rc), slotData(strData), slotDataIdx(slotData) { if (ref) ref->addref(); @@ -64,6 +69,7 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, data = new QVariant[propertyCount() - baseProp]; vTypes.resize(propertyCount() - baseProp); + // ### Optimize for (int ii = baseProp; ii < propertyCount(); ++ii) { QMetaProperty prop = property(ii); if ((int)prop.type() != -1) { @@ -72,6 +78,23 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, vTypes.setBit(ii - baseProp, true); } } + + baseSlot = -1; + slotCount = 0; + for (int ii = baseSig; ii < methodCount(); ++ii) { + QMetaMethod m = method(ii); + if (m.methodType() == QMetaMethod::Slot) { + if (baseSlot == -1) + baseSlot = ii; + } else { + if (baseSlot != -1) { + slotCount = ii - baseSlot; + break; + } + } + } + if(baseSlot != -1 && !slotCount) + slotCount = methodCount() - baseSlot; } QmlVMEMetaObject::~QmlVMEMetaObject() @@ -83,58 +106,69 @@ QmlVMEMetaObject::~QmlVMEMetaObject() int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int id, void **a) { - if (id >= baseProp) { - int propId = id - baseProp; - bool needActivate = false; + if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) { + if (id >= baseProp) { + int propId = id - baseProp; + bool needActivate = false; - if (vTypes.testBit(propId)) { - if (c == QMetaObject::ReadProperty) { - *reinterpret_cast(a[0]) = data[propId]; - } else if (c == QMetaObject::WriteProperty) { - needActivate = - (data[propId] != *reinterpret_cast(a[0])); - data[propId] = *reinterpret_cast(a[0]); - } - } else { - if (c == QMetaObject::ReadProperty) { - switch(data[propId].type()) { - case QVariant::Int: - *reinterpret_cast(a[0]) = data[propId].toInt(); - break; - case QVariant::Bool: - *reinterpret_cast(a[0]) = data[propId].toBool(); - break; - case QVariant::Double: - *reinterpret_cast(a[0]) = data[propId].toDouble(); - break; - case QVariant::String: - *reinterpret_cast(a[0]) = data[propId].toString(); - break; - case QVariant::Color: - *reinterpret_cast(a[0]) = data[propId].value(); - break; - case QVariant::Date: - *reinterpret_cast(a[0]) = data[propId].toDate(); - break; - default: - qFatal("Unknown type"); - break; + if (vTypes.testBit(propId)) { + if (c == QMetaObject::ReadProperty) { + *reinterpret_cast(a[0]) = data[propId]; + } else if (c == QMetaObject::WriteProperty) { + needActivate = + (data[propId] != *reinterpret_cast(a[0])); + data[propId] = *reinterpret_cast(a[0]); } - } else if (c == QMetaObject::WriteProperty) { + } else { + if (c == QMetaObject::ReadProperty) { + switch(data[propId].type()) { + case QVariant::Int: + *reinterpret_cast(a[0]) = data[propId].toInt(); + break; + case QVariant::Bool: + *reinterpret_cast(a[0]) = data[propId].toBool(); + break; + case QVariant::Double: + *reinterpret_cast(a[0]) = data[propId].toDouble(); + break; + case QVariant::String: + *reinterpret_cast(a[0]) = data[propId].toString(); + break; + case QVariant::Color: + *reinterpret_cast(a[0]) = data[propId].value(); + break; + case QVariant::Date: + *reinterpret_cast(a[0]) = data[propId].toDate(); + break; + default: + qFatal("Unknown type"); + break; + } + } else if (c == QMetaObject::WriteProperty) { - QVariant value = QVariant((QVariant::Type)data[propId].type(), a[0]); - needActivate = (data[propId] != value); - data[propId] = value; + QVariant value = QVariant((QVariant::Type)data[propId].type(), a[0]); + needActivate = (data[propId] != value); + data[propId] = value; + } } - } - if (c == QMetaObject::WriteProperty && needActivate) { - activate(object, baseSig + propId, 0); - } + if (c == QMetaObject::WriteProperty && needActivate) { + activate(object, baseSig + propId, 0); + } - return id; - } else { - return object->qt_metacall(c, id, a); + return id; + } + } else if(c == QMetaObject::InvokeMetaMethod) { + if(id >= baseSlot && id < (baseSlot + slotCount)) { + int idx = id - baseSlot + slotDataIdx; + QmlContext *ctxt = qmlContext(object); + QmlExpression expr(ctxt, slotData->at(idx), object); + expr.setTrackChange(false); + expr.value(); + return id; + } } + + return object->qt_metacall(c, id, a); } QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index 3fb1c46..d8ed242 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -52,7 +52,7 @@ class QmlRefCount; class QmlVMEMetaObject : public QAbstractDynamicMetaObject { public: - QmlVMEMetaObject(QObject *, const QMetaObject *, QmlRefCount * = 0); + QmlVMEMetaObject(QObject *, const QMetaObject *, QList *, int slotData, QmlRefCount * = 0); ~QmlVMEMetaObject(); protected: @@ -63,8 +63,12 @@ private: QmlRefCount *ref; int baseProp; int baseSig; + int baseSlot; + int slotCount; QVariant *data; QBitArray vTypes; + QList *slotData; + int slotDataIdx; }; QT_END_NAMESPACE -- cgit v0.12 From c814652c4276f7fba18243c1e3abff6557375582 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 5 May 2009 16:30:53 +1000 Subject: More doc cleanup. --- src/declarative/extra/qmlsqlconnection.cpp | 31 +-- src/declarative/extra/qmlsqlquery.cpp | 36 ++-- src/declarative/fx/qfxitem.cpp | 258 +++++++++++++++---------- src/declarative/fx/qfxparticles.cpp | 4 + src/declarative/qml/qmlcomponent.cpp | 6 +- src/declarative/qml/qmlengine.cpp | 2 +- src/declarative/qml/qmlparserstatus.cpp | 7 + src/declarative/qml/qmlparserstatus.h | 2 +- src/declarative/qml/qmlpropertyvaluesource.cpp | 3 + 9 files changed, 214 insertions(+), 135 deletions(-) diff --git a/src/declarative/extra/qmlsqlconnection.cpp b/src/declarative/extra/qmlsqlconnection.cpp index a39aa6f..25ab033 100644 --- a/src/declarative/extra/qmlsqlconnection.cpp +++ b/src/declarative/extra/qmlsqlconnection.cpp @@ -79,13 +79,14 @@ public: Qml the query should connect using its name. \qml - - qmlConnection - QSQLITE - "mydb.sqlite" - - SELECT * FROM mytable - SELECT * FROM myothertable + SqlConnection { + id: myConnection + name: "qmlConnection" + driver: "QSQLITE" + databaseName: "mydb.sqlite" + } + SqlQuery { id: listmodel; connection: myConnection; query: "SELECT * FROM mytable" } + SqlQuery { id: othermodel; connection: "qmlConnection"; query: "SELECT * FROM myothertable" } \endqml */ @@ -99,34 +100,34 @@ public: */ /*! - \qmlproperty QStringList SqlConnection::tables + \qmlproperty list SqlConnection::tables Defines the set of tables that exist in the database for the connection. */ /*! - \qmlproperty QString SqlConnection::databaseName + \qmlproperty string SqlConnection::databaseName Defines the connection's database name. This is used when opening the connection to the database. */ /*! - \qmlproperty QString SqlConnection::driver + \qmlproperty string SqlConnection::driver Defines the driver type of the connection. This is used when opening the connection to the database. */ /*! - \qmlproperty QString SqlConnection::connectOptions + \qmlproperty string SqlConnection::connectOptions Defines the options used when connecting to the database. These are used when opening the connection to the database. */ /*! - \qmlproperty QString SqlConnection::hostName + \qmlproperty string SqlConnection::hostName Defines the connection's host name. This is used when opening the connection to the database. @@ -140,21 +141,21 @@ public: */ /*! - \qmlproperty QString SqlConnection::userName + \qmlproperty string SqlConnection::userName Defines the connection's user name. This is used when opening the connection to the database. */ /*! - \qmlproperty QString SqlConnection::password + \qmlproperty string SqlConnection::password Defines the connection's password. This is used when opening the connection to the database. */ /*! - \qmlproperty QString SqlConnection::lastError + \qmlproperty string SqlConnection::lastError Defines the last error, if one occurred, when working with the database. If the error occurred in conjunction with an SQL query the error will be diff --git a/src/declarative/extra/qmlsqlquery.cpp b/src/declarative/extra/qmlsqlquery.cpp index 70b3bdd..5bd1459 100644 --- a/src/declarative/extra/qmlsqlquery.cpp +++ b/src/declarative/extra/qmlsqlquery.cpp @@ -77,18 +77,19 @@ public: values will only apply when the SqlQuery exec() slot is called. \qml - - SELECT * FROM mytable WHERE name LIKE :value - - - - - - SELECT * FROM mytable WHERE type = ? - - - - + SqlQuery { + query: "SELECT * FROM mytable WHERE name LIKE :value" + bindings: SqlBind { + name: ":value" + value: searchText + '%' + } + } + SqlQuery { + query: "SELECT * FROM mytable WHERE type = ?" + bindings: SqlBind { + value: "simple" + } + } \endqml */ @@ -254,11 +255,12 @@ public: appropriate table column name for the result column. \qml - - - SELECT * FROM mytable - - SELECT id AS recordId, (firstName || ' ' || lastName) AS fullName FROM mytable + SqlQuery { connection: qmlConnectionId; query: "DELETE FROM mytable" } + SqlQuery { + connection: "connectionName" + query: "SELECT * FROM mytable" + } + SqlQuery { query: "SELECT id AS recordId, (firstName || ' ' || lastName) AS fullName FROM mytable" } \endqml */ diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index ecc2d65..c46c34c 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -551,17 +551,18 @@ QFxItem *QFxItem::itemParent() const you, but it can come in handy in some cases. \qml - - - - - - - - - - - + Item { + children: [ + Text {}, + Rect {} + ] + resources: [ + Component { + id: myComponent + Text {} + } + ] + } \endqml */ @@ -728,24 +729,24 @@ void QFxItemPrivate::children_clear() So you can write: \qml - - - - + } \endqml If the item is in its base state (i.e. no explicit state has been @@ -1785,14 +1847,14 @@ QmlState *QFxItem::findState(const QString &name) const example: \qml - + } \endqml If the item is in its base state (i.e. no explicit state has been diff --git a/src/declarative/fx/qfxparticles.cpp b/src/declarative/fx/qfxparticles.cpp index 0ac537a..b1f4f56 100644 --- a/src/declarative/fx/qfxparticles.cpp +++ b/src/declarative/fx/qfxparticles.cpp @@ -116,6 +116,10 @@ QML_DEFINE_TYPE(QFxParticleMotion,ParticleMotion); \sa QFxParticles */ + +/*! + Constructs a QFxParticleMotion with parent object \a parent. +*/ QFxParticleMotion::QFxParticleMotion(QObject *parent) : QObject(parent) { diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index b1beb9c..72d4e08 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -256,7 +256,7 @@ QmlComponent::QmlComponent(QmlEngine *engine, const QUrl &url, QObject *parent) } /*! - Create a QmlComponent from the given XML \a data. If provided, \a filename + Create a QmlComponent from the given QML \a data. If provided, \a url is used to set the component name, and to provide a base path for items resolved by this component. */ @@ -283,8 +283,8 @@ QmlComponent::QmlComponent(QmlEngine *engine, QmlCompiledComponent *cc, int star } /*! - Sets the QmlComponent to use the given XML \a data. If provided, - \a filename is used to set the component name, and to provide a base path + Sets the QmlComponent to use the given QML \a data. If provided, + \a url is used to set the component name, and to provide a base path for items resolved by this component. */ void QmlComponent::setData(const QByteArray &data, const QUrl &url) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 30848c1..f8b7ad6 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -373,7 +373,7 @@ bool QmlEnginePrivate::loadCache(QmlBasicScriptNodeCache &cache, const QString & \code QmlEngine engine; - QmlComponent component(""); + QmlComponent component("Text { text: \"Hello world!\" }"); QFxItem *item = qobject_cast(component.create(&engine)); //add item to view, etc diff --git a/src/declarative/qml/qmlparserstatus.cpp b/src/declarative/qml/qmlparserstatus.cpp index 1f49553..71b7adf 100644 --- a/src/declarative/qml/qmlparserstatus.cpp +++ b/src/declarative/qml/qmlparserstatus.cpp @@ -49,6 +49,13 @@ QT_BEGIN_NAMESPACE */ /*! + Destroys the parser status instance. +*/ +QmlParserStatus::~QmlParserStatus() +{ +} + +/*! Invoked after class creation, but before any properties have been set. */ void QmlParserStatus::classBegin() diff --git a/src/declarative/qml/qmlparserstatus.h b/src/declarative/qml/qmlparserstatus.h index 1ec50ba..bb3691c 100644 --- a/src/declarative/qml/qmlparserstatus.h +++ b/src/declarative/qml/qmlparserstatus.h @@ -53,7 +53,7 @@ QT_MODULE(Declarative) class Q_DECLARATIVE_EXPORT QmlParserStatus { public: - virtual ~QmlParserStatus() {} + virtual ~QmlParserStatus(); virtual void classBegin(); virtual void classComplete(); diff --git a/src/declarative/qml/qmlpropertyvaluesource.cpp b/src/declarative/qml/qmlpropertyvaluesource.cpp index 78b0495..44e1952 100644 --- a/src/declarative/qml/qmlpropertyvaluesource.cpp +++ b/src/declarative/qml/qmlpropertyvaluesource.cpp @@ -50,6 +50,9 @@ QT_BEGIN_NAMESPACE */ QML_DEFINE_NOCREATE_TYPE(QmlPropertyValueSource); +/*! + Constructs a QmlPropertyValueSource with parent \a parent. +*/ QmlPropertyValueSource::QmlPropertyValueSource(QObject *parent) : QObject(parent) -- cgit v0.12 From 48568f402055dc5ea2bf59224ff06b3050c1927d Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 5 May 2009 17:23:31 +1000 Subject: Doc --- doc/src/declarative/qmlforcpp.qdoc | 774 +++++++++++---------------------- doc/src/declarative/qtdeclarative.qdoc | 2 +- doc/src/declarative/scenegraph.qdoc | 13 - 3 files changed, 243 insertions(+), 546 deletions(-) delete mode 100644 doc/src/declarative/scenegraph.qdoc diff --git a/doc/src/declarative/qmlforcpp.qdoc b/doc/src/declarative/qmlforcpp.qdoc index f0675fe..282f261 100644 --- a/doc/src/declarative/qmlforcpp.qdoc +++ b/doc/src/declarative/qmlforcpp.qdoc @@ -1,15 +1,14 @@ /*! \page qmlforcpp.html \target qmlforcpp - \title Qt Declarative Markup Language For C++ Programmers + \title QML for C++ Programmers This page describes the QML format and how to use and extend it from C++. - The QML syntax declaratively describes in XML how to construct an in memory - object tree. QML is usually used to describe a visual scene graph - using - \l {graphicsview}{GraphicsView} or the \l {fxprimitives}{Fx Primitives} - but it is not conceptually - limited to this: the QML format is an abstract XML description of \b any - object tree. + The QML syntax declaratively describes how to construct an in memory + object tree. QML is usually used to describe a visual scene graph + but it is not conceptually limited to this: the QML format is an abstract + description of \b any object tree. QML also includes property bindings. Bindings are ECMAScript expressions of a properties value. Whenever the value of the expression changes - @@ -27,58 +26,40 @@ The following code uses the C++ interface to create 100 red rectangles based on a simple declarative component description. - \raw html - - - - -
- \endraw + \code - QmlComponent redRectangle(""); + QmlComponent redRectangle("Rect { color: \"red\"; width: 100; height: 100 }"); for (int ii = 0; ii < 100; ++ii) { QObject *rectangle = redRectangle.create(); // ... do something with the rectangle ... } \endcode - \raw html -
- \endraw - Each independent XML file describes a QML component, but it is - also possible to create sub-components within a QML file as will be - shown later. + Each independent file describes a QML component, but it is also possible to + create sub-components within a QML file as will be shown later. \section1 QML Format 101 This is some sample QML code. -\raw HTML - - - - -
-\endraw \code - - - 50 - white - 16 - Hello world! - - - \endcode -\raw HTML -
-\endraw - - In QML, XML tags and attributes correspond to Qt objects and properties. - The general rule of thumb is any tag or attribute name that starts with a - capital letter refers to a class, and names that start with a lower case - letter to properties. It is not possible to access a property that starts - with a capital letter from QML. + Image { + id: myRect + x: 10 + y: 10 + width: 100 + height: 100 + src: "background.png" + + Text { + height: 50 + width: 100 + color: "white" + font.fontSize: 16 + text: "Hello world!" + } + } + \endcode The QML snippet shown above instantiates one \c Image instance and one \c Text instance and sets properties on both. \b Everything in QML @@ -86,50 +67,18 @@ assigning a property a value. QML relies heavily on Qt's meta object system and can only instantiate classes that derive from QObject. - Setting properties can be done in two ways: as an XML attribute directly on - the class tag that created the the object, or as sub-tags. - Although syntactically different, their behaviour is identical. The two QML - snippets below behave exactly the same. -\raw HTML - - - - - -
-\endraw - \code - - \endcode -\raw HTML - -\endraw - \code - - 10 - 10 - - \endcode -\raw HTML -
-\endraw - Arbitrary mixing and matching between the two is allowed. - QML can set properties that are more complex than just simple types like - integers and strings. Properties can be object pointers or Qt interface pointers - or even lists of object or Qt interface pointers! QML is typesafe, and will - ensure that only the valid types are assigned to properties. + integers and strings. Properties can be object pointers or Qt interface + pointers or even lists of object or Qt interface pointers! QML is typesafe, + and will ensure that only the valid types are assigned to properties. Assigning an object to a property is as simple as assigning a basic integer. Attempting to assign an object to a property when type coercian fails will produce an error. The following shows an example of valid and of invalid QML and the corresponding C++ classes. -\raw HTML - - - - - -
-\endraw + \table + \row \o \code class Image : public QObject { @@ -142,86 +91,33 @@ ... }; \endcode -\raw HTML - -\endraw - \code - - - - - - - - - - - - - - \endcode -\raw HTML -
-\endraw + \o \code + // OK + Image { + filter: ImageFilter {} + } - Classes can also define an optional default property. The default property - is used for assignment if no explicit property has been specified. - In the example below, the string "Hello World!" will be assigned to - the \c Text element's default property - which happens to be the \c text - property. Both lines do the same thing, one explicitly and one implicitly. - -\raw HTML - - - - - -
-\endraw - \code - - Hello World! - \endcode -\raw HTML - -\endraw - \code - class Text : public QObject - { - ... - Q_PROPERTY(QString text READ text WRITE setText) - Q_CLASSINFO("DefaultProperty", "text") - }; + // NOT OK: Image cannot be cast into ImageFilter + Image { + filter: Image {} + } \endcode -\raw HTML -
-\endraw + \endtable + Classes can also define an optional default property. The default property + is used for assignment if no explicit property has been specified. Any object property can be the default, even complex properties like lists of objects. The default property of the \c Rect class is the \c children property, a list of \c Item's. In the following example, as both \c Image and \c Text inherit from \c Item the \c Image and \c Text instances are added to the parent's \c children property. -\raw HTML - - - - -
-\endraw \code - - - - + Rect { + Image {} + Text {} + } \endcode -\raw HTML -
-\endraw Properties that return read-only object pointers can be used recursively. This can be used, for example, to group properties together. The @@ -230,11 +126,8 @@ QML makes it easy to interact with these grouped properties, as the following shows - everything you would expect to work, just does. -\raw HTML - - - - - -
-\endraw + \table + \row \o \code class Text : public ... { @@ -250,67 +143,36 @@ Q_PROPERTY(int size READ size WRITE setSize); }; \endcode -\raw HTML - -\endraw + \o \code - - - true - true - - 12 - - \endcode -\raw HTML -
-\endraw + Text { + font.family: "helvetica" + font.size: 12 + font { + bold: true + italic: true + } + } + \endcode + \endtable \section1 Defining QML Types The QML engine has no intrinsic knowledge of any class types. Instead the programmer must define the C++ types, and their corresponding QML - name. There are three ways of adding known types to the QML engine: - \list - \o + name. + \code #define QML_DECLARE_TYPE(T) #define QML_DEFINE_TYPE(T,QmlName) \endcode + Adding these macros to your library or executable automatically makes the C++ type \a T available from the declarative markup language under the name \a QmlName. Of course there's nothing stopping you using the same - name for both the C++ and the QML name!
- Most types are added to the QML engine using these macros. The only - requirement is that \a T inherits QObject and has a default constructor. - \o - \code - #define QML_DEFINE_CUSTOM_PARSER(QmlName, CustomParserClass) - \endcode - Custom parsers define a way to translate between declarative XML and an - object instance in the case the default object model lets you down. Free - form lists (\c {} are an example of a custom parser. - Custom parsers implement the \l QmlCustomParser interface. - - Custom parsers give a developer very fine grain control over how a type is - instantiated from the XML that describes it. During the - compilation phase, the custom parser is presented with the XML via a - QXmlStreamReader and must - compile this down into an opaque blob that is returned to the compiler. - When, at runtime, the type is instantiated, the opaque blob is passed into - the custom parser, which must return a QObject derived type. - - \o QML::ClassFactory - - The QML engine calls the class factory as a last resort when trying to - create a type. The class factory returns a \l QmlComponent instance for - the type if it can create it. This allows "on the fly" types to be created. - For example, a class factory is used to support automatic instantiation of - .qml template files. - \endlist + name for both the C++ and the QML name! + Any type can be added to the QML engine using these macros. The only + requirements are that \a T inherits QObject and that it has a default constructor. \section1 Property Binding @@ -321,31 +183,32 @@ Property bindings are ECMAScript expressions and can be applied to any object property. C++ classes don't have to do anything special to get - binding support other than define appropriate properties. Property binding - expressions are differentiated from regular constant literals by surrounding - them in braces. + binding support other than define appropriate properties. When a non-literal + property assignment appears in a QML file, it is automatically treated as a + property binding. Here's a simple example that stacks a red, blue and green rectangle. Bindings are used to ensure that the height of each is kept equal to it's parent's. Were the root rectangle's height property to change, the child rectangles height would be updated automatically. -\raw HTML - - - - -
-\endraw + \code - - - - - - \endcode -\raw HTML -
-\endraw + Rect { + color: "red" + width: 100 + Rect { + color: "blue" + width: 50 + height: parent.height + Rect { + color: "green" + width: 25 + height: parent.height + } + } + } + \endcode + Binding expressions execute in a context. A context behaves as a scope and defines how the expression resolves property and variable names. Although the two expressions in the last example are the same, the value of \c parent @@ -371,24 +234,14 @@ the case of grouped properties - the object context is that of the instantiated object, the consequences of which are shown below. -\raw HTML - - - - -
-\endraw \code - - - - {font.italic} {italic} - - - \endcode -\raw HTML -
-\endraw + // OK // NOT OK + Text { Text { + font { font { + bold: font.italic bold: italic + } } + } } + \endcode The second context is the "component context". Each QML component (and consequently each QML file) is created in its own unique binding context. @@ -396,21 +249,14 @@ object - but in this case it is the component's root object. An example will illustrate best - the resultant text will read "background.png". -\raw HTML - - - - -
-\endraw \code - - - + Image { + src: "background.png" + Text { + text: src + } + } \endcode -\raw HTML -
-\endraw If the name is not found in either of these contexts, the context heirarchy is searched parent-by-parent until the name is either found, or the @@ -421,23 +267,22 @@ parent, rather than fixing them all to a single common point. Here's the example rewritten to do just that. -\raw HTML - - - - -
-\endraw \code - - - - - - \endcode -\raw HTML -
-\endraw + Rect { + color: "red" + width: 100 + Rect { + color: "blue" + width: 50 + height: parent.height + Rect { + color: "green" + width: 25 + height: parent.parent.height + } + } + } + \endcode Clearly this sort of fragile relationship is undesirable and unmanageable - moving the green rectangle to be a sibling of the blue or introducing a @@ -450,28 +295,26 @@ property. Every object automatically has this magical property (if the object also has an actual property called \c id, that gets set too). As an id allows an object to be referenced directly, it must be unique within - a component. Any number of id's can exist, but they must all begin with - a capital letter. An id of "Root" is valid, while an id of "root" is not. - \note This is not technically true - lowercase id names do work, but are - slower. Support will probably be removed for them eventually. - -\raw HTML - - - - -
-\endraw - \code - - - - - - \endcode -\raw HTML -
-\endraw + a component. By convention, id's should start with an uppercase letter. + + \code + Rect { + id: Root + color: "red" + width: GreenRect.width + 75 + height: Root.height + Rect { + color: "blue" + width: GreenRect.width + 25 + Rect { + id: GreenRect + color: "green" + width: 25 + height: Root.height + } + } + } + \endcode To relate id's back to QmlBindContext, id's exist as properties on the component context. @@ -483,11 +326,6 @@ the expression will not be updated if the value changes. The following is an example of a QML friendly property declaration. -\raw HTML - - - - -
-\endraw \code class Example : public QObject { @@ -500,11 +338,6 @@ void sampleChanged(int); }; \endcode -\raw HTML -
-\endraw While generally no changes are needed to a C++ class to use property binding, sometimes more advanced interaction between the binding engine and @@ -523,19 +356,12 @@ easily associate ECMAScript with signals. Consider the following example, in which Button is a made-up type with a clicked() signal. -\raw HTML - - - - -
-\endraw \code -
-\endraw Clicking on the button causes "Hello world!" to be printed to the console (or lost forever if you're running Windows). @@ -558,23 +384,15 @@ below, as long as you remember to name the parameters of your signal in C++ (see QMetaMethod::parameterNames()). -\raw HTML - - - - - -
-\endraw + \table + \row \o \code - - - for(var ii = 0; ii < count; ++ii) - print(message) - - - \endcode -\raw HTML - -\endraw + Example { + onDoSomething: for(var ii = 0; ii < count; ++ii) + print(message) + } + \endcode + \o \code class Example : public QObject { @@ -583,11 +401,7 @@ void doSomething(int count, const QString &message); }; \endcode -\raw HTML -
-\endraw + \endtable Just like property bindings, signal scripts are executed in a context. The signal script context is identical in scope to the "object context" under @@ -599,41 +413,23 @@ default method is defined just like a default property, though the special "DefaultMethod" class info. -\raw HTML - - - - -
-\endraw \code Q_CLASSINFO("DefaultMethod", "myMethod(int)"); \endcode -\raw HTML -
-\endraw This is useful in achieving several use cases, like that below which moves the button when it is clicked. -\raw HTML - - - - -
-\endraw \code - + Button { + id: MyButton + onClicked: NumericAnimation { + target: MyButton + property: "x" + to: 100 + } + } \endcode -\raw HTML -
-\endraw - If the class itself actually defines a property called "on", this will be assigned the string value and the signal handling behaviour will be @@ -648,65 +444,44 @@ Qt's QGridLayout is one such example. -\raw HTML - - - - -
-\endraw \code - - - - - - - - \endcode -\raw HTML -
-\endraw + QGridLayout { + QLabel { + QGridLayout.row: 0 + QGridLayout.column: 0 + text: "Name:" + } + QLineEdit { + QGridLayout.row: 0 + QGridLayout.column: 1 + } + + QLabel { + QGridLayout.row: 1 + QGridLayout.column: 0 + text: "Occupation:" + } + QLineEdit { + QGridLayout.row: 1 + QGridLayout.column: 1 + } + } + \endcode - Attached properties are identified by the use of a class name, in the + Attached properties are identified by the use of a type name, in the case shown \c QGridLayout, as a grouped property specifier. To prevent ambiguity with actual class instantiations, attached properties must always be specified to include a period but can otherwise be used just like regular properties. -\raw HTML - - - - -
-\endraw - \code - - - 0 - 0 - - - \endcode -\raw HTML -
-\endraw - C++ types provide attached properties by declaring the public function \c qmlAttachedProperties like this example. -\raw HTML - - - - - -
-\endraw + \table + \row \o \code static QObject *Type::qmlAttachedProperties(QObject *); \endcode -\raw HTML - -\endraw + \o \code class Example : public QObject { @@ -715,18 +490,14 @@ static QObject *qmlAttachedProperties(QObject *); }; \endcode -\raw HTML -
-\endraw + \endtable When an attached property is accessed, the QML engine will call this method to create an attachment object, passing in the object instance that the attached property applies to. The attachment object should define all the attached properties, and is generally parented to the provided object - instance to avoid memory leaks. The QML engine does not save this object, - so it is necessary for the attached property function to ensure that + instance to avoid memory leaks. The QML engine does not saves this object, + so it is not necessary for the attached property function to ensure that multiple calls for the same instance object return the same attached object. While conceptually simple, implementing an attachment object is not quite @@ -737,23 +508,15 @@ that \b any object can attach \b any attached property. The following is perfectly valid, although the attached property has no actual effect: -\raw HTML - - - - -
-\endraw \code - - -
-\endraw + FancyGridLayout { + Item { + Button { + QGridLayout.row: 1 + } + } + } + \endcode The property has no effect because the (made-up) FancyGridLayout type defines the meaning of the \c row attached property only to apply to its direct children. It @@ -769,29 +532,17 @@ \section1 Property Value Sources Intrinsically, the QML engine can assign a property either a static value, - such as a number of object tree, or a property binding. It is possible for + such as a number or an object tree, or a property binding. It is possible for advanced users to extend the engine to assign other "types" of values to properties. These "types" are known as property value sources. - Consider the following \l {fxprimitives}{Fx Primitives} example. + Consider the following example. -\raw HTML - - - - -
-\endraw \code - - - - - - \endcode -\raw HTML -
-\endraw + Rect { + x: NumericAnimation { running: true; repeat; true; from: 0; to: 100; } + } + \endcode Here the \c x property of the rectangle will be animated from 0 to 100. To support this, the NumericAnimation class inherits the @@ -805,26 +556,17 @@ 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 \l {fxprimitives}{Fx Primitives}. To create new types, it is + 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. - \note slots are not yet supported - - Any object is extensible in this way under QML, using the special - \c properties and \c signals properties. Like \c id, these two properties - are automatically available on all types under QML and accessible from - other QML files or directly from C++. - 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. -\raw HTML - - - - - -
-\endraw + \table + \row + \o \code QmlComponent component(xmlData); QObject *object = component.create(); @@ -833,44 +575,36 @@ // Will be emitted whenever the button is clicked QObject::connect(object, SIGNAL(clicked2()), this, SLOT(...)); \endcode -\raw HTML - -\endraw + \o \code - - \endcode -\raw HTML -
-\endraw - - Any number of properties and signals can be added to an existing type. The - \c Property and \c Signal elements have the following properties that can - be set: - \table - \header \o Tag \o Property \o Description - \row \o Property \o name \o The name of the property - \row \o Property \o type \o The type of the property. The available types are: \list \o int \o bool \o double \o real \o string \o color \o date \o variant \endlist The default is variant. - \row \o Property \o value \o The initial value of the property. Setting this is just a shortcut for setting the property normally, as shown in the example above. - \row \o Property \o onValueChanged \o A special signal property that is emitted each time the property value changes. - \row \o Property \o default \o Set this as the object's default property - \row \o Signal \o name \o The name of the signal. + Button { + property string text2 + signal clicked2 + + text: "Hello!" + text2: "Hello world!" + onClicked: clicked2.emit() + } + \endcode \endtable - If the type itself actually defines a property called \c properties or - \c signals, the respective extension will be disabled for that type and - the types own properties will be set. + 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 @@ -890,11 +624,6 @@ these notifications, all a class has to do is to inherit the interface, and notify the Qt meta system using the Q_INTERFACES() macro. For example, -\raw HTML - - - - -
-\endraw \code class Example : public QObject, public QmlParserStatus { @@ -907,11 +636,6 @@ } }; \endcode -\raw HTML -
-\endraw \section1 Extended Type Definitions @@ -935,29 +659,17 @@ property or slots on the extension object is used instead. When an extended type is installed, the -\raw HTML - - - - -
-\endraw \code #define QML_DEFINE_EXTENDED_TYPE(T,QmlName,ExtendedTypeName) \endcode -\raw HTML -
-\endraw macro should be used instead of the regular \c QML_DEFINE_TYPE. This example shows the addition of a read-only \c textLength property to QLabel being implemented as an extension. -\raw HTML - - - - - -
-\endraw + \table + \row + \o \code class QLabelExtension : public QObject { @@ -971,19 +683,17 @@ }; QML_DEFINE_EXTENDED_TYPE(QLabel,QLabel,QLabelExtension); \endcode -\raw HTML - -\endraw + \o \code - - - \endcode -\raw HTML -
-\endraw + QLabel { + id: Label1 + text: "Hello World!" + } + QLabel { + text: "Label1 text length: " + Label1.textLength + } + \endcode + \endtable Attributes defined through extensions are inherited, just like attributes defined on a normal class. Any types that inherit from \c QLabel, will diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index 666c8ae..67605dc 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -65,7 +65,7 @@ \o \l {qmlexamples}{Examples} \o \l {tutorial}{Tutorial: 'Hello World'} \o \l {tutorials-declarative-contacts.html}{Tutorial: 'Introduction to QML'} - \o \l {qmlforcpp}{Qt Declarative Markup Language For C++ Programmers} + \o \l {qmlforcpp}{QML For C++ Programmers} \endlist Core Features: diff --git a/doc/src/declarative/scenegraph.qdoc b/doc/src/declarative/scenegraph.qdoc deleted file mode 100644 index 2340324..0000000 --- a/doc/src/declarative/scenegraph.qdoc +++ /dev/null @@ -1,13 +0,0 @@ -/*! - \page graphicsview.html - \target graphicsview - \title GraphicsView - -*/ - -/*! - \page fxprimitives.html - \target fxprimitives - \title FX Primitives - -*/ -- cgit v0.12 From 089f01e07cea648bc56a6b825d70a54abfe15fd3 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Tue, 5 May 2009 17:44:43 +1000 Subject: ffmpeg support still image based for now, streaming next --- tools/qmlviewer/main.cpp | 18 +++++++--- tools/qmlviewer/qmlviewer.cpp | 81 ++++++++++++++++++++++++++++++++++--------- tools/qmlviewer/qmlviewer.h | 2 ++ 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp index c5676ab..26ff213 100644 --- a/tools/qmlviewer/main.cpp +++ b/tools/qmlviewer/main.cpp @@ -27,11 +27,15 @@ void usage() qWarning(" -v, -version ............................. display version"); qWarning(" -frameless ............................... run with no window frame"); qWarning(" -skin ...................... run with a skin window frame"); - qWarning(" -recorddither ordered|threshold|floyd .... set dither mode used for recording"); + qWarning(" -recordfile ..................... set output file"); + qWarning(" - ImageMagick 'convert' for GIF)"); + qWarning(" - png file for raw frames"); + qWarning(" - 'ffmpeg' for other formats"); + qWarning(" -recorddither ordered|threshold|floyd .... set GIF dither recording mode"); qWarning(" -recordperiod ............. set time between recording frames"); - qWarning(" -autorecord [from-] ...... set recording to start and stop automatically"); + qWarning(" -autorecord [from-] ...... set recording to start and stop"); qWarning(" -devicekeys .............................. use numeric keys (see F1)"); - qWarning(" -cache ................................... enable a disk cache of remote content"); + qWarning(" -cache ................................... disk cache remote content"); qWarning(" -recordtest .................. record an autotest"); qWarning(" -runtest ..................... run a previously recorded test"); qWarning(" "); @@ -66,7 +70,8 @@ int main(int argc, char ** argv) int period = 0; int autorecord_from = 0; int autorecord_to = 0; - QString dither = "threshold"; + QString dither = "none"; + QString recordfile = "animation.gif"; QString skin; bool devkeys = false; bool cache = false; @@ -83,6 +88,10 @@ int main(int argc, char ** argv) cache = true; } else if (arg == "-recordperiod") { period = QString(argv[++i]).toInt(); + } else if (arg == "-recordfile") { + recordfile = QString(argv[++i]); + } else if (arg == "-recorddither") { + dither = QString(argv[++i]); } else if (arg == "-autorecord") { QString range = QString(argv[++i]); int dash = range.indexOf('-'); @@ -119,6 +128,7 @@ int main(int argc, char ** argv) QmlViewer viewer(testMode, testDir, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget); viewer.setCacheEnabled(cache); viewer.openQml(fileName); + viewer.setRecordFile(recordfile); if (period>0) viewer.setRecordPeriod(period); if (autorecord_to) diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 3c52cfe..950baf8 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -210,6 +210,11 @@ void QmlViewer::setAutoRecord(int from, int to) } } +void QmlViewer::setRecordFile(const QString& f) +{ + record_file = f; +} + void QmlViewer::setRecordPeriod(int ms) { record_period = ms; @@ -238,7 +243,7 @@ void QmlViewer::keyPressEvent(QKeyEvent *event) exit(0); else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) { qDebug() << "F1 - help\n" - << "F2 - toggle GIF recording\n" + << "F2 - toggle video recording\n" << "F3 - take PNG snapshot\n" << "F4 - show items and state\n" << "F5 - reload QML\n" @@ -286,9 +291,21 @@ void QmlViewer::setRecording(bool on) QStringList inputs; qDebug() << "Saving frames..."; + QString framename; + bool png_output = false; + if (record_file.right(4).toLower()==".png") { + if (record_file.contains('%')) + framename = record_file; + else + framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4); + png_output = true; + } else { + framename = "tmp-frame%04d.png"; + png_output = false; + } foreach (QImage* img, frames) { QString name; - name.sprintf("tmp-frame%04d.png",frame++); + name.sprintf(framename.toLocal8Bit(),frame++); if (record_dither=="ordered") img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name); else if (record_dither=="threshold") @@ -296,27 +313,57 @@ void QmlViewer::setRecording(bool on) else if (record_dither=="floyd") img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name); else - img->convertToFormat(QImage::Format_Indexed8).save(name); + img->save(name); inputs << name; delete img; } - QString output="animation.gif"; - QStringList args; - - args << "-delay" << QString::number(record_period/10); - args << inputs; - args << output; - qDebug() << "Converting..." << output; - if (0!=QProcess::execute("convert", args)) { - qWarning() << "Cannot run ImageMagick 'convert' - not converted to gif"; + if (png_output) { + framename.replace(QRegExp("%\\d*."),"*"); + qDebug() << "Wrote frames" << framename; inputs.clear(); // don't remove them - qDebug() << "Wrote frames tmp-frame*.png"; } else { - qDebug() << "Compressing..." << output; - if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << output << output)) - qWarning() << "Cannot run 'gifsicle' - not compressed"; - qDebug() << "Wrote" << output; + if (record_file.right(4).toLower()==".gif") { + // ImageMagick and gifsicle for GIF encoding + QStringList args; + args << "-delay" << QString::number(record_period/10); + args << inputs; + args << record_file; + qDebug() << "Converting..." << record_file; + if (0!=QProcess::execute("convert", args)) { + qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted"; + inputs.clear(); // don't remove them + qDebug() << "Wrote frames tmp-frame*.png"; + } else { + if (record_file.right(4).toLower() == ".gif") { + qDebug() << "Compressing..." << record_file; + if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file)) + qWarning() << "Cannot run 'gifsicle' - not compressed"; + } + qDebug() << "Wrote" << record_file; + } + } else { + // ffmpeg for other formats (eg. MPEG) + + // Ensure no old file after end + QString name; + name.sprintf(framename.toLocal8Bit(),frame++); + QFile::remove(name); + + QStringList args; + args << "-sameq"; // ie. high + args << "-y"; + args << "-r" << QString::number(1000/record_period); + args << "-i" << framename; + args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height()); + args << record_file; + qDebug() << "Converting..." << record_file; + if (0!=QProcess::execute("ffmpeg", args)) { + qWarning() << "Cannot run ffmpeg - recorded frames not converted"; + inputs.clear(); // don't remove them + qDebug() << "Wrote frames tmp-frame*.png"; + } + } } foreach (QString name, inputs) diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h index 0fa879d..ee0c3d7 100644 --- a/tools/qmlviewer/qmlviewer.h +++ b/tools/qmlviewer/qmlviewer.h @@ -33,6 +33,7 @@ public: void setRecordDither(const QString& s) { record_dither = s; } void setRecordPeriod(int ms); + void setRecordFile(const QString&); int recordPeriod() const { return record_period; } void setRecording(bool on); bool isRecording() const { return recordTimer.isActive(); } @@ -62,6 +63,7 @@ private: QBasicTimer autoStartTimer; QTime autoTimer; QString record_dither; + QString record_file; int record_period; int record_autotime; bool devicemode; -- cgit v0.12 From a454798fff3e0093a180a9aa890d94375280e09c Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Tue, 5 May 2009 18:00:30 +1000 Subject: Stream video recording. --- tools/qmlviewer/qmlviewer.cpp | 131 ++++++++++++++++++++++-------------------- tools/qmlviewer/qmlviewer.h | 1 + 2 files changed, 71 insertions(+), 61 deletions(-) diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 950baf8..93370d9 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -35,7 +35,7 @@ #include QmlViewer::QmlViewer(QFxTestEngine::TestMode testMode, const QString &testDir, QWidget *parent, Qt::WindowFlags flags) - : QWidget(parent, flags) + : QWidget(parent, flags), frame_stream(0) { testEngine = 0; devicemode = false; @@ -285,45 +285,70 @@ void QmlViewer::setRecording(bool on) if (on) { recordTimer.start(record_period,this); + QString fmt = record_file.right(4).toLower(); + if (fmt != ".png" && fmt != ".gif") { + // Stream video to ffmpeg + + QProcess *proc = new QProcess(this); + frame_stream = proc; + + QStringList args; + args << "-sameq"; // ie. high + args << "-y"; + args << "-r" << QString::number(1000/record_period); + args << "-f" << "rawvideo"; + args << "-pix_fmt" << "rgb32"; + args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height()); + args << "-i" << "-"; + args << record_file; + proc->start("ffmpeg",args,QIODevice::WriteOnly); + } else { + // Store frames, save to GIF/PNG + frame_stream = 0; + } } else { recordTimer.stop(); - int frame=0; - QStringList inputs; - qDebug() << "Saving frames..."; - - QString framename; - bool png_output = false; - if (record_file.right(4).toLower()==".png") { - if (record_file.contains('%')) - framename = record_file; - else - framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4); - png_output = true; + if (frame_stream) { + qDebug() << "Saving video..."; + frame_stream->close(); + qDebug() << "Wrote" << record_file; } else { - framename = "tmp-frame%04d.png"; - png_output = false; - } - foreach (QImage* img, frames) { - QString name; - name.sprintf(framename.toLocal8Bit(),frame++); - if (record_dither=="ordered") - img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name); - else if (record_dither=="threshold") - img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name); - else if (record_dither=="floyd") - img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name); - else - img->save(name); - inputs << name; - delete img; - } + int frame=0; + QStringList inputs; + qDebug() << "Saving frames..."; + + QString framename; + bool png_output = false; + if (record_file.right(4).toLower()==".png") { + if (record_file.contains('%')) + framename = record_file; + else + framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4); + png_output = true; + } else { + framename = "tmp-frame%04d.png"; + png_output = false; + } + foreach (QImage* img, frames) { + QString name; + name.sprintf(framename.toLocal8Bit(),frame++); + if (record_dither=="ordered") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name); + else if (record_dither=="threshold") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name); + else if (record_dither=="floyd") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name); + else + img->save(name); + inputs << name; + delete img; + } - if (png_output) { - framename.replace(QRegExp("%\\d*."),"*"); - qDebug() << "Wrote frames" << framename; - inputs.clear(); // don't remove them - } else { - if (record_file.right(4).toLower()==".gif") { + if (png_output) { + framename.replace(QRegExp("%\\d*."),"*"); + qDebug() << "Wrote frames" << framename; + inputs.clear(); // don't remove them + } else { // ImageMagick and gifsicle for GIF encoding QStringList args; args << "-delay" << QString::number(record_period/10); @@ -342,34 +367,13 @@ void QmlViewer::setRecording(bool on) } qDebug() << "Wrote" << record_file; } - } else { - // ffmpeg for other formats (eg. MPEG) + } - // Ensure no old file after end - QString name; - name.sprintf(framename.toLocal8Bit(),frame++); + foreach (QString name, inputs) QFile::remove(name); - QStringList args; - args << "-sameq"; // ie. high - args << "-y"; - args << "-r" << QString::number(1000/record_period); - args << "-i" << framename; - args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height()); - args << record_file; - qDebug() << "Converting..." << record_file; - if (0!=QProcess::execute("ffmpeg", args)) { - qWarning() << "Cannot run ffmpeg - recorded frames not converted"; - inputs.clear(); // don't remove them - qDebug() << "Wrote frames tmp-frame*.png"; - } - } + frames.clear(); } - - foreach (QString name, inputs) - QFile::remove(name); - - frames.clear(); } qDebug() << "Recording: " << (recordTimer.isActive()?"ON":"OFF"); } @@ -377,7 +381,12 @@ void QmlViewer::setRecording(bool on) void QmlViewer::timerEvent(QTimerEvent *event) { if (event->timerId() == recordTimer.timerId()) { - frames.append(new QImage(canvas->asImage())); + if (frame_stream) { + QImage frame(canvas->asImage()); + frame_stream->write((char*)frame.bits(),frame.numBytes()); + } else { + frames.append(new QImage(canvas->asImage())); + } if (record_autotime && autoTimer.elapsed() >= record_autotime) setRecording(false); } else if (event->timerId() == autoStartTimer.timerId()) { diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h index ee0c3d7..fc65ebf 100644 --- a/tools/qmlviewer/qmlviewer.h +++ b/tools/qmlviewer/qmlviewer.h @@ -60,6 +60,7 @@ private: void init(QFxTestEngine::TestMode, const QString &, const QString& fileName); QBasicTimer recordTimer; QList frames; + QIODevice* frame_stream; QBasicTimer autoStartTimer; QTime autoTimer; QString record_dither; -- cgit v0.12