diff options
author | Martin Jones <martin.jones@nokia.com> | 2009-05-20 04:51:29 (GMT) |
---|---|---|
committer | Martin Jones <martin.jones@nokia.com> | 2009-05-20 04:51:29 (GMT) |
commit | e484ee27f929aca738a269947237d834dab89b39 (patch) | |
tree | 216f95598411eb4c72141308973695d5e0d8b372 | |
parent | ded29009f766a8373193d94bcb8309270f66a266 (diff) | |
parent | d1f1f2c91f63609ca1ffad32efdd6590f9f0ce6a (diff) | |
download | Qt-e484ee27f929aca738a269947237d834dab89b39.zip Qt-e484ee27f929aca738a269947237d834dab89b39.tar.gz Qt-e484ee27f929aca738a269947237d834dab89b39.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
501 files changed, 11812 insertions, 6234 deletions
@@ -5,6 +5,8 @@ syntax: glob *~ *.a +*.la +*.pc *.core *.moc *.o @@ -45,7 +47,9 @@ bin/rcc* bin/uic* bin/qcollectiongenerator bin/qhelpgenerator +bin/macdeployqt tools/qdoc3/qdoc3* +tools/macdeployqt/macchangeqt/macchangeqt #configure.cache mkspecs/default mkspecs/qconfig.pri diff --git a/demos/declarative/flickr/content/ImageDetails.qml b/demos/declarative/flickr/content/ImageDetails.qml index b8091f2..ccc91cb 100644 --- a/demos/declarative/flickr/content/ImageDetails.qml +++ b/demos/declarative/flickr/content/ImageDetails.qml @@ -89,7 +89,6 @@ Flipable { // Center image if it is smaller than the flickable area. x: ImageContainer.width > width*scale ? (ImageContainer.width - width*scale) / 2 : 0 y: ImageContainer.height > height*scale ? (ImageContainer.height - height*scale) / 2 : 0 - anchors.centeredIn: parent onStatusChanged : { // Default scale shows the entire image. if (status == 0 && width != 0) { diff --git a/demos/declarative/flickr/content/Progress.qml b/demos/declarative/flickr/content/Progress.qml index 92a232e..aa2a2e6 100644 --- a/demos/declarative/flickr/content/Progress.qml +++ b/demos/declarative/flickr/content/Progress.qml @@ -5,7 +5,7 @@ Item { Rect { id: Container; anchors.fill: parent; gradientColor: "#66000000"; - pen.color: "white"; pen.width: 1; color: "#66343434"; radius: height/2 - 2 + pen.color: "white"; pen.width: 0; color: "#66343434"; radius: height/2 - 2 } Rect { diff --git a/demos/declarative/flickr/content/Slider.qml b/demos/declarative/flickr/content/Slider.qml index 92f4993..aae4631 100644 --- a/demos/declarative/flickr/content/Slider.qml +++ b/demos/declarative/flickr/content/Slider.qml @@ -3,25 +3,25 @@ Item { // value is read/write. property real value - onValueChanged: { Handle.x = (value - minimum) * Slider.xMax / (maximum - minimum); } + onValueChanged: { Handle.x = 2 + (value - minimum) * Slider.xMax / (maximum - minimum); } property real maximum: 1 property real minimum: 1 - property int xMax: Slider.width - Handle.width - 2 + property int xMax: Slider.width - Handle.width - 4 Rect { id: Container; anchors.fill: parent; gradientColor: "#66000000"; - pen.color: "white"; pen.width: 1; color: "#66343434"; radius: 8 + pen.color: "white"; pen.width: 0; color: "#66343434"; radius: 8 } Rect { id: Handle - x: Slider.width / 2 - Handle.width / 2; y: 2; width: 30; height: 12 + x: Slider.width / 2 - Handle.width / 2; y: 2; width: 30; height: Slider.height-4 color: "lightgray"; gradientColor: "gray"; radius: 6 MouseRegion { anchors.fill: parent; drag.target: parent - drag.axis: "x"; drag.xmin: 2; drag.xmax: Slider.xMax - onPositionChanged: { value = (maximum - minimum) * Handle.x / Slider.xMax + minimum; } + drag.axis: "x"; drag.xmin: 2; drag.xmax: Slider.xMax+2 + onPositionChanged: { value = (maximum - minimum) * (Handle.x-2) / Slider.xMax + minimum; } } } } diff --git a/demos/declarative/webbrowser/webbrowser.qml b/demos/declarative/webbrowser/webbrowser.qml index 4b03b63..a38d032 100644 --- a/demos/declarative/webbrowser/webbrowser.qml +++ b/demos/declarative/webbrowser/webbrowser.qml @@ -114,6 +114,7 @@ Item { opacity: 1-Header.progressOff clip: true } + /* KeyProxy { id: proxy @@ -134,30 +135,14 @@ Item { wrap: false font.size: 11 color: "#555555" + focusOnPress: true anchors.left: UrlBox.left anchors.right: UrlBox.right anchors.leftMargin: 6 anchors.verticalCenter: UrlBox.verticalCenter anchors.verticalCenterOffset: 1 - - opacity: 0 } - Text { - id: ShowUrl - text: WebView.url == '' ? ' ' : WebView.url - font.size: 11 - color: "#555555" - anchors.left: UrlBox.left - anchors.right: UrlBox.right - anchors.leftMargin: 6 - anchors.verticalCenter: UrlBox.verticalCenter - anchors.verticalCenterOffset: 1 - } - } - MouseRegion { - anchors.fill: UrlBox - onClicked: { proxy.focus=true } } } diff --git a/demos/spreadsheet/spreadsheet.cpp b/demos/spreadsheet/spreadsheet.cpp index 742855e..d740aee 100644 --- a/demos/spreadsheet/spreadsheet.cpp +++ b/demos/spreadsheet/spreadsheet.cpp @@ -481,7 +481,7 @@ void SpreadSheet::setupContents() table->setItem(3, 0, new SpreadSheetItem("Lunch")); table->setItem(4, 0, new SpreadSheetItem("Flight (LA)")); table->setItem(5, 0, new SpreadSheetItem("Taxi")); - table->setItem(6, 0, new SpreadSheetItem("Diinner")); + table->setItem(6, 0, new SpreadSheetItem("Dinner")); table->setItem(7, 0, new SpreadSheetItem("Hotel")); table->setItem(8, 0, new SpreadSheetItem("Flight (Oslo)")); table->setItem(9, 0, new SpreadSheetItem("Total:")); diff --git a/doc/src/animation.qdoc b/doc/src/animation.qdoc index f8b6d4c..7a4e778 100644 --- a/doc/src/animation.qdoc +++ b/doc/src/animation.qdoc @@ -40,7 +40,7 @@ ****************************************************************************/ /*! - \page animation.html + \page animation-overview.html \title The Animation Framework \ingroup architecture \ingroup group_animation @@ -64,7 +64,10 @@ We will in this section take a high-level look at the animation framework's architecture and how it is used to animate Qt - properties. + properties. The following diagram shows the most important classes + in the animation framework. + + \image animations-architecture.png The animation framework foundation consists of the base class QAbstractAnimation, and its two subclasses QVariantAnimation and @@ -132,7 +135,7 @@ \endcode This code will move \c button from the top left corner of the - screen to the position (250, 250). + screen to the position (250, 250) in 10 seconds (10000 milliseconds). The example above will do a linear interpolation between the start and end value. It is also possible to set values @@ -162,7 +165,7 @@ that is not declared as a Qt property. The only requirement is that this value has a setter. You can then subclass the class containing the value and declare a property that uses this setter. - Note that all Qt properties requires a getter, so you will need to + Note that each Qt property requires a getter, so you will need to provide a getter yourself if this is not defined. \code @@ -184,9 +187,9 @@ \section1 Animations and the Graphics View Framework When you want to animate \l{QGraphicsItem}s, you also use - QPropertyAnimation. But, unfortunetly, QGraphicsItem does not - inherit QObject. A good solution is to subclass the graphics item - you wish to animate. This class will then also inherit QObject. + QPropertyAnimation. However, QGraphicsItem does not inherit QObject. + A good solution is to subclass the graphics item you wish to animate. + This class will then also inherit QObject. This way, QPropertyAnimation can be used for \l{QGraphicsItem}s. The example below shows how this is done. Another possibility is to inherit QGraphicsWidget, which already is a QObject. @@ -326,7 +329,7 @@ When using a \l{The State Machine Framework}{state machine}, we have a special state, QAnimationState, that will play one or more animations. - + The QState::addAnimatedTransition() convenience function lets you associate an animation to a state transition. The function will create the QAnimationState for you, and insert it into the state diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc index 976e2f1..3298699 100644 --- a/doc/src/declarative/elements.qdoc +++ b/doc/src/declarative/elements.qdoc @@ -140,6 +140,7 @@ The following table lists the Qml elements provided by the Qt Declarative module \o \list +\o \l Rotation \o \l Squish \o \l Rotation3D \endlist diff --git a/doc/src/declarative/qmlforcpp.qdoc b/doc/src/declarative/qmlforcpp.qdoc index e29b962..2898499 100644 --- a/doc/src/declarative/qmlforcpp.qdoc +++ b/doc/src/declarative/qmlforcpp.qdoc @@ -28,7 +28,8 @@ based on a simple declarative component description. \code - QmlComponent redRectangle("Rect { color: \"red\"; width: 100; height: 100 }"); + QmlEngine engine; + QmlComponent redRectangle(&engine, "Rect { color: \"red\"; width: 100; height: 100 }"); for (int ii = 0; ii < 100; ++ii) { QObject *rectangle = redRectangle.create(); // ... do something with the rectangle ... @@ -581,7 +582,8 @@ \row \o \code - QmlComponent component(xmlData); + QmlEngine engine; + QmlComponent component(&engine, qmlData); QObject *object = component.create(); // Will print "Hello world!" qDebug() << object->property("text2"); diff --git a/doc/src/diagrams/animations-architecture.svg b/doc/src/diagrams/animations-architecture.svg new file mode 100644 index 0000000..0246510 --- /dev/null +++ b/doc/src/diagrams/animations-architecture.svg @@ -0,0 +1,351 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="950.00006" + height="365.28983" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docname="animations-architecture.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + version="1.0"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0" + refX="0" + id="Arrow2Mend" + style="overflow:visible"> + <path + id="path3736" + style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" + transform="scale(-0.6,-0.6)" /> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0" + refX="0" + id="Arrow2Lend" + style="overflow:visible"> + <path + id="path3730" + style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" + transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Lend" + orient="auto" + refY="0" + refX="0" + id="Arrow1Lend" + style="overflow:visible"> + <path + id="path3712" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(-0.8,0,0,-0.8,-10,0)" /> + </marker> + <marker + inkscape:stockid="TriangleOutL" + orient="auto" + refY="0" + refX="0" + id="TriangleOutL" + style="overflow:visible"> + <path + id="path3852" + d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="scale(0.8,0.8)" /> + </marker> + <linearGradient + id="linearGradient3165"> + <stop + style="stop-color:#c8c8dc;stop-opacity:1;" + offset="0" + id="stop3167" /> + <stop + style="stop-color:#b4b4c8;stop-opacity:0;" + offset="1" + id="stop3169" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3165" + id="linearGradient3171" + x1="249.25" + y1="89.862183" + x2="475.75" + y2="89.862183" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.2195969,0,0,3.7006494,-257.93754,-842.42203)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3165" + id="linearGradient3183" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.2195969,0,0,3.7006494,-383.02298,-676.69717)" + x1="249.25" + y1="89.862183" + x2="475.75" + y2="89.862183" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3165" + id="linearGradient3191" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.2195969,0,0,3.7006494,-382.93759,-1004.922)" + x1="249.25" + y1="89.862183" + x2="475.75" + y2="89.862183" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3165" + id="linearGradient7165" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.2195969,0,0,3.7006494,-483.69907,-593.77419)" + x1="249.25" + y1="89.862183" + x2="475.75" + y2="89.862183" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3165" + id="linearGradient7195" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.2195969,0,0,3.7006494,-571.87523,-1167.422)" + x1="249.25" + y1="89.862183" + x2="475.75" + y2="89.862183" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3165" + id="linearGradient7203" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.2195969,0,0,3.7006494,-572.46592,-841.2256)" + x1="249.25" + y1="89.862183" + x2="475.75" + y2="89.862183" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.98994949" + inkscape:cx="276.75951" + inkscape:cy="155.06417" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:snap-bbox="true" + inkscape:window-width="1592" + inkscape:window-height="1124" + inkscape:window-x="0" + inkscape:window-y="0"> + <inkscape:grid + type="xygrid" + id="grid2383" + visible="true" + enabled="true" + units="pt" + spacingx="2pt" + spacingy="2pt" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-121.77519,-152.95286)"> + <rect + style="opacity:1;fill:url(#linearGradient3171);fill-opacity:1;stroke:#202020;stroke-width:1.35220754;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect2385" + width="49.409317" + height="277.54871" + x="-203.03828" + y="-648.64777" + ry="12.582828" + rx="10.562523" + transform="matrix(0,-1,-1,0,0,0)" /> + <text + xml:space="preserve" + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono;-inkscape-font-specification:DejaVu Sans Mono" + x="380.311" + y="185.86879" + id="text3173" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan3175" + x="380.311" + y="185.86879">QAbstractAnimation</tspan></text> + <rect + style="opacity:1;fill:url(#linearGradient3183);fill-opacity:1;stroke:#202020;stroke-width:1.35220754;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect3177" + width="49.409317" + height="277.54871" + x="-328.12369" + y="-482.92297" + ry="12.582828" + rx="10.562523" + transform="matrix(0,-1,-1,0,0,0)" /> + <text + xml:space="preserve" + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono;-inkscape-font-specification:DejaVu Sans Mono" + x="221.80489" + y="310.95419" + id="text3179" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan3181" + x="221.80489" + y="310.95419">QVariantAnimation</tspan></text> + <rect + style="opacity:1;fill:url(#linearGradient3191);fill-opacity:1;stroke:#202020;stroke-width:1.35220754;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect3185" + width="49.409317" + height="277.54871" + x="-328.03827" + y="-811.14777" + ry="12.582828" + rx="10.562523" + transform="matrix(0,-1,-1,0,0,0)" /> + <text + xml:space="preserve" + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono;-inkscape-font-specification:DejaVu Sans Mono" + x="564.13324" + y="310.86877" + id="text3187" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan3189" + x="564.13324" + y="310.86877">QAnimationGroup</tspan></text> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;marker-mid:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 346.77519,279.39048 L 346.77519,241.89048 L 509.27519,241.89048 L 509.27519,204.39048" + id="path3195" + sodipodi:nodetypes="cccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 671.77519,279.39048 L 671.77519,241.89048 L 509.27519,241.89048" + id="path7137" + sodipodi:nodetypes="ccc" /> + <rect + style="opacity:1;fill:url(#linearGradient7165);fill-opacity:1;stroke:#202020;stroke-width:1.35220754;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect7159" + width="49.409317" + height="277.54871" + x="-428.7998" + y="-400" + ry="12.582828" + rx="10.562523" + transform="matrix(0,-1,-1,0,0,0)" /> + <text + xml:space="preserve" + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono;-inkscape-font-specification:DejaVu Sans Mono" + x="131.66315" + y="411.63031" + id="text7161" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan7163" + x="131.66315" + y="411.63031">QPropertyAnimation</tspan></text> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;marker-mid:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 309.27519,379.39048 L 309.27519,329.39048" + id="path7167" + sodipodi:nodetypes="cc" /> + <rect + style="opacity:1;fill:url(#linearGradient7195);fill-opacity:1;stroke:#202020;stroke-width:1.35220754;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect7189" + width="49.409317" + height="375" + x="-516.97589" + y="-1071.0991" + ry="12.582828" + rx="10.562523" + transform="matrix(0,-1,-1,0,0,0)" /> + <text + xml:space="preserve" + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono;-inkscape-font-specification:DejaVu Sans Mono" + x="703.17139" + y="499.8064" + id="text7191" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan7193" + x="703.17139" + y="499.8064">QSequentialAnimationGroup</tspan></text> + <rect + style="opacity:1;fill:url(#linearGradient7203);fill-opacity:1;stroke:#202020;stroke-width:1.35220754;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect7197" + width="50" + height="350" + x="-517.56659" + y="-647.45129" + ry="12.582828" + rx="10.562523" + transform="matrix(0,-1,-1,0,0,0)" /> + <text + xml:space="preserve" + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono;-inkscape-font-specification:DejaVu Sans Mono" + x="306.46109" + y="500.39709" + id="text7199" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan7201" + x="306.46109" + y="500.39709">QParallelAnimationGroup</tspan></text> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 859.27519,466.89048 L 859.27519,391.89048 L 671.77519,391.89048" + id="path7205" + sodipodi:nodetypes="ccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;marker-mid:none;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 496.77519,466.89048 L 496.77519,391.89048 L 671.77519,391.89048 L 671.77519,329.39048" + id="path7207" + sodipodi:nodetypes="cccc" /> + </g> +</svg> diff --git a/doc/src/examples-overview.qdoc b/doc/src/examples-overview.qdoc index 549574d..92ccd4e 100644 --- a/doc/src/examples-overview.qdoc +++ b/doc/src/examples-overview.qdoc @@ -319,6 +319,14 @@ from displaying Web pages within a Qt user interface to an implementation of a basic function Web browser. + \section1 \l{Qt Examples#State Machine}{State Machine} + + Qt provides a powerful hierchical finite state machine through the Qt State + Machine classes. + + These examples demonstrate the fundamental aspects of implementing + Statecharts with Qt. + \section1 \l{Qt Examples#Qt for Embedded Linux}{Qt for Embedded Linux} \l{Qt Examples#Qt for Embedded Linux}{\inlineimage qt-embedded-examples.png diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc index 06d7727..6603390 100644 --- a/doc/src/examples.qdoc +++ b/doc/src/examples.qdoc @@ -311,7 +311,12 @@ \section1 State Machine \list + \o \l{statemachine/eventtransitions}{Event Transitions}\raisedaster + \o \l{statemachine/factorial}{Factorial States}\raisedaster + \o \l{statemachine/pingpong}{Ping Pong States}\raisedaster \o \l{statemachine/trafficlight}{Traffic Light}\raisedaster + \o \l{statemachine/twowaybutton}{Two-way Button}\raisedaster + \o \l{statemachine/tankgame}{Tank Game}\raisedaster \endlist \section1 Threads diff --git a/doc/src/examples/contiguouscache.qdoc b/doc/src/examples/contiguouscache.qdoc new file mode 100644 index 0000000..fbfde3f --- /dev/null +++ b/doc/src/examples/contiguouscache.qdoc @@ -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 documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example tools/contiguouscache + \title Contiguous Cache Example + + The Contiguous Cache example shows how to use QContiguousCache to manage memory usage for + very large models. In some environments memory is limited and, even when it + isn't, users still dislike an application using excessive memory. + Using QContiguousCache to manage a list, rather than loading + the entire list into memory, allows the application to limit the amount + of memory it uses, regardless of the size of the data set it accesses + + The simplest way to use QContiguousCache is to cache as items are requested. When + a view requests an item at row N it is also likely to ask for items at rows near + to N. + + \snippet examples/tools/contiguouscache/randomlistmodel.cpp 0 + + After getting the row, the class determines if the row is in the bounds + of the contiguous cache's current range. It would have been equally valid to + simply have the following code instead. + + \code + while (row > m_rows.lastIndex()) + m_rows.append(fetchWord(m_rows.lastIndex()+1); + while (row < m_rows.firstIndex()) + m_rows.prepend(fetchWord(m_rows.firstIndex()-1); + \endcode + + However a list will often jump rows if the scroll bar is used directly, resulting in + the code above causing every row between the old and new rows to be fetched. + + Using QContiguousCache::lastIndex() and QContiguousCache::firstIndex() allows + the example to determine what part of the list the cache is currently caching. + These values don't represent the indexes into the cache's own memory, but rather + a virtual infinite array that the cache represents. + + By using QContiguousCache::append() and QContiguousCache::prepend() the code ensures + that items that may be still on the screen are not lost when the requested row + has not moved far from the current cache range. QContiguousCache::insert() can + potentially remove more than one item from the cache as QContiguousCache does not + allow for gaps. If your cache needs to quickly jump back and forth between + rows with significant gaps between them consider using QCache instead. + + And thats it. A perfectly reasonable cache, using minimal memory for a very large + list. In this case the accessor for getting the words into the cache + generates random information rather than fixed information. This allows you + to see how the cache range is kept for a local number of rows when running the + example. + + \snippet examples/tools/contiguouscache/randomlistmodel.cpp 1 + + It is also worth considering pre-fetching items into the cache outside of the + application's paint routine. This can be done either with a separate thread + or using a QTimer to incrementally expand the range of the cache prior to + rows being requested out of the current cache range. +*/ diff --git a/doc/src/examples/eventtransitions.qdoc b/doc/src/examples/eventtransitions.qdoc new file mode 100644 index 0000000..3b956bb --- /dev/null +++ b/doc/src/examples/eventtransitions.qdoc @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example statemachine/eventtransitions + \title Event Transitions Example + + The Event Transitions example shows how to use event transitions, a + feature of \l{The State Machine Framework}. + + \snippet examples/statemachine/eventtransitions/main.cpp 0 + + The \c Window class's constructors begins by creating a button. + + \snippet examples/statemachine/eventtransitions/main.cpp 1 + + Two states, \c s1 and \c s2, are created; upon entry they will assign + "Outside" and "Inside" to the button's text, respectively. + + \snippet examples/statemachine/eventtransitions/main.cpp 2 + + When the button receives an event of type QEvent::Enter and the state + machine is in state \c s1, the machine will transition to state \c s2. + + \snippet examples/statemachine/eventtransitions/main.cpp 3 + + When the button receives an event of type QEvent::Leave and the state + machine is in state \c s2, the machine will transition back to state \c + s1. + + \snippet examples/statemachine/eventtransitions/main.cpp 4 + + Next, the state \c s3 is created. \c s3 will be entered when the button + receives an event of type QEvent::MouseButtonPress and the state machine + is in state \c s2. When the button receives an event of type + QEvent::MouseButtonRelease and the state machine is in state \c s3, the + machine will transition back to state \c s2. + + \snippet examples/statemachine/eventtransitions/main.cpp 5 + + Finally, the states are added to the machine as top-level states, the + initial state is set to be \c s1 ("Outside"), and the machine is started. + + \snippet examples/statemachine/eventtransitions/main.cpp 6 + + The main() function constructs a Window object and shows it. + +*/ diff --git a/doc/src/examples/factorial.qdoc b/doc/src/examples/factorial.qdoc new file mode 100644 index 0000000..2a72e0a --- /dev/null +++ b/doc/src/examples/factorial.qdoc @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example statemachine/factorial + \title Factorial States Example + + The Factorial States example shows how to use \l{The State Machine + Framework} to calculate the factorial of an integer. + + The statechart for calculating the factorial looks as follows: + + \img factorial-example.png + \omit + \caption This is a caption + \endomit + + In other words, the state machine calculates the factorial of 6 and prints + the result. + + \snippet examples/statemachine/factorial/main.cpp 0 + + The Factorial class is used to hold the data of the computation, \c x and + \c fac. It also provides a signal that's emitted whenever the value of \c + x changes. + + \snippet examples/statemachine/factorial/main.cpp 1 + + The FactorialLoopTransition class implements the guard (\c x > 1) and + calculations (\c fac = \c x * \c fac; \c x = \c x - 1) of the factorial + loop. + + \snippet examples/statemachine/factorial/main.cpp 2 + + The FactorialDoneTransition class implements the guard (\c x <= 1) that + terminates the factorial computation. It also prints the final result to + standard output. + + \snippet examples/statemachine/factorial/main.cpp 3 + + The application's main() function first creates the application object, a + Factorial object and a state machine. + + \snippet examples/statemachine/factorial/main.cpp 4 + + The \c compute state is created, and the initial values of \c x and \c fac + are defined. A FactorialLoopTransition object is created and added to the + state. + + \snippet examples/statemachine/factorial/main.cpp 5 + + A final state, \c done, is created, and a FactorialDoneTransition object + is created with \c done as its target state. The transition is then added + to the \c compute state. + + \snippet examples/statemachine/factorial/main.cpp 6 + + The machine's initial state is set to be the \c compute state. We connect + the QStateMachine::finished() signal to the QCoreApplication::quit() slot, + so the application will quit when the state machine's work is + done. Finally, the state machine is started, and the application's event + loop is entered. + + */ diff --git a/doc/src/examples/fancybrowser.qdoc b/doc/src/examples/fancybrowser.qdoc index 9001c20..631aff9 100644 --- a/doc/src/examples/fancybrowser.qdoc +++ b/doc/src/examples/fancybrowser.qdoc @@ -40,12 +40,109 @@ ****************************************************************************/ /*! - \example webkit/fancybrowser - \title Fancy Browser Example + \example webkit/fancybrowser + \title Fancy Browser Example The Fancy Browser example shows how to use jQuery with QtWebKit to - make a web browser with some special effects and content manipulation. + create a web browser with special effects and content + manipulation. \image fancybrowser-example.png + The application makes use of QWebFrame::evaluateJavaScript to + evaluate the jQuery JavaScript code. A QMainWindow with a QWebView + as central widget builds up the browser itself. + + \section1 MainWindow Class Definition + + The \c MainWindow class inherits QMainWindow. It implements a number of + slots to perform actions on both the application and on the web content. + + \snippet examples/webkit/fancybrowser/mainwindow.h 1 + + We also declare a QString that contains the jQuery, a QWebView + that displays the web content, and a QLineEdit that acts as the + address bar. + + \section1 MainWindow Class Implementation + + We start by implementing the constructor. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 1 + + The first part of the constructor sets the value of \c progress to + 0. This value will be used later in the code to visualize the + loading of a webpage. + + Next, the jQuery library is loaded using a QFile and reading the file + content. The jQuery library is a JavaScript library that provides different + functions for manipulating HTML. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 2 + + The second part of the constructor creates a QWebView and connects + slots to the views signals. Furthermore, we create a QLineEdit as + the browsers address bar. We then set the horizontal QSizePolicy + to fill the available area in the browser at all times. We add the + QLineEdit to a QToolbar together with a set of navigation actions + from QWebView::pageAction. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 3 + + The third and last part of the constructor implements two QMenus and assigns + a set of actions to them. The last line sets the QWebView as the central + widget in the QMainWindow. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 4 + + When the page is loaded, \c adjustLocation() updates the address + bar; \c adjustLocation() is triggered by the \c loadFinished() + signal in QWebView. In \c changeLocation() we create a QUrl + object, and then use it to load the page into the QWebView. When + the new web page has finished loading, \c adjustLocation() will be + run once more to update the address bar. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 5 + + \c adjustTitle() sets the window title and displays the loading + progress. This slot is triggered by the \c titleChanged() signal + in QWebView. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 6 + + When a web page has loaded, \c finishLoading() is triggered by the + \c loadFinished() signal in QWebView. \c finishLoading() then updates the + progress in the title bar and calls \c evaluateJavaScript() to evaluate the + jQuery library. This evaluates the JavaScript against the current web page. + What that means is that the JavaScript can be viewed as part of the content + loaded into the QWebView, and therefore needs to be loaded every time a new + page is loaded. Once the jQuery library is loaded, we can start executing + the different jQuery functions in the browser. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 7 + + The first jQuery-based function, \c highlightAllLinks(), is designed to + highlight all links in the current webpage. The JavaScript code looks + for web elements named \e {a}, which is the tag for a hyperlink. + For each such element, the background color is set to be yellow by + using CSS. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 8 + + The \c rotateImages() function rotates the images on the current + web page. Webkit supports CSS transforms and this JavaScript code + looks up all \e {img} elements and rotates the images 180 degrees + and then back again. + + \snippet examples/webkit/fancybrowser/mainwindow.cpp 9 + + The remaining four methods remove different elements from the current web + page. \c removeGifImages() removes all Gif images on the page by looking up + the \e {src} attribute of all the elements on the web page. Any element with + a \e {gif} file as its source is removed. \c removeInlineFrames() removes all + \e {iframe} or inline elements. \c removeObjectElements() removes all + \e {object} elements, and \c removeEmbeddedElements() removes any elements + such as plugins embedded on the page using the \e {embed} tag. + */ + diff --git a/doc/src/examples/pingpong.qdoc b/doc/src/examples/pingpong.qdoc new file mode 100644 index 0000000..040e429 --- /dev/null +++ b/doc/src/examples/pingpong.qdoc @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example statemachine/pingpong + \title Ping Pong States Example + + The Ping Pong States example shows how to use parallel states together + with custom events and transitions in \l{The State Machine Framework}. + + This example implements a statechart where two states communicate by + posting events to the state machine. The state chart looks as follows: + + \img pingpong-example.png + \omit + \caption This is a caption + \endomit + + The \c pinger and \c ponger states are parallel states, i.e. they are + entered simultaneously and will take transitions independently of + eachother. + + The \c pinger state will post the first \c ping event upon entry; the \c + ponger state will respond by posting a \c pong event; this will cause the + \c pinger state to post a new \c ping event; and so on. + + \snippet examples/statemachine/pingpong/main.cpp 0 + + Two custom events are defined, \c PingEvent and \c PongEvent. + + \snippet examples/statemachine/pingpong/main.cpp 1 + + The \c Pinger class defines a state that posts a \c PingEvent to the state + machine when the state is entered. + + \snippet examples/statemachine/pingpong/main.cpp 2 + + The \c PingTransition class defines a transition that is triggered by + events of type \c PingEvent, and that posts a \c PongEvent (with a delay + of 500 milliseconds) to the state machine when the transition is + triggered. + + \snippet examples/statemachine/pingpong/main.cpp 3 + + The \c PongTransition class defines a transition that is triggered by + events of type \c PongEvent, and that posts a \c PingEvent (with a delay + of 500 milliseconds) to the state machine when the transition is + triggered. + + \snippet examples/statemachine/pingpong/main.cpp 4 + + The main() function begins by creating a state machine and a parallel + state group. + + \snippet examples/statemachine/pingpong/main.cpp 5 + + Next, the \c pinger and \c ponger states are created, with the parallel + state group as their parent state. Note that the transitions are \e + targetless. When such a transition is triggered, the source state won't be + exited and re-entered; only the transition's onTransition() function will + be called, and the state machine's configuration will remain the same, + which is precisely what we want in this case. + + \snippet examples/statemachine/pingpong/main.cpp 6 + + Finally, the group is added to the state machine, the machine is started, + and the application event loop is entered. + + */ diff --git a/doc/src/examples/tankgame.qdoc b/doc/src/examples/tankgame.qdoc new file mode 100644 index 0000000..ab3e0f4 --- /dev/null +++ b/doc/src/examples/tankgame.qdoc @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example statemachine/tankgame + \title Tank Game Example + + The Tank Game example is part of the in \l{The State Machine Framework}. It shows how to use + parallel states to implement artificial intelligence controllers that run in parallel, and error + states to handle run-time errors in parts of the state graph created by external plugins. + + \image tankgame-example.png + + In this example we write a simple game. The application runs a state machine with two main + states: A "stopped" state and a "running" state. The user can load plugins from the disk by + selecting the "Add tank" menu item. + + When the "Add tank" menu item is selected, the "plugins" subdirectory in the example's + directory is searched for compatible plugins. If any are found, they will be listed in a + dialog box created using QInputDialog::getItem(). + + \snippet examples/statemachine/tankgame/mainwindow.cpp 1 + + If the user selects a plugin, the application will construct a TankItem object, which inherits + from QGraphicsItem and QObject, and which implements an agreed-upon interface using the + meta-object mechanism. + + \snippet examples/statemachine/tankgame/tankitem.h 0 + + The tank item will be passed to the plugin's create() function. This will in turn return a + QState object which is expected to implement an artificial intelligence which controls the + tank and attempts to destroy other tanks it detects. + + \snippet examples/statemachine/tankgame/mainwindow.cpp 2 + + Each returned QState object becomes a descendant of a \c region in the "running" state, which is + defined as a parallel state. This means that entering the "running" state will cause each of the + plugged-in QState objects to be entered simultaneously, allowing the tanks to run independently + of each other. + + \snippet examples/statemachine/tankgame/mainwindow.cpp 0 + + The maximum number of tanks on the map is four, and when this number is reached, the + "Add tank" menu item should be disabled. This is implemented by giving the "stopped" state two + children which define whether the map is full or not. + + \snippet examples/statemachine/tankgame/mainwindow.cpp 5 + + To make sure that we go into the correct child state when returning from the "running" state + (if the "Stop game" menu item is selected while the game is running) we also give the "stopped" + state a history state which we make the initial state of "stopped" state. + + \snippet examples/statemachine/tankgame/mainwindow.cpp 3 + + Since part of the state graph is defined by external plugins, we have no way of controlling + whether they contain errors. By default, run-time errors are handled in the state machine by + entering a top level state which prints out an error message and never exits. If we were to + use this default behavior, a run-time error in any of the plugins would cause the "running" + state to exit, and thus all the other tanks to stop running as well. A better solution would + be if the broken plugin was disabled and the rest of the tanks allowed to continue as before. + + This is done by setting the error state of the plugin's top-most state to a special error state + defined specifically for the plugin in question. + + \snippet examples/statemachine/tankgame/mainwindow.cpp 4 + + If a run-time error occurs in \c pluginState or any of its descendants, the state machine will + search the hierarchy of ancestors until it finds a state whose error state is different from + \c null. (Note that if we are worried that a plugin could inadvertedly be overriding our + error state, we could search the descendants of \c pluginState and verify that their error + states are set to \c null before accepting the plugin.) + + The specialized \c errorState sets the "enabled" property of the tank item in question to false, + causing it to be painted with a red cross over it to indicate that it is no longer running. + Since the error state is a child of the same region in the parallel "running" state as + \c pluginState, it will not exit the "running" state, and the other tanks will continue running + without disruption. + +*/ diff --git a/doc/src/examples/trafficlight.qdoc b/doc/src/examples/trafficlight.qdoc index 16ee8ad..ae62127 100644 --- a/doc/src/examples/trafficlight.qdoc +++ b/doc/src/examples/trafficlight.qdoc @@ -1,11 +1,41 @@ /**************************************************************************** ** -** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $TROLLTECH_DUAL_LICENSE$ +** $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$ ** ****************************************************************************/ @@ -26,30 +56,41 @@ \snippet examples/statemachine/trafficlight/main.cpp 0 The LightWidget class represents a single light of the traffic light. It - provides a setOn() function to turn the light on or off. It paints itself - in the color that's passed to the constructor. + provides an \c on property and two slots, turnOn() and turnOff(), to turn + the light on and off, respectively. The widget paints itself in the color + that's passed to the constructor. - \snippet examples/statemachine/trafficlight/main.cpp 2 + \snippet examples/statemachine/trafficlight/main.cpp 1 The TrafficLightWidget class represents the visual part of the traffic - light; it's a widget that contains three lights, and provides accessor - functions for these. + light; it's a widget that contains three lights arranged vertically, and + provides accessor functions for these. - \snippet examples/statemachine/trafficlight/main.cpp 1 + \snippet examples/statemachine/trafficlight/main.cpp 2 - The LightState class represents a state that turns a light on when the - state is entered, and off when the state is exited. The class is a timer, - and as we shall see the timeout is used to transition from one LightState - to another. + The createLightState() function creates a state that turns a light on when + the state is entered, and off when the state is exited. The state uses a + timer, and as we shall see the timeout is used to transition from one + LightState to another. Here is the statechart for the light state: + + \img trafficlight-example1.png + \omit + \caption This is a caption + \endomit \snippet examples/statemachine/trafficlight/main.cpp 3 - The TrafficLight class combines the TrafficLightWidget with control flow - based on the LightState class. The state graph has four states: - red-to-yellow, yellow-to-green, green-to-yellow and yellow-to-red. The - initial state is red-to-yellow; when the state's timer times out, the - state machine transitions to yellow-to-green. The same process repeats - through the other states. + The TrafficLight class combines the TrafficLightWidget with a state + machine. The state graph has four states: red-to-yellow, yellow-to-green, + green-to-yellow and yellow-to-red. The initial state is red-to-yellow; + when the state's timer times out, the state machine transitions to + yellow-to-green. The same process repeats through the other states. + This is what the statechart looks like: + + \img trafficlight-example2.png + \omit + \caption This is a caption + \endomit \snippet examples/statemachine/trafficlight/main.cpp 4 diff --git a/doc/src/examples/twowaybutton.qdoc b/doc/src/examples/twowaybutton.qdoc new file mode 100644 index 0000000..87de2e8 --- /dev/null +++ b/doc/src/examples/twowaybutton.qdoc @@ -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 documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example statemachine/twowaybutton + \title Two-way Button Example + + The Two-way button example shows how to use \l{The State Machine + Framework} to implement a simple state machine that toggles the current + state when a button is clicked. + + \snippet examples/statemachine/twowaybutton/main.cpp 0 + + The application's main() function begins by constructing the application + object, a button and a state machine. + + \snippet examples/statemachine/twowaybutton/main.cpp 1 + + The state machine has two states; \c on and \c off. When either state is + entered, the text of the button will be set accordingly. + + \snippet examples/statemachine/twowaybutton/main.cpp 2 + + When the state machine is in the \c off state and the button is clicked, + it will transition to the \c on state; when the state machine is in the \c + on state and the button is clicked, it will transition to the \c off + state. + + \snippet examples/statemachine/twowaybutton/main.cpp 3 + + The states are added to the state machine; they become top-level (sibling) + states. + + \snippet examples/statemachine/twowaybutton/main.cpp 4 + + The initial state is \c off; this is the state the state machine will + immediately transition to once the state machine is started. + + \snippet examples/statemachine/twowaybutton/main.cpp 5 + + Finally, the button is resized and made visible, and the application event + loop is entered. + +*/ diff --git a/doc/src/groups.qdoc b/doc/src/groups.qdoc index 0411c3a..3c4da53 100644 --- a/doc/src/groups.qdoc +++ b/doc/src/groups.qdoc @@ -69,14 +69,14 @@ */ /*! - \group animations + \group animation \ingroup groups \title Animation Framework \brief Classes for animations, states and transitions. These classes provide a framework for creating both simple and complex - animations. The Animation Framework also provides states and animated + animations. \l{The Animation Framework} also provides states and animated transitions, making it easy to create animated stateful forms. */ diff --git a/doc/src/images/animations-architecture.png b/doc/src/images/animations-architecture.png Binary files differnew file mode 100644 index 0000000..9b581af --- /dev/null +++ b/doc/src/images/animations-architecture.png diff --git a/doc/src/images/factorial-example.png b/doc/src/images/factorial-example.png Binary files differnew file mode 100644 index 0000000..8fb1cc6 --- /dev/null +++ b/doc/src/images/factorial-example.png diff --git a/doc/src/images/pingpong-example.png b/doc/src/images/pingpong-example.png Binary files differnew file mode 100644 index 0000000..af707e4 --- /dev/null +++ b/doc/src/images/pingpong-example.png diff --git a/doc/src/images/statemachine-button-history.png b/doc/src/images/statemachine-button-history.png Binary files differindex cd66478..7f51cae 100644 --- a/doc/src/images/statemachine-button-history.png +++ b/doc/src/images/statemachine-button-history.png diff --git a/doc/src/images/statemachine-button-nested.png b/doc/src/images/statemachine-button-nested.png Binary files differindex 60360d1..762ac14 100644 --- a/doc/src/images/statemachine-button-nested.png +++ b/doc/src/images/statemachine-button-nested.png diff --git a/doc/src/images/statemachine-button.png b/doc/src/images/statemachine-button.png Binary files differindex 75d9e53..10102bd 100644 --- a/doc/src/images/statemachine-button.png +++ b/doc/src/images/statemachine-button.png diff --git a/doc/src/images/statemachine-customevents.png b/doc/src/images/statemachine-customevents.png Binary files differnew file mode 100644 index 0000000..62a4222 --- /dev/null +++ b/doc/src/images/statemachine-customevents.png diff --git a/doc/src/images/statemachine-customevents2.png b/doc/src/images/statemachine-customevents2.png Binary files differnew file mode 100644 index 0000000..57b37ef --- /dev/null +++ b/doc/src/images/statemachine-customevents2.png diff --git a/doc/src/images/statemachine-finished.png b/doc/src/images/statemachine-finished.png Binary files differindex 802621e..0ac081d 100644 --- a/doc/src/images/statemachine-finished.png +++ b/doc/src/images/statemachine-finished.png diff --git a/doc/src/images/statemachine-nonparallel.png b/doc/src/images/statemachine-nonparallel.png Binary files differindex 1fe60d8..f9850a7 100644 --- a/doc/src/images/statemachine-nonparallel.png +++ b/doc/src/images/statemachine-nonparallel.png diff --git a/doc/src/images/statemachine-parallel.png b/doc/src/images/statemachine-parallel.png Binary files differindex 1868792..a65c297 100644 --- a/doc/src/images/statemachine-parallel.png +++ b/doc/src/images/statemachine-parallel.png diff --git a/doc/src/images/tankgame-example.png b/doc/src/images/tankgame-example.png Binary files differnew file mode 100644 index 0000000..9e17e30 --- /dev/null +++ b/doc/src/images/tankgame-example.png diff --git a/doc/src/images/trafficlight-example1.png b/doc/src/images/trafficlight-example1.png Binary files differnew file mode 100644 index 0000000..ec8c7ff --- /dev/null +++ b/doc/src/images/trafficlight-example1.png diff --git a/doc/src/images/trafficlight-example2.png b/doc/src/images/trafficlight-example2.png Binary files differnew file mode 100644 index 0000000..a12e4db --- /dev/null +++ b/doc/src/images/trafficlight-example2.png diff --git a/doc/src/layout.qdoc b/doc/src/layout.qdoc index 55dfd8b..196999b 100644 --- a/doc/src/layout.qdoc +++ b/doc/src/layout.qdoc @@ -315,7 +315,11 @@ \snippet doc/src/snippets/code/doc_src_layout.qdoc 1 - First we define two functions that iterate over the layout: \c{itemAt()} + First we define \c{count()} to fetch the number of items in the list. + + \snippet doc/src/snippets/code/doc_src_layout.qdoc 2 + + Then we define two functions that iterate over the layout: \c{itemAt()} and \c{takeAt()}. These functions are used internally by the layout system to handle deletion of widgets. They are also available for application programmers. @@ -326,7 +330,7 @@ structure, we may have to spend more effort defining a linear order for the items. - \snippet doc/src/snippets/code/doc_src_layout.qdoc 2 + \snippet doc/src/snippets/code/doc_src_layout.qdoc 3 \c{addItem()} implements the default placement strategy for layout items. This function must be implemented. It is used by QLayout::add(), by the @@ -336,26 +340,26 @@ QGridLayout::addItem(), QGridLayout::addWidget(), and QGridLayout::addLayout(). - \snippet doc/src/snippets/code/doc_src_layout.qdoc 3 + \snippet doc/src/snippets/code/doc_src_layout.qdoc 4 The layout takes over responsibility of the items added. Since QLayoutItem does not inherit QObject, we must delete the items manually. The function QLayout::deleteAllItems() uses \c{takeAt()} defined above to delete all the items in the layout. - \snippet doc/src/snippets/code/doc_src_layout.qdoc 4 + \snippet doc/src/snippets/code/doc_src_layout.qdoc 5 The \c{setGeometry()} function actually performs the layout. The rectangle supplied as an argument does not include \c{margin()}. If relevant, use \c{spacing()} as the distance between items. - \snippet doc/src/snippets/code/doc_src_layout.qdoc 5 + \snippet doc/src/snippets/code/doc_src_layout.qdoc 6 \c{sizeHint()} and \c{minimumSize()} are normally very similar in implementation. The sizes returned by both functions should include \c{spacing()}, but not \c{margin()}. - \snippet doc/src/snippets/code/doc_src_layout.qdoc 6 + \snippet doc/src/snippets/code/doc_src_layout.qdoc 7 \section2 Further Notes diff --git a/doc/src/qset.qdoc b/doc/src/qset.qdoc index 9795123..2d12661 100644 --- a/doc/src/qset.qdoc +++ b/doc/src/qset.qdoc @@ -447,7 +447,7 @@ \fn QSet::const_iterator QSet::insert(const T &value) Inserts item \a value into the set, if \a value isn't already - in the set, and returns an iterator positioned at the inserted + in the set, and returns an iterator pointing at the inserted item. \sa operator<<(), remove(), contains() diff --git a/doc/src/snippets/code/doc_src_layout.qdoc b/doc/src/snippets/code/doc_src_layout.qdoc index 48e10e9..fedcf0c 100644 --- a/doc/src/snippets/code/doc_src_layout.qdoc +++ b/doc/src/snippets/code/doc_src_layout.qdoc @@ -2,23 +2,21 @@ #ifndef CARD_H #define CARD_H -#include <QLayout> +#include <QtGui> #include <QList> class CardLayout : public QLayout { public: - CardLayout(QWidget *parent, int dist) - : QLayout(parent, 0, dist) {} - CardLayout(QLayout *parent, int dist) - : QLayout(parent, dist) {} - CardLayout(int dist) - : QLayout(dist) {} + CardLayout(QWidget *parent, int dist): QLayout(parent, 0, dist) {} + CardLayout(QLayout *parent, int dist): QLayout(parent, dist) {} + CardLayout(int dist): QLayout(dist) {} ~CardLayout(); void addItem(QLayoutItem *item); QSize sizeHint() const; QSize minimumSize() const; + QLayoutItem *count() const; QLayoutItem *itemAt(int) const; QLayoutItem *takeAt(int); void setGeometry(const QRect &rect); @@ -31,11 +29,18 @@ private: //! [1] -#include "card.h" +//#include "card.h" //! [1] - //! [2] +QLayoutItem *CardLayout::count() const +{ + // QList::size() returns the number of QLayoutItems in the list + return list.size(); +} +//! [2] + +//! [3] QLayoutItem *CardLayout::itemAt(int idx) const { // QList::value() performs index checking, and returns 0 if we are @@ -48,26 +53,26 @@ QLayoutItem *CardLayout::takeAt(int idx) // QList::take does not do index checking return idx >= 0 && idx < list.size() ? list.takeAt(idx) : 0; } -//! [2] +//! [3] -//! [3] +//! [4] void CardLayout::addItem(QLayoutItem *item) { list.append(item); } -//! [3] +//! [4] -//! [4] +//! [5] CardLayout::~CardLayout() { deleteAllItems(); } -//! [4] +//! [5] -//! [5] +//! [6] void CardLayout::setGeometry(const QRect &r) { QLayout::setGeometry(r); @@ -85,10 +90,10 @@ void CardLayout::setGeometry(const QRect &r) ++i; } } -//! [5] +//! [6] -//! [6] +//! [7] QSize CardLayout::sizeHint() const { QSize s(0,0); @@ -116,4 +121,4 @@ QSize CardLayout::minimumSize() const } return s + n*QSize(spacing(), spacing()); } -//! [6] +//! [7]
\ No newline at end of file diff --git a/doc/src/snippets/sqldatabase/sqldatabase.cpp b/doc/src/snippets/sqldatabase/sqldatabase.cpp index ae176ac..06afa0c 100644 --- a/doc/src/snippets/sqldatabase/sqldatabase.cpp +++ b/doc/src/snippets/sqldatabase/sqldatabase.cpp @@ -524,7 +524,7 @@ protected: bool fetchLast() { return false; } int size() { return 0; } int numRowsAffected() { return 0; } - QSqlRecord record() { return QSqlRecord(); } + QSqlRecord record() const { return QSqlRecord(); } }; //! [47] diff --git a/doc/src/statemachine.qdoc b/doc/src/statemachine.qdoc index 60ae815..5a89f4d 100644 --- a/doc/src/statemachine.qdoc +++ b/doc/src/statemachine.qdoc @@ -1,11 +1,41 @@ /**************************************************************************** ** -** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $TROLLTECH_DUAL_LICENSE$ +** $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$ ** ****************************************************************************/ @@ -13,6 +43,7 @@ \page statemachine-api.html \title The State Machine Framework \brief An overview of the State Machine framework for constructing and executing state graphs. + \ingroup architecture \tableofcontents @@ -33,10 +64,10 @@ The State Machine framework provides an API and execution model that can be used to effectively embed the elements and semantics of statecharts in Qt - applications. The framework integrates tightly with Qt's existing event - system and meta-object system; for example, transitions between states can - be triggered by signals, and states can be configured to set properties and - invoke methods on QObjects. + applications. The framework integrates tightly with Qt's meta-object system; + for example, transitions between states can be triggered by signals, and + states can be configured to set properties and invoke methods on QObjects. + Qt's event system is used to drive the state machines. \section1 A Simple State Machine @@ -52,34 +83,49 @@ \endomit The following snippet shows the code needed to create such a state machine. + First, we create the state machine and states: \code QStateMachine machine; QState *s1 = new QState(); QState *s2 = new QState(); QState *s3 = new QState(); + \endcode + + Then, we create the transitions by using the QState::addTransition() + function: + \code s1->addTransition(button, SIGNAL(clicked()), s2); s2->addTransition(button, SIGNAL(clicked()), s3); s3->addTransition(button, SIGNAL(clicked()), s1); + \endcode + + Next, we add the states to the machine and set the machine's initial state: + \code machine.addState(s1); machine.addState(s2); machine.addState(s3); machine.setInitialState(s1); + \endcode + + Finally, we start the state machine: + \code machine.start(); \endcode - Once the state machine has been set up, you need to start it by calling - QStateMachine::start(). The state machine executes asynchronously, i.e. it - becomes part of your application's event loop. + The state machine executes asynchronously, i.e. it becomes part of your + application's event loop. + + \section1 Doing Useful Work on State Entry and Exit - The above state machine is perfectly fine, but it doesn't \e do anything; it - merely transitions from one state to another. The QState::assignProperty() - function can be used to have a state set a property of a QObject when the - state is entered. In the following snippet, the value that should be - assigned to a QLabel's text property is specified for each state: + The above state machine merely transitions from one state to another, it + doesn't perform any operations. The QState::assignProperty() function can be + used to have a state set a property of a QObject when the state is + entered. In the following snippet, the value that should be assigned to a + QLabel's text property is specified for each state: \code s1->assignProperty(label, "text", "In state s1"); @@ -90,20 +136,32 @@ When any of the states is entered, the label's text will be changed accordingly. - The QActionState::entered() signal is emitted when the state is entered. In the + The QState::entered() signal is emitted when the state is entered, and the + QState::exited() signal is emitted when the state is exited. In the following snippet, the button's showMaximized() slot will be called when - state \c s3 is entered: + state \c s3 is entered, and the button's showMinimized() slot will be called + when \c s3 is exited: \code QObject::connect(s3, SIGNAL(entered()), button, SLOT(showMaximized())); + QObject::connect(s3, SIGNAL(exited()), button, SLOT(showMinimized())); \endcode - \section1 Sharing Transitions By Grouping States + Custom states can reimplement QAbstractState::onEntry() and + QAbstractState::onExit(). + + \section1 State Machines That Finish The state machine defined in the previous section never finishes. In order for a state machine to be able to finish, it needs to have a top-level \e - final state. When the state machine enters a top-level final state, the - machine will emit the finished() signal and halt. + final state (QFinalState object). When the state machine enters a top-level + final state, the machine will emit the QStateMachine::finished() signal and + halt. + + All you need to do to introduce a final state in the graph is create a + QFinalState object and use it as the target of one or more transitions. + + \section1 Sharing Transitions By Grouping States Assume we wanted the user to be able to quit the application at any time by clicking a Quit button. In order to achieve this, we need to create a final @@ -165,6 +223,9 @@ s12>addTransition(quitButton, SIGNAL(clicked()), s12); \endcode + A transition can have any state as its target, i.e. the target state does + not have to be on the same level in the state hierarchy as the source state. + \section1 Using History States to Save and Restore the Current State Imagine that we wanted to add an "interrupt" mechanism to the example @@ -251,19 +312,334 @@ QState *s12 = new QState(s1); \endcode + When a parallel state group is entered, all its child states will be + simultaneously entered. Transitions within the individual child states + operate normally. However, any of the child states may take a transition + outside the parent state. When this happens, the parent state and all of its + child states are exited. + \section1 Detecting that a Composite State has Finished - A child state can be final; when a final child state is entered, the parent - state emits the QState::finished() signal. + A child state can be final (a QFinalState object); when a final child state + is entered, the parent state emits the QState::finished() signal. The + following diagram shows a composite state \c s1 which does some processing + before entering a final state: \img statemachine-finished.png \omit \caption This is a caption \endomit - This is useful when you want to hide the internal details of a state; - i.e. the only thing the outside world should be able to do is enter the - state, and get a notification when the state has finished (i.e. when a final - child state has been entered). + When \c s1 's final state is entered, \c s1 will automatically emit + finished(). We use a signal transition to cause this event to trigger a + state change: + + \code + s1->addTransition(s1, SIGNAL(finished()), s2); + \endcode + + Using final states in composite states is useful when you want to hide the + internal details of a composite state; i.e. the only thing the outside world + should be able to do is enter the state, and get a notification when the + state has completed its work. This is a very powerful abstraction and + encapsulation mechanism when building complex (deeply nested) state + machines. (In the above example, you could of course create a transition + directly from \c s1 's \c done state rather than relying on \c s1 's + finished() signal, but with the consequence that implementation details of + \c s1 are exposed and depended on). + + For parallel state groups, the QState::finished() signal is emitted when \e + all the child states have entered final states. + + \section1 Events, Transitions and Guards + + A QStateMachine runs its own event loop. For signal transitions + (QSignalTransition objects), QStateMachine automatically posts a + QSignalEvent to itself when it intercepts the corresponding signal; + similarly, for QObject event transitions (QEventTransition objects) a + QWrappedEvent is posted. + + You can post your own events to the state machine using + QStateMachine::postEvent(). + + When posting a custom event to the state machine, you typically also have + one or more custom transitions that can be triggered from events of that + type. To create such a transition, you subclass QAbstractTransition and + reimplement QAbstractTransition::eventTest(), where you check if an event + matches your event type (and optionally other criteria, e.g. attributes of + the event object). + + Here we define our own custom event type, \c StringEvent, for posting + strings to the state machine: + + \code + struct StringEvent : public QEvent + { + StringEvent(const QString &val) + : QEvent(QEvent::Type(QEvent::User+1)), + value(val) {} + + QString value; + }; + \endcode + + Next, we define a transition that only triggers when the event's string + matches a particular string (a \e guarded transition): + + \code + class StringTransition : public QAbstractTransition + { + public: + StringTransition(const QString &value) + : m_value(value) {} + + protected: + virtual bool eventTest(QEvent *e) const + { + if (e->type() != QEvent::Type(QEvent::User+1)) // StringEvent + return false; + StringEvent *se = static_cast<StringEvent*>(e); + return (m_value == se->value); + } + + virtual void onTransition(QEvent *) {} + + private: + QString m_value; + }; + \endcode + + In the eventTest() reimplementation, we first check if the event type is the + desired one; if so, we cast the event to a StringEvent and perform the + string comparison. + + The following is a statechart that uses the custom event and transition: + + \img statemachine-customevents.png + \omit + \caption This is a caption + \endomit + + Here's what the implementation of the statechart looks like: + + \code + QStateMachine machine; + QState *s1 = new QState(); + QState *s2 = new QState(); + QFinalState *done = new QFinalState(); + + StringTransition *t1 = new StringTransition("Hello"); + t1->setTargetState(s2); + s1->addTransition(t1); + StringTransition *t2 = new StringTransition("world"); + t2->setTargetState(done); + s2->addTransition(t2); + + machine.addState(s1); + machine.addState(s2); + machine.addState(done); + machine.setInitialState(s1); + \endcode + + Once the machine is started, we can post events to it. + + \code + machine.postEvent(new StringEvent("Hello")); + machine.postEvent(new StringEvent("world")); + \endcode + + An event that is not handled by any relevant transition will be silently + consumed by the state machine. It can be useful to group states and provide + a default handling of such events; for example, as illustrated in the + following statechart: + + \img statemachine-customevents2.png + \omit + \caption This is a caption + \endomit - */ + For deeply nested statecharts, you can add such "fallback" transitions at + the level of granularity that's most appropriate. + + \section1 Using Restore Policy To Automatically Restore Properties + + In some state machines it can be useful to focus the attention on assigning properties in states, + not on restoring them when the state is no longer active. If you know that a property should + always be restored to its initial value when the machine enters a state that does not explicitly + give the property a value, you can set the global restore policy to + QStateMachine::RestoreProperties. + + \code + QStateMachine machine; + machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); + \endcode + + When this restore policy is set, the machine will automatically restore all properties. If it + enters a state where a given property is not set, it will first search the hierarchy of ancestors + to see if the property is defined there. If it is, the property will be restored to the value + defined by the closest ancestor. If not, it will be restored to its initial value (i.e. the + value of the property before any property assignments in states were executed.) + + Take the following code: + \code + QStateMachine machine; + machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); + + QState *s1 = new QState(); + s1->assignProperty(object, "fooBar", 1.0); + machine.addState(s1); + machine.setInitialState(s1); + + QState *s2 = new QState(); + machine.addState(s2); + \endcode + + Lets say the property \c fooBar is 0.0 when the machine starts. When the machine is in state + \c s1, the property will be 1.0, since the state explicitly assigns this value to it. When the + machine is in state \c s2, no value is explicitly defined for the property, so it will implicitly + be restored to 0.0. + + If we are using nested states, the parent defines a value for the property which is inherited by + all descendants that do not explicitly assign a value to the property. + \code + QStateMachine machine; + machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); + + QState *s1 = new QState(); + s1->assignProperty(object, "fooBar", 1.0); + machine.addState(s1); + machine.setInitialState(s1); + + QState *s2 = new QState(s1); + s2->assignProperty(object, "fooBar", 2.0); + s1->setInitialState(s2); + + QState *s3 = new QState(s1); + \endcode + + Here \c s1 has two children: \c s2 and \c s3. When \c s2 is entered, the property \c fooBar + will have the value 2.0, since this is explicitly defined for the state. When the machine is in + state \c s3, no value is defined for the state, but \c s1 defines the property to be 1.0, so this + is the value that will be assigned to \c fooBar. + + \section1 Animating Property Assignments + + The State Machine API connects with the Animation API in Qt to allow automatically animating + properties as they are assigned in states. + + Say we have the following code: + \code + QState *s1 = new QState(); + QState *s2 = new QState(); + + s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); + + s1->addTransition(button, SIGNAL(clicked()), s2); + \endcode + + Here we define two states of a user interface. In \c s1 the \c button is small, and in \c s2 + it is bigger. If we click the button to transition from \c s1 to \c s2, the geometry of the button + will be set immediately when a given state has been entered. If we want the transition to be + smooth, however, all we need to do is make a QPropertyAnimation and add this to the transition + object. + + \code + QState *s1 = new QState(); + QState *s2 = new QState(); + + s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); + + QSignalTransition *transition = s1->addTransition(button, SIGNAL(clicked()), s2); + transition->addAnimation(new QPropertyAnimation(button, "geometry")); + \endcode + + Adding an animation for the property in question means that the property assignment will no + longer take immediate effect when the state has been entered. Instead, the animation will start + playing when the state has been entered and smoothly animate the property assignment. Since we + do not set the start value or end value of the animation, these will be set implicitly. The + start value of the animation will be the property's current value when the animation starts, and + the end value will be set based on the property assignments defined for the state. + + If the global restore policy of the state machine is set to QStateMachine::RestoreProperties, + it is possible to also add animations for the property restorations. + + \section1 Detecting That All Properties Have Been Set In A State + + When animations are used to assign properties, a state no longer defines the exact values that a + property will have when the machine is in the given state. While the animation is running, the + property can potentially have any value, depending on the animation. + + In some cases, it can be useful to be able to detect when the property has actually been assigned + the value defined by a state. For this, we can use the state's polished() signal. + \code + QState *s1 = new QState(); + s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + + QState *s2 = new QState(); + + s1->addTransition(s1, SIGNAL(polished()), s2); + \endcode + + The machine will be in state \c s1 until the \c geometry property has been set. Then it will + immediately transition into \c s2. If the transition into \c s1 has an animation for the \c + geometry property, then the machine will stay in \c s1 until the animation has finished. If there + is no animation, it will simply set the property and immediately enter state \c s2. + + Either way, when the machine is in state \c s2, the property \c geometry has been assigned the + defined value. + + If the global restore policy is set to QStateMachine::RestoreProperties, the state will not emit + the polished() signal until these have been executed as well. + + \section1 What happens if a state is exited before the animation has finished + + If a state has property assignments, and the transition into the state has animations for the + properties, the state can potentially be exited before the properties have been assigned to the + values defines by the state. This is true in particular when there are transitions out from the + state that do not depend on the state being polished, as described in the previous section. + + The State Machine API guarantees that a property assigned by the state machine either: + \list + \o Has a value explicitly assigned to the property. + \o Is currently being animated into a value explicitly assigned to the property. + \endlist + + When a state is exited prior to the animation finishing, the behavior of the state machine depends + on the target state of the transition. If the target state explicitly assigns a value to the + property, no additional action will be taken. The property will be assigned the value defined by + the target state. + + If the target state does not assign any value to the property, there are two + options: By default, the property will be assigned the value defined by the state it is leaving + (the value it would have been assigned if the animation had been permitted to finish playing.) If + a global restore policy is set, however, this will take precedence, and the property will be + restored as usual. + + \section1 Default Animations + + As described earlier, you can add animations to transitions to make sure property assignments + in the target state are animated. If you want a specific animation to be used for a given property + regardless of which transition is taken, you can add it as a default animation to the state + machine. This is in particular useful when the properties assigned (or restored) by specific + states is not known when the machine is constructed. + + \code + QState *s1 = new QState(); + QState *s2 = new QState(); + + s2->assignProperty(object, "fooBar", 2.0); + s1->addTransition(s2); + + QStateMachine machine; + machine.setInitialState(s1); + machine.addDefaultAnimation(new QPropertyAnimation(object, "fooBar")); + \endcode + + When the machine is in state \c s2, the machine will play the default animation for the + property \c fooBar since this property is assigned by \c s2. + + Note that animations explicitly set on transitions will take precedence over any default + animation for the given property. +*/ diff --git a/examples/animation/animation.pro b/examples/animation/animation.pro index d5121a1..0a57d3d 100644 --- a/examples/animation/animation.pro +++ b/examples/animation/animation.pro @@ -7,9 +7,6 @@ SUBDIRS += \ example \ moveblocks \ padnavigator-ng \ - photobrowser \ - piemenu \ - selectbutton \ states \ stickman \ sub-attaq diff --git a/examples/animation/moveblocks/main.cpp b/examples/animation/moveblocks/main.cpp index 06ed3dd..0ce07fc 100644 --- a/examples/animation/moveblocks/main.cpp +++ b/examples/animation/moveblocks/main.cpp @@ -95,7 +95,7 @@ public: } protected: - virtual bool eventTest(QEvent *event) const + virtual bool eventTest(QEvent *event) { return (event->type() == QEvent::Type(StateSwitchEvent::StateSwitchType)) && (static_cast<StateSwitchEvent *>(event)->rand() == m_rand); diff --git a/examples/animation/stickman/lifecycle.cpp b/examples/animation/stickman/lifecycle.cpp index b22af55..423d7ad 100644 --- a/examples/animation/stickman/lifecycle.cpp +++ b/examples/animation/stickman/lifecycle.cpp @@ -69,7 +69,7 @@ public: { } - virtual bool eventTest(QEvent *e) const + virtual bool eventTest(QEvent *e) { if (QSignalTransition::eventTest(e)) { QVariant key = static_cast<QSignalEvent*>(e)->arguments().at(0); @@ -92,7 +92,7 @@ public: startTimer(1000); } - virtual bool eventTest(QEvent *e) const + virtual bool eventTest(QEvent *e) { return QEventTransition::eventTest(e) && ((qrand() % 50) == 0); } diff --git a/examples/animation/sub-attaq/boat_p.h b/examples/animation/sub-attaq/boat_p.h index 17fbe5c..6f03e48 100644 --- a/examples/animation/sub-attaq/boat_p.h +++ b/examples/animation/sub-attaq/boat_p.h @@ -67,7 +67,7 @@ public: this->key = key; } protected: - virtual bool eventTest(QEvent *event) const + virtual bool eventTest(QEvent *event) { Q_UNUSED(event); if (!QKeyEventTransition::eventTest(event)) @@ -93,7 +93,7 @@ public: this->key = key; } protected: - virtual bool eventTest(QEvent *event) const + virtual bool eventTest(QEvent *event) { Q_UNUSED(event); if (!QKeyEventTransition::eventTest(event)) @@ -131,7 +131,7 @@ public: this->key = key; } protected: - virtual bool eventTest(QEvent *event) const + virtual bool eventTest(QEvent *event) { Q_UNUSED(event); if (!QKeyEventTransition::eventTest(event)) diff --git a/examples/animation/sub-attaq/states.cpp b/examples/animation/sub-attaq/states.cpp index c6af924..7650b0f 100644 --- a/examples/animation/sub-attaq/states.cpp +++ b/examples/animation/sub-attaq/states.cpp @@ -281,7 +281,7 @@ UpdateScoreTransition::UpdateScoreTransition(GraphicsScene *scene, PlayState *ga { } -bool UpdateScoreTransition::eventTest(QEvent *event) const +bool UpdateScoreTransition::eventTest(QEvent *event) { if (!QSignalTransition::eventTest(event)) return false; @@ -300,7 +300,7 @@ WinTransition::WinTransition(GraphicsScene *scene, PlayState *game, QAbstractSta { } -bool WinTransition::eventTest(QEvent *event) const +bool WinTransition::eventTest(QEvent *event) { if (!QSignalTransition::eventTest(event)) return false; @@ -319,7 +319,7 @@ CustomSpaceTransition::CustomSpaceTransition(QWidget *widget, PlayState *game, Q { } -bool CustomSpaceTransition::eventTest(QEvent *event) const +bool CustomSpaceTransition::eventTest(QEvent *event) { Q_UNUSED(event); if (!QKeyEventTransition::eventTest(event)) diff --git a/examples/animation/sub-attaq/states.h b/examples/animation/sub-attaq/states.h index 27beb71..a1cb5ff 100644 --- a/examples/animation/sub-attaq/states.h +++ b/examples/animation/sub-attaq/states.h @@ -152,7 +152,7 @@ class UpdateScoreTransition : public QSignalTransition public: UpdateScoreTransition(GraphicsScene *scene, PlayState *game, QAbstractState *target); protected: - virtual bool eventTest(QEvent *event) const; + virtual bool eventTest(QEvent *event); private: PlayState * game; GraphicsScene *scene; @@ -164,7 +164,7 @@ class WinTransition : public QSignalTransition public: WinTransition(GraphicsScene *scene, PlayState *game, QAbstractState *target); protected: - virtual bool eventTest(QEvent *event) const; + virtual bool eventTest(QEvent *event); private: PlayState * game; GraphicsScene *scene; @@ -176,7 +176,7 @@ private: public: CustomSpaceTransition(QWidget *widget, PlayState *game, QEvent::Type type, int key); protected: - virtual bool eventTest(QEvent *event) const; + virtual bool eventTest(QEvent *event); private: PlayState *game; int key; diff --git a/examples/declarative/dial/DialLibrary/Dial.qml b/examples/declarative/dial/DialLibrary/Dial.qml index 2e214a8..6cd42df 100644 --- a/examples/declarative/dial/DialLibrary/Dial.qml +++ b/examples/declarative/dial/DialLibrary/Dial.qml @@ -3,28 +3,32 @@ Item { width: 210; height: 210 - Image { id: Background; source: "background.svg" } - Item { - x: 104; y: 102 - rotation: Needle.rotation - Image { - source: "needle_shadow.svg" - x: -104; y: -102 + Image { id: Background; source: "background.png" } + + Image { + x: 93 + y: 35 + source: "needle_shadow.png" + transform: Rotation { + originX: 11; originY: 67 + angle: NeedleRotation.angle } } - Item { + Image { id: Needle - x: 102; y: 98 - rotation: -130 - rotation: Follow { - spring: 1.4 - damping: .15 - source: Math.min(Math.max(-130, value*2.2 - 130), 133) - } - Image { - source: "needle.svg" - x: -102; y: -98 + x: 95 + y: 33 + source: "needle.png" + transform: Rotation { + id: NeedleRotation + originX: 7; originY: 65 + angle: -130 + angle: Follow { + spring: 1.4 + damping: .15 + source: Math.min(Math.max(-130, value*2.2 - 130), 133) + } } } - Image { source: "overlay.svg" } + Image { x: 21; y: 18; source: "overlay.png" } } diff --git a/examples/declarative/dial/DialLibrary/background.png b/examples/declarative/dial/DialLibrary/background.png Binary files differnew file mode 100644 index 0000000..75d555d --- /dev/null +++ b/examples/declarative/dial/DialLibrary/background.png diff --git a/examples/declarative/dial/DialLibrary/background.svg b/examples/declarative/dial/DialLibrary/background.svg deleted file mode 100644 index 415320d..0000000 --- a/examples/declarative/dial/DialLibrary/background.svg +++ /dev/null @@ -1,385 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In --> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ - <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> -]> -<svg version="1.1" - xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" - x="0px" y="0px" width="210px" height="210px" viewBox="0 0 210 210" enable-background="new 0 0 210 210" xml:space="preserve"> -<defs> -</defs> -<radialGradient id="SVGID_1_" cx="0.8066" cy="-16.5908" r="92.0159" gradientTransform="matrix(0.9944 0 0 -0.9944 101.1987 90.0014)" gradientUnits="userSpaceOnUse"> - <stop offset="0.1264" style="stop-color:#E0E0E0"/> - <stop offset="0.3421" style="stop-color:#C7C7C7"/> - <stop offset="0.5495" style="stop-color:#B3B3B3"/> - <stop offset="0.721" style="stop-color:#B1B1B1"/> - <stop offset="0.7828" style="stop-color:#AAAAAA"/> - <stop offset="0.8269" style="stop-color:#9E9E9E"/> - <stop offset="0.8625" style="stop-color:#8D8D8D"/> - <stop offset="0.893" style="stop-color:#777777"/> - <stop offset="0.92" style="stop-color:#5C5C5C"/> - <stop offset="0.9445" style="stop-color:#3C3C3C"/> - <stop offset="0.9662" style="stop-color:#171717"/> - <stop offset="0.978" style="stop-color:#000000"/> -</radialGradient> -<circle fill="url(#SVGID_1_)" cx="102" cy="98" r="85"/> -<path opacity="0.5" fill="#FFFFFF" fill-opacity="0.8" enable-background="new " d="M57,169c0,0,20.146,5.732,45.001,5.732 - C126.855,174.732,147,169,147,169s-20.145,12.846-44.999,12.846C77.146,181.846,57,169,57,169z"/> -<image overflow="visible" opacity="0.75" enable-background="new " width="206" height="206" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAM8AAADPCAYAAABSgYVfAAAACXBIWXMAAAsSAAALEgHS3X78AAAA -GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAIVhJREFUeNrsnQtz27oOhKGH7SRN -m3P//588p83DdmzptjPiFNksQMqWHdkGZzRO0zbxg58WWIKgSIwYMWLEiHHOUcVbcDXvex9va8Bz -re9rdaL3vz/iezECnlm9h1Xm++dQnt74uz6ACnjm8p5VBY+VA1V1Imj0Y+/8XQ66GM5o4y04CBgL -jpr8HbtOCY91pb/vMnAFSAHPSYDxrjrzaEFUTQCOBUyXeczBFiAFPJMCUwMYpRcCdUwIx0ItBkjp -1cPXAVLAMzkw6WrIo75q+JqBVE0IT+8Asx8u/TV+Tz92AVLAUwrNGGDS1TqPLYGpcVRoipyHqc2e -XLvh2juP+wxIXUA0XcJ6DSpTZ4BpAZCF8diSf9uCSqH6HPo5YL6D4HQEFn29G487A6R9Jme6OYja -G4OGOWO1EYIhDAtyLeHPDCSmPlbecyhAqDxMbRCUdG3hz+8EKK1MHkg3pUbtjULjhWMWLEvjQoha -Ax78vTKh8oiT6zDF0dBsjQvB8lSpu8WQrr1ycHLQjIFlNVxL9bg01KdxwGFmwRR5T+/kPVo9UHXS -tRmuLXncFoCE8F49QO2VQiNG4o8qkwOFXfrfpP/bAjgYquXWd0rv1lbJj7Xe0xmmQQIgAbEBgLxr -C/AhSDcDUXvF0FSQyzCVYaDcGY+W4rDcBteD2MT3ymrGmB7ez8b1G5YLWQr051oPF36NyoSKxHKj -qysDqq4IHGYzeyqjYbkfHvFCxVk40ORCst5RiDEAVWLb7FLw+3sjJ7IgWsP1BkBtILx7d0I6b80o -4JlJiGZBo4FJ0OgrfS/9G602LDRjyT86YGPLYyyAStalrLIg7zl2JKR7Jyr0BgC9EZg2hhpZEF20 -ClUXDg4L0Sxo7gCah+FCgLTaoINWk3AMJ2IvfNXeWngcM5nYzcKrgEALvnKAR5AYRAgPu5gaMSW6 -eBWqLvg5W9C0kJcwYB4IPHeQ3+iwTE84Ic4WS8rZ1wygzgjpSnO6kkqIxjEzcMFWvy4W0jGAXtWl -v+9BdPEq1F6J2mgjYElCMw3Lt+FCcFaQzzRkUllJN1uI3El+bYTlAjm3bUwJEVvoZd/HvE3/jA5C -unuiQgmcF/W4HP5uMfy7ZgCodlToogBqLxScGhy0FF4xaDQsDBwdorWgMgyYd2L1vkOy/G5AxODJ -FV968FhWvFUd0crnRV3Paq/U9/DGpCHSYe+L+gwSTBrajXp/Kng/LsqNay8EGjEMAQ1N+lBRZR4B -mgeiNlppBICx3ChvZT5X3tIVOFB9oWFgLf6yOjyvUsJzExFMlkeWOJWvw8/YqOfLbioXAVF7QWpT -EUMgfej6zqeBeVRfa3BKoMGE2VpEZPAcWhdWAo84LltTAJC3ILwkjwtQ5VJThi0sL4jCpffMs/UD -niPDNPzQ9IelQ7JHuNL3MURrVHiGcb1OjjdiLxRuiOKw8pVO7DqwMQuIpVXhjeRLkBg81gKxlQ+2 -mSUBD552eC9rR4VmrUDtTKHxwjRUGx2efR8uVJx7Ak2llAZVZk3WMdYAz9YBxyrn70au7ZQ6jtYC -sVeStCAKdEcsffweQlSr97U1fq5VC8jWzC4mF2pnrDbopuncBkM0Dc13Bc49fOAamp1K+reZNYwc -OCWFkmOabxwCkMi4vUltAUD3wheS79T/0SbLgrifDNSF8CqN9fDcLyKMa2cMDiaoS/WBplDsO1yP -AA6qTa/Cs61hueIjq+kaC01OaY6Bp1SJSiFaOVb/PRgud8Sp1Iux+LPZHqgFWU/Ta0/pfZW5KVA7 -Q3BqeOMX4KSh2vwAcB7Uh9pCXpNymg1Zo2CLfQycXE5TstOyP9F7mHPlqoKciAH0qgB6I0Ch3V+p -mxYzeRaO+uCGwXf1+c0qhGtnDs6SrNl8J+B8V/lNiq/TB9GpvGYr9sIeA8daId/J+IYZ5wg7qoyx -kLO3sUJDQ/QKywDpPXpQNyx900rv/9JYk1tkch/s8bBTEM0CoGaGjppWmwTNo4Ll6ff1z3A9Ddd3 -CNVS6JDUJhU2/gHl1+/r5+/rP3L9+f7zcL0MFwNp54D0lXv8WdW2/rPXlsrarsB2oVpbEHROx5xS -qzFKI35jlF5mWErWzAycloRpCRwNTbqS8qQ730K9pr1SmgTNLwOa9HcJHFSfXJVwJ/NthmEZFB5Q -pSDhTQQBEvFLiNj29GqO+c2c4MmBo520H4XgpPxmr/KatwEGT20SOC/ysbCRQdOJvcnrUmqycv2s -c9u4cx13GEDWlpGmIFybLUjNDMHRisPAeRq+/zhAtgS1eVch2jNA8y8J0XTOsybGgKUycmHQ5ICy -2vXmQLKKX3vIT3IAsQrvWVvVzYWA8z/Ibx7VWkOjEsqtMgG02iA0vwAcndMwaG6lP1muE6l2FhEW -1o0U37dcB1ZsyyVODndT8DC3Z1EIzj9gDKT8pgZT4FWpzU/HEGDQbIVXB9xiUz+voYjXlZQB1RtG -QpUBqCoEqL8VePR+kdZw1XKOGoKDpsB/JEz7mTEDMGa/6U6YhaFdrid2NyIHYpcQiLwF57N/Vs0Z -wfFCtW+ZHAfBqcBNe86Eac9gCLC8JqAZH85hQ5FO7E1/uRCutL/d1JUaB4/2zODotZylfKwa0Os4 -T8oYSI7aSj3fBI520zQ82nrWwGyEr08ENOXgVAUh3E7KdtOmn71UN9UxhoblGnbn+BzbM4HDVEfX -qeEC6BOxorWjhjb0fwocFqJ5DlpAcxxEnjPn5UMIwkrNj6owB2PrVWdTo+YM8OCWaW8BFM0BvYZT -KXBeHRs6uWnaFNgSeK6qh9jM8iGmTNZ77YVvrOLAaud1djOhPTE4WCGN4dojhGo/5O8azoO6G4nh -qDFonuVjNbQO09haTYBzvCNnTe7cKXW9My+b4fP3fmafya2qU37G7YnBwY1srDr6hwIIwWkJOJYx -kNTmRTlpqTpgX3AHjHFcKNcZYZQFUq7xic6BmNrkjInu1PlPc0JwKrEXQb8rtfFcNYFQDcH5V/6u -6TwDOFsAJ8K0rw3jvJ4NuV50nmV9TBPJ2SoPGgRL+bz784e6Ejjoqlmhmg7X0IZGCzrCtK8L44S4 -YSL55o4CJsJK7F7be0OJROxzg2anPMxZY5Y0qk4K1/QCKNrRFjjaVdP7bvYRps1OgaTQPKgkfwiy -l/ecJdJoTgBOJZ+b5N0b4GhLOhV56sqBMeAwxQlw5guTFLpvzIETACjXD/wkc2BqeKydoNpZY2U3 -D/J3oUyX3Oh1HA1NgHMdEAlxxgRA8bYrWEWrZynqbSYEp8qA81142Q0ugu4UONY6zkuAc1UA5cwD -7wwkq+G+ZyLMBh7PXcMKAtyTk5w1tKStLQWhONetQF7Y5p3q4J1YcbLwbSp4WLh2T8I1XbeWNrOh -QfCaAedFmQMBznU5dd55sta2Be/8VQ+e/qvhyblrrP/AkzIIkhWZdoAmS9orucGtBAHOdYBTGrox -8+BQgL4cnlzBJ3PXMM/RW6d/OuBEqHY7w2sa0gjvdbAfCVD/VfAw1cn1INC9B7DY02oLpcFZh+Lc -ZOjmta3SEFnbI7zdwWeHp9QkwHAt1a2hLc3Wc9BZS0We7wHO1Y4qYxzoUxnYoco6dMNGJZOHb8fC -oztN4q7QJ8NdS3lOarbObGl01tbi16rFuC6A2A2anTtknRd7FoCaI8DRWw1SJUEqwcEdoUl1cBu1 -DtcsZ20NzlonJ/LtY8wGnpxhgOep6vANbWvvTNgvg4dtNWC9CHArdVKdFK6xPOcZDIKtAicU57oV -Rwoct9YAqBJeOGqdZnHUXGqOuCvg+ZTaJPgh+cXQdUZ1MFzLbaCKcR3gVAXGAZ7sjdUHCaAEC7ZK -3k0Rvh0KD+4M1QuiT4bqYLuoV/ncKopVSb+H6tx8+Gad6GABlHIfr9f2/ivgwd2haV0HF0Rxcxuu -6TCToHQ9J8bt5T6V2GcKIUAC6oMnPLAjYkbPreaAF4MntqHDpvsRPILq4K7QUnctFCfCOA8eBKgi -rlvp0Sgng0f77bhXhzXy0DtD+4zq4DZqDNdi3LZxYJkGCA/mPgyekt59k8HDDqBaGg4bU51kTVtt -cXWrKKxbC9UJmLBVs3W6N3PeEB7vBIxRc6w+UHkaoj54YnJSnHRCmz7WEI8w1DlOLITGYK1809zY -qDmj55Eu3Uqb63RqoednOnpzYZgNJ4GHOW0reHL6hGQ8N2dNXjhrhbuPcC2GkbdsFEB4A16rm2+a -34vMHMVSn2pKeHIH7uKx4+ncnFZJ585RnXWoTowD1GedUZ8O8vM7mKeoPtihtJoCHhG73/SSPKGV -cte06jC5XYtftxYjBgNoq+aOpT6dyusXBCCmPsXgTAGPPmp8pWhOJKeEjR3hrrcYxDaDGKXqs1Nz -xptTSX0qkp9reJby2eaeBJ4xIZs2CTDX2ao7w5vww6WO8txj3ETugwBh+IZpQCcfW6FZN/uF8C3e -1VQ5DwvZVuRJtGATviuJfRP/DNBQnRil6qPNgzW5KesFdlybROU5KHSbAp47yHUaYhRs4MWtw12L -MaH7tiYAMdu6VH2OhscK2TzlacEo2MGLW4t9XHuoToxD1GdL5lhSpDS30lzPRUyjQrfSnMcL2ZaQ -dNUQsuGL24jf/SZGjFLnTUc2CNCWhG7NCICOznmsc3bwl6fyCF3RunfuCngCdRz/EWOM+uB2A+8G -vVehW+Pc/CeDx9rFp5UHLwzZLNXxwrUYMQ5RHzbXcC+YgHGwPDZ0K8l5EBxN7pIkWyxk03cCrTon -7SUc46rBwf06W2O+eaHbEuAZpT7H5DxLMAq0y8bi0a2hOuGyxTjUdWPqszXyah26tYYAnCRss0I2 -TWv6WZ1xJ2CqE+DEmAKgXcGcw9BtYcxnBlBx2GY1226MX9pCyNaRO0FOdSJki3GIceCpz1Z4Dwzc -UmOFbKg+1RjlkUzOg1tfRZkF7IW8G6oT0MQ4Nv/BXgXWDTsN3Inq5TxyqGHAtr4u4NK/iBXvpRfA -du/FIbsxDgVHhPdoeycA6WgHd0SznajWMY7FylNLWdOFRj422mbKw7qWRLgWY8rwzYIH553I5x7r -C7GbKNaH5jwlvbK0y6Ztaq/dT0AT4xThm9UpB7swYRcoq4VVPSbnqQoBQnAqyHd2wruUTNYnOEYM -sY9U9OagNsNKel+LBdAY5fF+kRjOxy7jsEW+E2OKvKcfOf8kIwgHKY8AmaxHcEsSK1Ehm9XiNOzp -GKfOe7rM/NurOVcyrw8qz/F6BFtH22G5RIRrMeYSvmE5mAg/dQ7DtlomqG3TJxFbbXqsM1F26vsB -T4xzmAad+AdbiQGQdeK2lMBTid1guzbiQXTa9sIPFYpcJ8a5ch9rDqLj5s3t2mDhIOVhF4Zs7CTi -Tuxu9AFQjKnBKZmLPTHFMIRz13hKDYPKAaeCF4JPmoVrAU6MUwDE0odO/H7UbH7r70lpzsMsuYr8 -QEZkTxTGO/skwIlxipyHuW/WfBSiPpXYLtsnPkr28wgBR0i+0ztPNOzpGHMACOcgi7AqI98pMgxQ -qtgPqZwn3hU86RgxzgVQn1GdHDiMj1HKY30v9ySjsUeMOUHE8m3LYfYYKILHC+PGPGF0RWLEmAM4 -HjyVEYmNgqeke2J/wJOOEeMU0MhIcEpTk6OVJweORKgWYwYQWUDlUpPKyf0nh6c3/hzWdIxLGJZB -djblYeBI5DgxZg5NNTKnPyk8MWJcu0IFPDFiHJmeBDwxbhqGPpOzf3nYVny+Y4wYMwGpGKB6AjhY -shXAxLjk8KwIoKmUx7P8JGCKMdP8pWRRvz8lPBYsRScKx4hxglRBMjdzL3QrXl6pC0ntC57wwQV2 -MWJMnF+XzMOcwmRrMscqD/6i3BMuKrCLEeMEEJXc0BlAxdUxdSEsue9521kjfIsxJ4BYFJQrai6C -p3ckq7Ss2+t3EADF+ApoWNMacVSnd1gYrTzYmUT/0BJwAqAYXwFOnYmGcCPnqG00tRP/Cfmh2JNA -P/Fci6owD2J8JTiW+rCWVWyOf+KjdhSntC8BA4h1YBy92ShGjEJwUBCsDrcMnJK+G6Nr28a08LFO -VGgyKhQAxZgCHNbEw5uLrFlniUBkDQOv+4jVtB3PO9Gd51nX+QAnxikBsuZgQ/Kd3Nw2FWiM8rAO -jL0hl/pJt0b4FiPG1DmPnmctmYs1yfOtDrejlccL2VLj7L0BUKWetHXeScAT49TwWOfutEbIhocT -7EtDtxLDwDrvRAMkMv6cx4AoxpQu25jzc6VwXo82DHqSTO2dX9QZYdsCHpswDWKcONcpnX8in8+S -YlFVJ86aj1dhwABiv0iTidQvInyL8YXhGpuDOrLyBKGTTPHoGOXJnfOoHbcFPHmkP8CJcSqzgM27 -BXHaxpyfW6Q86EL0huroI7rZIanpCS+HywMoIIoxRb6D4Oi5hye39/Lx1Ox3Q31YpUEWHivn0b8s -XfoX6RexdODBM00DoBiH5jsYriE8S4BHCwLO5Z34h2EVK48Q5Um/ZEtkTiDvWRCAtGUY4VuMKfOd -NjPvGvV/MVzbEoDckK0k52F5jwZoC79Mr/Xgi1hmnLeAKMYh4Vrt3LD1nEtzTc/lrQNO9vzcMes8 -O4AGf6m2rHXYthouLaGoPjFiHAIRqo4357RFzURgayjPQYWhUgDQBtSnV45ba7wQS31ixDgEHKY6 -es61ymnrQXU2BeDI2JzHA+fd+MU6dGvUi1ll1KeK/CfGAXlOlVGdlbpZNxCyMQF4HwtQadjGlGcD -ALHQLQF0N1wrQ30CnBiHAISqs1JzDfMdHbJtyRz2cp6ThW0bUB8duuk7AQLUgqSGcRCj1CjQqUFL -wNHKgyGbdfOfNGzLwbMx4GGh253xwkJ9YhyrOuwGfVcQsm0yyjNJzlMSuuknkEK39OLYC8uFbwFR -DEt1cuGavkHr9Z1uBDjZkK1EeZj64BNYq6/Tk0ihW6uU53649Atk8MSIkXPZNDwaHD3HUmSTQrZ0 -02fzFiOnopa7h8CDyrNWT0QbBzp0W5EXt3IACvWJUaI6K2duYci2c+bs6JBtTM6DoVtOfZJxUBN4 -HuBFYu4TChTDUhyW61jzaiF/a9n2I1SnKGQrVR4Nka4JQorfQH0SPBi6PcALXTrmQUAU0FgmQW5O -tQoePV/fjGhJL/RPejKcFbppeNKlSRalPlpa04tlzkg4bzE8hw0dXA1Ogmeh5raOlHCubg4N2Q7J -eXr5WBvEaF5D7oPq80DuFElmF6E+MRzVWRhpgL4Za9XRuc7aiJJ0bWY/tWGgIWJ7ezbqCb0B0dq2 -ttTnPmMexIhch5kE947qoD3tzVHW9KNoHHI+j+W6vakLc58qoz73oT4xRqjOfUZ1Ksh11sb8tPbv -FI3myBflbX9leylE/L4IxW1/YtwEOKg4f4D59vv6/vt6Gq5/fl8/fl+Pw98vhv+7HyB5+X39+n39 -HK5fw/UygKQX90flPM3IF8Wsw5JdfLo4z+qLkIMnILqtUI0VF38bIHmC6/ugPqthTvcDFH/geFbg -pOsPOK8kdDup8pSqj9U1JweQ1y84xm05awjOwwDOdwDnxwDV3fB/ZJhL6wGSBMx/Snle5LMz3I2d -a4eEbVZM2hIFWhh5jA7frKZzB72gGFcBTu2Eaz8AnscBrKVy2JLq/AJ4finVSfDom/Wo0Uz4Yq2G -cxi6seMdvH7BEbrdXp6j13Puler8UHnOPwNMTHXeHNV5hVyHNe88adiWC9+wVzCzoHXVAjvmwetW -HxBdb57TFIRr2iRA1dkMgPwi4DwT1dkfojrH5jw59cGuodbeHdatfu+YBwHO9YZruH2fuWvaJPgm -fze89YOSJJPg1wBOup4d1ZFzwVNiHrDjHdoCgKyDhsI8uK08Z6nAeQTF0aqTwrUKTAINTgrdnuXj -Gs/ReXVz5IvO5T+NA1Aj/GDVzgjdOgjZAqLry3N0wec3I8/5MajOPTEJXgdIGDgpXNsog6o75gU0 -J7qD5FQIzyoVyZ+Bin2DA57rAAc74HgGgV7TuYNwbQ3hml4UTQuia/m8rnNwNNNM/EZgWyBLgfC4 -ETHCt9EnFMe4OHDQIEjh2g8I1/Sazr18XtN5BXftP6I62OH2qHk0Rc6Ty4G0C9eQr9kWhA5A6iP3 -uVpwWgLOd1CdJ3DXFiRcS+7av/J5QTTlOlhBfdSYMmxjKsQUiB2y2hADAbdC9BG6XS04yVl7BHD+ -B+Gadtc6cNd+grv2S5kEk4ZrU4dtJepTy+djvb3T4qwj7XtQpxiXC06qIHjI5DkpXEsdcXrHXbPC -NSzDOXo0J36jcgqklccDyIIpwrfLB+fecNaeIFxLe3VE/lZMvxrgsKrp3dRhf3OCN8r6Gh242gAJ -9/BUJETrCFQxLhOcpDi4lvMPAQerCJ4dcFLV9HbqcO0U8FQjFKg2AKpBgWr4eb0BTQB02eBoxfmf -Upy0nrNS4KQ854U4a2cJ104ZtpWYCZYK1eTydpOyotGA6DLMASvH0QuhD8QgWBNwdJ7juWuT3mSb -MwCjRy22ld0YAFlhnBBY+sLnFeP8arNU5sA3xxzQ2wz05radfNwZmqD5Vz4WfrISnJPkx80Jwcnl -Q7XYVQm1EcYxFaqMN6YPcL4EHLa+hz3WWI7zBIqzUvPTAseypU8arp0zbCsN4UovL4yr4I0KYL4+ -TNPgPIpvR3vg4DYDBOf11O7aV8FTFbzhHkxeOCcGTAkkL+QLuKaHRne6SbVqVuUALoImcFoCzrOh -OKyK4Cw7kc9tGFj5UOWEcrk8yAvpcvDGmD5MW4DiPBjgsLIbDc4ewPmpchy9R+flnHnOOeGpjoSt -zuRHtfBzTRlQhwAWw1cbrIpmG9lSmIYLoP84odpe/hZ7ojnAFkKtos+TjuYLP4B+RDhQAo4FUlUY -4gVE40I0q2ffnfCqAaxVG5vjeOC8C++C018jPJ4rZt3d6hH5UClMng0eEPnQNIbaPBjgsFAtbWgr -NQewgoA5a2fruPQVbpu1LuO94NIqhdziqwZJxLa+A6L89pKWqI3VrMOqVWPrOMwc0KqDu0Inr5ae -IzxscbMi8PRODlRJWaUCg4kZDrk1JHGculvJaSpDbfSpbFptvou/hpNaRelatV2BOWBtbNvJF/X3 -a2bygfUGQFbPNm+BFfcNWdsfWM5UYjBUNwBN7YRoK/l4UoGGJhempW0FGpx0isGLYw54ivNlmySb -GX14ua0HJXfHUoCsau4xRsM1nN5QjYBmKZ+P97DAQTftm/ytU0tWNNaqeeaAF6p92e7iZmYfpgeQ -lxd5CW2uDVYuNypRoeoKoGkMF806wpD1jbYqBtLpBSm/SWs4b2KX3DBzYDbgzBEeC5wuo0al/eMW -BkAeSFauZDl1c1SknPWvX/cClEYfSKaVhjUi1GqT3LTUW43lN6w6WlcPMFdtFuDMFR5PgTrja2uS -lAJUqkhepUMOpuoLVcWDhjXoT9CgGWCFaLqL56MyBbQNrcM0NAZYrZpex9G91mZzflM7E0jSmytG -mMaawePBWOm6k4+HaqXktHXuqK9w6Q8tlX1s5fOJDrnWWD1xF/sTgyNGbuatmyFES8hx2PmfDyqX -0Yczr9QNSJ/QlsDRodovleskaHR+g4ozqw5K7YxURgO0g79nrXjTB4LXTj4eEoyNR9jdNU0MBhBC -9G5ApO+InZOzyYk+9Cpj7dckv/GUh70/+ihM70zZCtRmoxQHwdHQsPxmluDMBR4GUA/g9AY8CBDG -xSuiQg25u94PsCBEFkAWRCVqZBkf/QGgMOevRGUsaHLg3MvHU8zvyHtcyccT07UxkCBh0GCd2hbe -19k1fZkLPGzy7Em+g+eZvhvwpDf/gahQI/zksTsF0YN8PAB2DRBtD4SoI7ncsfBgTlUfCA2qsQ5r -9XWn8pklQJOcNKY2LwoYDNGsMG3Wp2TMCR4MayrDhfPUBye1lv0VfNit8HavadKsVYy+LgDoXT4f -TFwS0o0N57zwzArNcM1mUQDOHcCiocEjY3qlNvp09FelOBoYHaK9kTCNHa8pMrP+FHODxwrhmAKx -3EdPaAyz7kmYUYFdrSHaqLsne2Rh3HtBTmQZC2OVp7QzESrNwgjTVur9wccVgUbnNTtQmzflqD0T -aF7gprSVCzwRfY7weBCx5u87R4E2cOkEd6lyoAoUCQseN+rnbQ14MIzTk8EyFqaEh0HDDhpbEsXR -gODjAnIafarFXr3fWm1eARYNzSvJbS4iTLskeErCuJwCbUBB1mCtrsjESDBhOMdyqq0BTw6g7giA -ctazBw6DR18LUBh2kvneUBvtVCIwL5DbbBy1uZhe5HOHxwvjuoyFbcGjIbpzQhJtLOwVRBqKreH0 -sfDNmiR9gYFQum5jnYe0IOqjYcJzY/XhY9oIYO8vA+eFKM2b+izeidpc3AkYlwBPSS5kmQhbAOfP -B/hNfZhoubJkWOdF1u/yFm13honQZcyDnFmQ63/XGhDlKiqwV7gHzRpCtRd4fCMmSy63uZimlZcE -DwvjLBsbP2wdk7/BuoVlweqJxmxfZl7sIUTbZ8DpRtjWlvrUGYBKtmcwYDpyI9oCNG8Azyt836rQ -sHZ9XlS310uDh73BneHGoYnA7pbWGsaKJMzWfqB++Hs9GZjDVgLOWKvaA4g5bxXkLwyYvTICMPxl -4LyRNTEPmqs54fwa9qOI5PfYLwxb9l4+Lgbq9Y2VAZF1LCSe5sCKWI9d6yld42HdhKzn6JkuOmd8 -I/CsCTAbYpzsr0VtrgkeK4m2EmirDAVhujNUaGm4UdbxKKiY3o5ZGQGPBZAU/P5cjrg11GZNYMmV -LeUMkqu4c18LQFKw9sHUiNV0rQhAJRBheFTSoH7sHTjX+RRrAztI/kug2UCyz2r8mMrk1rREruQk -i2vcj2+Fcl75vRXaWVf6dzmrlylSKUxjPjdv/xMzM9BqZ4u/1oX2fOk2jauB5prhERK+jCmUZDVf -TKFQgTAnasU+tGvqzXF9gfPIimmtciZ83BoKkyuEFbnig8euvZ0SS7BrsRuGWCB5K/MLYihYayi1 -YTJUBwLDkn9r6wYrYfKqJd4LgMF8ppMbOmzslnqRScahKqkLw4upzsKAhzUYOfYzQGePrTuxBVy2 -jYNtKiypzxuzVhXwXKGxUFrO3xKgco1FWvEbL06hPCxc60Apdg5IuwJ1GbNT9ubuyLcMEYZ0pSv3 -7NHqE2f1z54i3+mcfIep0N55zFVC3FRoFvAcFtKVrOAzhbL6Z+dMg2okMDmzACFiQHXCqyFK9x31 -MXFiHALS2CMhq0y+cww8IryKofTqA5iA59wglZTHlPZ3O8YwsCZ8J2XlQQFMwHNWkNjXtfinOpyi -abwVwlkJvbUGE8AEPGcHKfeYO4t1anhE/FMmvGQ/gAl4vvQ9LDl5+xTvuwdBn/l+jIBn1u/rqQ4R -7o/4XoyAJ973gCNGjBgxYsS49vF/AQYAwYoCo3RnAfgAAAAASUVORK5CYII="> -</image> -<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="-15.9541" y1="83.9062" x2="13.6193" y2="-106.171" gradientTransform="matrix(1 0 0 -1 102.5 88)"> - <stop offset="0" style="stop-color:#B3B3B3"/> - <stop offset="0.151" style="stop-color:#AFAFAF"/> - <stop offset="0.301" style="stop-color:#A3A3A3"/> - <stop offset="0.4506" style="stop-color:#8F8F8F"/> - <stop offset="0.6001" style="stop-color:#737373"/> - <stop offset="0.7495" style="stop-color:#4F4F4F"/> - <stop offset="0.8968" style="stop-color:#232323"/> - <stop offset="1" style="stop-color:#000000"/> -</linearGradient> -<path fill="url(#SVGID_2_)" d="M101,187.999c-50.178,0-91-40.821-91-91c0-50.178,40.822-91,91-91c50.178,0,91,40.822,91,91 - C191.999,147.178,151.178,187.999,101,187.999L101,187.999z M101,13c-46.316,0-84,37.684-84,84c0,46.316,37.684,84,84,84 - c46.316,0,84-37.684,84-84C185,50.683,147.316,13,101,13L101,13z"/> -<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-79.4551" y1="-54.0073" x2="76.4557" y2="36.0078" gradientTransform="matrix(1 0 0 -1 102.5 88)"> - <stop offset="0" style="stop-color:#ECECEC"/> - <stop offset="0.0105" style="stop-color:#DDDDDD"/> - <stop offset="0.0399" style="stop-color:#B7B7B7"/> - <stop offset="0.0704" style="stop-color:#979797"/> - <stop offset="0.1021" style="stop-color:#7F7F7F"/> - <stop offset="0.1353" style="stop-color:#6E6E6E"/> - <stop offset="0.1712" style="stop-color:#636363"/> - <stop offset="0.2143" style="stop-color:#606060"/> - <stop offset="0.4615" style="stop-color:#FFFFFF"/> - <stop offset="0.5195" style="stop-color:#CFCFCF"/> - <stop offset="0.5899" style="stop-color:#9A9A9A"/> - <stop offset="0.6512" style="stop-color:#747474"/> - <stop offset="0.7002" style="stop-color:#5D5D5D"/> - <stop offset="0.7308" style="stop-color:#545454"/> - <stop offset="1" style="stop-color:#ECECEC"/> -</linearGradient> -<path fill="url(#SVGID_3_)" d="M101,7C51.294,7,11,47.294,11,97s40.294,90,90,90c49.705,0,90-40.294,90-90S150.705,7,101,7z - M101,182c-46.945,0-85-38.057-85-85c0-46.944,38.055-85,85-85c46.943,0,85,38.056,85,85C186,143.943,147.943,182,101,182z"/> -<circle fill="none" cx="102" cy="98.001" r="65"/> -<text transform="matrix(-0.6383 -0.7436 0.7588 -0.6513 54.624 142.6035)" font-family="'MyriadPro-Regular'" font-size="12">0</text> -<text transform="matrix(-0.589 -0.7833 0.7993 -0.601 50.7637 138.0234)" font-family="'MyriadPro-Regular'" font-size="12.0005"> </text> -<text transform="matrix(-0.3613 -0.911 0.9296 -0.3686 42.665 124.7539)" font-family="'MyriadPro-Regular'" font-size="12">1</text> -<text transform="matrix(-0.275 -0.9406 0.9598 -0.2807 40.4512 119.1719)" font-family="'MyriadPro-Regular'" font-size="12">0</text> -<text transform="matrix(-0.213 -0.9566 0.9761 -0.2173 38.8223 113.4023)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.0159 -0.9799 0.9999 0.0162 36.96 100.019)" font-family="'MyriadPro-Regular'" font-size="12.0004">2</text> -<text transform="matrix(0.104 -0.9745 0.9944 0.1061 37.0518 94.0215)" font-family="'MyriadPro-Regular'" font-size="12.0005">0</text> -<text transform="matrix(0.167 -0.9657 0.9854 0.1704 37.7407 88.0718)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.3752 -0.9053 0.9238 0.3828 40.7725 75.9199)" font-family="'MyriadPro-Regular'" font-size="12">3</text> -<text transform="matrix(0.4573 -0.8669 0.8845 0.4666 43.0674 70.3799)" font-family="'MyriadPro-Regular'" font-size="11.9993">0</text> -<text transform="matrix(0.5127 -0.8352 0.8523 0.5231 45.9121 65.1069)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.6672 -0.7178 0.7325 0.6808 52.3262 55.9673)" font-family="'MyriadPro-Regular'" font-size="12">4</text> -<text transform="matrix(0.7301 -0.6537 0.6671 0.745 56.4102 51.5703)" font-family="'MyriadPro-Regular'" font-size="12">0</text> -<text transform="matrix(0.7708 -0.6052 0.6176 0.7865 60.9082 47.6182)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.8905 -0.4092 0.4175 0.9087 72.1504 40.165)" font-family="'MyriadPro-Regular'" font-size="12">5</text> -<text transform="matrix(0.9246 -0.3249 0.3315 0.9435 77.6006 37.6587)" font-family="'MyriadPro-Regular'" font-size="12.0005">0</text> -<text transform="matrix(0.944 -0.2633 0.2687 0.9632 83.2959 35.7197)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.9797 -0.0248 0.0253 0.9997 97.3081 33.0972)" font-family="'MyriadPro-Regular'" font-size="12">6</text> -<text transform="matrix(0.9779 0.0643 -0.0656 0.9978 103.3198 32.9438)" font-family="'MyriadPro-Regular'" font-size="11.9994">0</text> -<text transform="matrix(0.9717 0.1274 -0.13 0.9915 109.2959 33.3921)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.9148 0.3514 -0.3586 0.9335 122.4863 36.2207)" font-family="'MyriadPro-Regular'" font-size="12">7</text> -<text transform="matrix(0.8783 0.4348 -0.4437 0.8962 128.0967 38.375)" font-family="'MyriadPro-Regular'" font-size="12">0</text> -<text transform="matrix(0.8481 0.4911 -0.5011 0.8654 133.4463 41.085)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.719 0.6659 -0.6795 0.7337 143.9395 48.2495)" font-family="'MyriadPro-Regular'" font-size="12">8</text> -<text transform="matrix(0.6551 0.7289 -0.7438 0.6684 148.3438 52.3242)" font-family="'MyriadPro-Regular'" font-size="12">0</text> -<text transform="matrix(0.6067 0.7696 -0.7853 0.6191 152.3047 56.814)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.4267 0.8822 -0.9002 0.4354 159.2344 67.0146)" font-family="'MyriadPro-Regular'" font-size="11.9996">9</text> -<text transform="matrix(0.3433 0.9179 -0.9366 0.3503 161.8438 72.4062)" font-family="'MyriadPro-Regular'" font-size="11.9996">0</text> -<text transform="matrix(0.2823 0.9384 -0.9576 0.2881 163.8945 78.0513)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(0.1113 0.9737 -0.9935 0.1136 166.2334 87.54)" font-family="'MyriadPro-Regular'" font-size="12">1</text> -<text transform="matrix(0.0217 0.9798 -0.9998 0.0221 166.917 93.5156)" font-family="'MyriadPro-Regular'" font-size="12.0005">0</text> -<text transform="matrix(-0.067 0.9777 -0.9977 -0.0684 167.0527 99.502)" font-family="'MyriadPro-Regular'" font-size="12.0005">0</text> -<text transform="matrix(-0.1305 0.9713 -0.9911 -0.1331 166.5859 105.5)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(-0.2564 0.9459 -0.9652 -0.2616 165.5303 112.1348)" font-family="'MyriadPro-Regular'" font-size="12">1</text> -<text transform="matrix(-0.3429 0.918 -0.9368 -0.3499 163.9658 117.918)" font-family="'MyriadPro-Regular'" font-size="12">1</text> -<text transform="matrix(-0.4267 0.8822 -0.9002 -0.4354 161.8613 123.5527)" font-family="'MyriadPro-Regular'" font-size="11.9996">0</text> -<text transform="matrix(-0.4834 0.8525 -0.8699 -0.4932 159.1973 128.9287)" font-family="'MyriadPro-Regular'" font-size="12"> </text> -<text transform="matrix(-0.5948 0.7788 -0.7947 -0.607 155.5195 135.0195)" font-family="'MyriadPro-Regular'" font-size="12">1</text> -<text transform="matrix(-0.6637 0.721 -0.7357 -0.6773 151.8789 139.791)" font-family="'MyriadPro-Regular'" font-size="12">2</text> -<text transform="matrix(-0.7269 0.6572 -0.6707 -0.7418 147.8154 144.2051)" font-family="'MyriadPro-Regular'" font-size="12.0006">0</text> -<path fill="#333333" d="M141.121,133.456l7.08,6.485l-0.436,0.475l-7.08-6.484L141.121,133.456z"/> -<path fill="#333333" d="M143.077,132.336l4.927,4.186l-0.541,0.637l-4.926-4.186L143.077,132.336z"/> -<path fill="#333333" d="M144.354,130.73l5.092,4l-0.518,0.658l-5.091-4L144.354,130.73z"/> -<path fill="#333333" d="M145.572,129.104l5.234,3.806l-0.492,0.676l-5.233-3.806L145.572,129.104z"/> -<path fill="#333333" d="M146.73,127.412l5.379,3.6l-0.465,0.694l-5.379-3.601L146.73,127.412z"/> -<path fill="#333333" d="M147.157,125.37l8.179,5.036l-0.338,0.548l-8.18-5.035L147.157,125.37z"/> -<path fill="#333333" d="M148.854,123.91l5.637,3.178l-0.41,0.729l-5.637-3.178L148.854,123.91z"/> -<path fill="#333333" d="M149.814,122.104l5.75,2.963l-0.383,0.742l-5.75-2.963L149.814,122.104z"/> -<path fill="#333333" d="M150.709,120.241l5.861,2.735l-0.354,0.756l-5.861-2.734L150.709,120.241z"/> -<path fill="#333333" d="M151.516,118.376l5.965,2.51l-0.322,0.771l-5.965-2.51L151.516,118.376z"/> -<path fill="#333333" d="M151.539,116.303l8.988,3.389l-0.229,0.603l-8.986-3.388L151.539,116.303z"/> -<path fill="#333333" d="M152.928,114.539l6.141,2.047l-0.266,0.792l-6.14-2.047L152.928,114.539z"/> -<path fill="#333333" d="M153.525,112.57l6.211,1.811l-0.232,0.803l-6.212-1.812L153.525,112.57z"/> -<path fill="#333333" d="M154.046,110.602l6.272,1.562l-0.201,0.812l-6.273-1.563L154.046,110.602z"/> -<path fill="#333333" d="M154.482,108.585l6.336,1.326l-0.172,0.817l-6.334-1.326L154.482,108.585z"/> -<path fill="#333333" d="M154.117,106.549l9.461,1.604l-0.107,0.634l-9.461-1.603L154.117,106.549z"/> -<path fill="#333333" d="M155.132,104.559l6.417,0.833l-0.107,0.828l-6.416-0.833L155.132,104.559z"/> -<path fill="#333333" d="M155.338,102.516l6.448,0.586l-0.075,0.832l-6.447-0.586L155.338,102.516z"/> -<path fill="#333333" d="M155.477,100.476l6.459,0.34l-0.043,0.833l-6.459-0.339L155.477,100.476z"/> -<path fill="#333333" d="M155.529,98.425l6.469,0.103l-0.014,0.835l-6.469-0.103L155.529,98.425z"/> -<path fill="#333333" d="M154.777,96.482l9.6-0.213l0.014,0.643l-9.598,0.214L154.777,96.482z"/> -<path fill="#333333" d="M155.406,94.336l6.458-0.391l0.051,0.833l-6.459,0.391L155.406,94.336z"/> -<path fill="#333333" d="M155.232,92.29l6.438-0.627l0.081,0.831l-6.438,0.627L155.232,92.29z"/> -<path fill="#333333" d="M154.979,90.257l6.407-0.874l0.112,0.827l-6.407,0.874L154.979,90.257z"/> -<path fill="#333333" d="M154.639,88.227l6.377-1.121l0.146,0.823l-6.377,1.121L154.639,88.227z"/> -<path fill="#333333" d="M153.539,86.475l9.384-2.029l0.138,0.629l-9.386,2.029L153.539,86.475z"/> -<path fill="#333333" d="M153.756,84.251l6.264-1.604l0.207,0.809l-6.264,1.604L153.756,84.251z"/> -<path fill="#333333" d="M153.188,82.293l6.203-1.852l0.237,0.801l-6.201,1.852L153.188,82.293z"/> -<path fill="#333333" d="M152.545,80.339l6.13-2.088l0.271,0.791l-6.131,2.088L152.545,80.339z"/> -<path fill="#333333" d="M151.84,78.426l6.036-2.324l0.301,0.779l-6.036,2.324L151.84,78.426z"/> -<path fill="#333333" d="M150.427,76.915l8.819-3.784l0.254,0.592l-8.82,3.784L150.427,76.915z"/> -<path fill="#333333" d="M150.199,74.675l5.841-2.777l0.358,0.754l-5.842,2.777L150.199,74.675z"/> -<path fill="#333333" d="M149.271,72.855L155,69.852l0.389,0.74l-5.729,3.003L149.271,72.855z"/> -<path fill="#333333" d="M148.271,71.069l5.614-3.22l0.415,0.726l-5.615,3.219L148.271,71.069z"/> -<path fill="#333333" d="M147.204,69.314l5.481-3.435l0.442,0.707l-5.481,3.436L147.204,69.314z"/> -<path fill="#333333" d="M145.529,68.108l7.936-5.401l0.362,0.531l-7.935,5.402L145.529,68.108z"/> -<path fill="#333333" d="M144.887,65.962l5.215-3.836l0.494,0.673l-5.214,3.836L144.887,65.962z"/> -<path fill="#333333" d="M143.63,64.343l5.062-4.031l0.521,0.653l-5.062,4.031L143.63,64.343z"/> -<path fill="#333333" d="M142.307,62.78l4.904-4.228l0.546,0.634l-4.905,4.227L142.307,62.78z"/> -<path fill="#333333" d="M140.932,61.255l4.74-4.401l0.568,0.612l-4.741,4.401L140.932,61.255z"/> -<path fill="#333333" d="M139.052,60.387l6.774-6.806l0.456,0.454l-6.774,6.806L139.052,60.387z"/> -<path fill="#333333" d="M138.008,58.389l4.393-4.752l0.613,0.567l-4.392,4.751L138.008,58.389z"/> -<path fill="#333333" d="M136.467,57.041l4.207-4.916l0.635,0.543l-4.207,4.916L136.467,57.041z"/> -<path fill="#333333" d="M134.871,55.746l4.021-5.07l0.654,0.52l-4.021,5.07L134.871,55.746z"/> -<path fill="#333333" d="M133.227,54.52l3.825-5.224l0.675,0.493l-3.826,5.225L133.227,54.52z"/> -<path fill="#333333" d="M131.211,54.016l5.371-7.966l0.534,0.36l-5.371,7.965L131.211,54.016z"/> -<path fill="#333333" d="M129.803,52.251l3.414-5.503l0.711,0.441l-3.414,5.502L129.803,52.251z"/> -<path fill="#333333" d="M128.047,51.223l3.198-5.626l0.726,0.413l-3.197,5.625L128.047,51.223z"/> -<path fill="#333333" d="M126.244,50.255l2.982-5.739l0.739,0.386l-2.981,5.738L126.244,50.255z"/> -<path fill="#333333" d="M124.404,49.366l2.757-5.853l0.755,0.356l-2.756,5.852L124.404,49.366z"/> -<path fill="#333333" d="M122.325,49.252l3.754-8.835l0.592,0.252l-3.754,8.835L122.325,49.252z"/> -<path fill="#333333" d="M120.621,47.796l2.304-6.047l0.781,0.297l-2.304,6.047L120.621,47.796z"/> -<path fill="#333333" d="M118.693,47.118l2.066-6.13l0.791,0.267l-2.066,6.13L118.693,47.118z"/> -<path fill="#333333" d="M116.725,46.524l1.832-6.212l0.801,0.236l-1.83,6.212L116.725,46.524z"/> -<path fill="#333333" d="M114.779,46.004l1.582-6.273l0.812,0.204l-1.584,6.273L114.779,46.004z"/> -<path fill="#333333" d="M112.713,46.28l1.998-9.385l0.629,0.135l-1.999,9.384L112.713,46.28z"/> -<path fill="#333333" d="M110.762,45.182l1.102-6.377l0.822,0.143l-1.101,6.376L110.762,45.182z"/> -<path fill="#333333" d="M108.746,44.895l0.854-6.417l0.828,0.109l-0.854,6.418L108.746,44.895z"/> -<path fill="#333333" d="M106.686,44.667l0.607-6.438l0.831,0.078l-0.606,6.438L106.686,44.667z"/> -<path fill="#333333" d="M104.646,44.531l0.36-6.458l0.833,0.046l-0.359,6.459L104.646,44.531z"/> -<path fill="#333333" d="M102.68,45.202l0.183-9.598l0.644,0.013l-0.184,9.598L102.68,45.202z"/> -<path fill="#333333" d="M100.542,44.489l-0.123-6.469l0.835-0.017l0.123,6.469L100.542,44.489z"/> -<path fill="#333333" d="M98.505,44.581l-0.37-6.458l0.833-0.048l0.37,6.458L98.505,44.581z"/> -<path fill="#333333" d="M96.458,44.747l-0.606-6.438l0.831-0.078l0.606,6.438L96.458,44.747z"/> -<path fill="#333333" d="M94.423,45.004l-0.854-6.418l0.828-0.109l0.854,6.417L94.423,45.004z"/> -<path fill="#333333" d="M92.632,46.025l-1.633-9.46l0.634-0.109l1.633,9.46L92.632,46.025z"/> -<path fill="#333333" d="M90.413,45.722l-1.347-6.324l0.816-0.174l1.347,6.324L90.413,45.722z"/> -<path fill="#333333" d="M88.408,46.207l-1.584-6.273l0.811-0.204l1.583,6.273L88.408,46.207z"/> -<path fill="#333333" d="M86.447,46.767l-1.83-6.212l0.802-0.236l1.83,6.212L86.447,46.767z"/> -<path fill="#333333" d="M84.515,47.387l-2.067-6.13l0.791-0.267l2.067,6.129L84.515,47.387z"/> -<path fill="#333333" d="M82.944,48.742l-3.418-8.972l0.602-0.229l3.418,8.973L82.944,48.742z"/> -<path fill="#333333" d="M80.687,48.877l-2.53-5.954l0.769-0.327l2.53,5.955L80.687,48.877z"/> -<path fill="#333333" d="M78.817,49.73l-2.756-5.852l0.755-0.356l2.757,5.853L78.817,49.73z"/> -<path fill="#333333" d="M77.015,50.641l-2.982-5.738l0.74-0.386l2.982,5.739L77.015,50.641z"/> -<path fill="#333333" d="M75.205,51.646l-3.198-5.626l0.726-0.413l3.199,5.626L75.205,51.646z"/> -<path fill="#333333" d="M73.931,53.274l-5.066-8.163l0.547-0.34l5.066,8.164L73.931,53.274z"/> -<path fill="#333333" d="M71.764,53.824l-3.62-5.368l0.692-0.468l3.62,5.368L71.764,53.824z"/> -<path fill="#333333" d="M70.097,55.016l-3.826-5.225l0.675-0.493l3.825,5.225L70.097,55.016z"/> -<path fill="#333333" d="M68.474,56.267l-4.021-5.07l0.655-0.521l4.021,5.07L68.474,56.267z"/> -<path fill="#333333" d="M66.896,57.584l-4.206-4.916l0.634-0.543l4.207,4.916L66.896,57.584z"/> -<path fill="#333333" d="M65.941,59.427l-6.515-7.05l0.472-0.437l6.516,7.05L65.941,59.427z"/> -<path fill="#333333" d="M63.906,60.392l-4.566-4.587l0.592-0.59l4.566,4.587L63.906,60.392z"/> -<path fill="#333333" d="M62.501,61.867l-4.741-4.401l0.568-0.612l4.741,4.402L62.501,61.867z"/> -<path fill="#333333" d="M61.145,63.415l-4.906-4.227l0.546-0.634l4.905,4.228L61.145,63.415z"/> -<path fill="#333333" d="M59.848,64.996l-5.06-4.031l0.521-0.653l5.06,4.031L59.848,64.996z"/> -<path fill="#333333" d="M59.263,66.991L51.526,61.3l0.381-0.519l7.736,5.691L59.263,66.991z"/> -<path fill="#333333" d="M57.446,68.317l-5.358-3.63l0.469-0.691l5.358,3.63L57.446,68.317z"/> -<path fill="#333333" d="M56.349,70.033l-5.492-3.425l0.442-0.709l5.491,3.425L56.349,70.033z"/> -<path fill="#333333" d="M55.312,71.795l-5.615-3.219l0.415-0.726l5.615,3.22L55.312,71.795z"/> -<path fill="#333333" d="M54.34,73.605l-5.738-2.993l0.386-0.74l5.739,2.992L54.34,73.605z"/> -<path fill="#333333" d="M54.141,75.654l-8.667-4.12l0.275-0.58l8.667,4.119L54.141,75.654z"/> -<path fill="#333333" d="M52.61,77.307l-5.944-2.551l0.33-0.768l5.944,2.551L52.61,77.307z"/> -<path fill="#333333" d="M51.851,79.216l-6.037-2.314l0.299-0.779l6.037,2.314L51.851,79.216z"/> -<path fill="#333333" d="M51.177,81.153l-6.13-2.088l0.27-0.791l6.13,2.088L51.177,81.153z"/> -<path fill="#333333" d="M50.569,83.094l-6.201-1.851l0.238-0.801l6.202,1.852L50.569,83.094z"/> -<path fill="#333333" d="M50.768,85.146l-9.293-2.38l0.159-0.623l9.293,2.38L50.768,85.146z"/> -<path fill="#333333" d="M49.584,87.067l-6.325-1.368l0.177-0.816l6.325,1.368L49.584,87.067z"/> -<path fill="#333333" d="M49.213,89.074l-6.377-1.121l0.146-0.823l6.376,1.121L49.213,89.074z"/> -<path fill="#333333" d="M48.907,91.083l-6.406-0.874l0.112-0.827l6.407,0.874L48.907,91.083z"/> -<path fill="#333333" d="M48.687,93.121l-6.438-0.628l0.081-0.831l6.438,0.628L48.687,93.121z"/> -<path fill="#333333" d="M49.276,95.13l-9.583-0.564l0.038-0.643l9.583,0.564L49.276,95.13z"/> -<path fill="#333333" d="M48.475,97.23l-6.47-0.144l0.019-0.835l6.47,0.144L48.475,97.23z"/> -<path fill="#333333" d="M48.483,99.283l-6.47,0.103L42,98.551l6.469-0.103L48.483,99.283z"/> -<path fill="#333333" d="M48.568,101.321l-6.458,0.35l-0.046-0.833l6.459-0.35L48.568,101.321z"/> -<path fill="#333333" d="M48.737,103.374l-6.448,0.586l-0.075-0.832l6.448-0.587L48.737,103.374z"/> -<path fill="#333333" d="M49.688,105.223l-9.521,1.235l-0.083-0.638l9.521-1.236L49.688,105.223z"/> -<path fill="#333333" d="M49.291,107.421l-6.377,1.08l-0.139-0.823l6.376-1.08L49.291,107.421z"/> -<path fill="#333333" d="M49.691,109.426l-6.335,1.327l-0.172-0.817l6.335-1.326L49.691,109.426z"/> -<path fill="#333333" d="M50.159,111.432l-6.273,1.563l-0.202-0.812l6.274-1.562L50.159,111.432z"/> -<path fill="#333333" d="M50.707,113.372l-6.212,1.81l-0.233-0.802l6.212-1.81L50.707,113.372z"/> -<path fill="#333333" d="M51.998,115.01l-9.109,3.037l-0.204-0.609l9.11-3.037L51.998,115.01z"/> -<path fill="#333333" d="M52.037,117.253l-6.058,2.283l-0.294-0.782l6.058-2.281L52.037,117.253z"/> -<path fill="#333333" d="M52.807,119.146l-5.966,2.509l-0.323-0.771l5.965-2.51L52.807,119.146z"/> -<path fill="#333333" d="M53.652,121.018l-5.862,2.735l-0.353-0.757l5.862-2.735L53.652,121.018z"/> -<path fill="#333333" d="M54.565,122.846l-5.749,2.963l-0.382-0.742l5.749-2.963L54.565,122.846z"/> -<path fill="#333333" d="M56.144,124.195l-8.362,4.716l-0.315-0.562l8.361-4.715L56.144,124.195z"/> -<path fill="#333333" d="M56.606,126.384l-5.513,3.394l-0.438-0.711l5.513-3.395L56.606,126.384z"/> -<path fill="#333333" d="M57.731,128.107l-5.379,3.6l-0.464-0.693l5.378-3.601L57.731,128.107z"/> -<path fill="#333333" d="M58.918,129.779l-5.235,3.805l-0.491-0.676l5.235-3.805L58.918,129.779z"/> -<path fill="#333333" d="M60.164,131.405l-5.08,4l-0.517-0.655l5.08-4.001L60.164,131.405z"/> -<path fill="#333333" d="M61.971,132.432l-7.31,6.226l-0.417-0.49l7.31-6.226L61.971,132.432z"/> -<path fill="#FFF200" d="M137.911,69.32l3.624-2.875c-5.367-6.779-12.527-12.29-21.146-15.7l-1.701,4.304 - C126.523,58.147,133.029,63.156,137.911,69.32z"/> -<path fill="#FFB700" d="M147.43,91.292l4.574-0.677c-1.314-8.823-4.932-17.174-10.469-24.17l-3.624,2.875 - C142.945,75.68,146.232,83.27,147.43,91.292z"/> -<path fill="#FFF200" d="M94.898,52.31l-0.677-4.574c-8.823,1.314-17.173,4.932-24.167,10.469l2.875,3.623 - C79.287,56.793,86.878,53.505,94.898,52.31z"/> -<path fill="#FFB700" d="M72.93,61.827l-2.875-3.623c-6.781,5.367-12.291,12.525-15.702,21.146l4.303,1.701 - C61.755,73.216,66.765,66.707,72.93,61.827z"/> -<path fill="#59DE00" d="M118.688,55.049l1.701-4.304c-8.621-3.408-17.613-4.285-26.167-3.01l0.677,4.574 - C102.676,51.151,110.85,51.948,118.688,55.049z"/> -</svg> diff --git a/examples/declarative/dial/DialLibrary/needle.png b/examples/declarative/dial/DialLibrary/needle.png Binary files differnew file mode 100644 index 0000000..2d19f75 --- /dev/null +++ b/examples/declarative/dial/DialLibrary/needle.png diff --git a/examples/declarative/dial/DialLibrary/needle.svg b/examples/declarative/dial/DialLibrary/needle.svg deleted file mode 100644 index dce7d7e..0000000 --- a/examples/declarative/dial/DialLibrary/needle.svg +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In --> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ - <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> -]> -<svg version="1.1" - xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" - x="0px" y="0px" width="210px" height="210px" viewBox="-98 -35 210 210" enable-background="new -98 -35 210 210" - xml:space="preserve"> -<defs> -</defs> -<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-102.5" y1="-13.5" x2="-94.5" y2="-13.5" gradientTransform="matrix(1 0 0 -1 102.5 18)"> - <stop offset="0" style="stop-color:#EC1C24"/> - <stop offset="0.0782" style="stop-color:#E51B23"/> - <stop offset="0.3901" style="stop-color:#CA181F"/> - <stop offset="0.5495" style="stop-color:#F0C7C9"/> - <stop offset="0.5972" style="stop-color:#D98D90"/> - <stop offset="0.6452" style="stop-color:#C4595D"/> - <stop offset="0.687" style="stop-color:#B53339"/> - <stop offset="0.7206" style="stop-color:#AC1C22"/> - <stop offset="0.7418" style="stop-color:#A9141A"/> - <stop offset="1" style="stop-color:#EC1C24"/> -</linearGradient> -<path fill="url(#SVGID_1_)" d="M8,61c0,1.104-2.343,2-4,2l0,0c-1.657,0-4-0.896-4-2L2.5,2C2.5,0.896,3,0,4,0l0,0 - c1,0,1.5,0.896,1.5,2L8,61z"/> -</svg> diff --git a/examples/declarative/dial/DialLibrary/needle_shadow.png b/examples/declarative/dial/DialLibrary/needle_shadow.png Binary files differnew file mode 100644 index 0000000..8d8a928 --- /dev/null +++ b/examples/declarative/dial/DialLibrary/needle_shadow.png diff --git a/examples/declarative/dial/DialLibrary/needle_shadow.svg b/examples/declarative/dial/DialLibrary/needle_shadow.svg deleted file mode 100644 index 6aab197..0000000 --- a/examples/declarative/dial/DialLibrary/needle_shadow.svg +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In --> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ - <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> -]> -<svg version="1.1" - xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" - x="0px" y="0px" width="210px" height="210px" viewBox="-90 -30 210 210" enable-background="new -90 -30 210 210" - xml:space="preserve"> -<defs> -</defs> -<image overflow="visible" opacity="0.5" enable-background="new " width="26" height="81" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAABSCAYAAAClg6/xAAAACXBIWXMAAAsSAAALEgHS3X78AAAA -GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAydJREFUeNrsmetu2zAMhUVaS9pu -2Pu/5dY2vaSJ7dkAOZ8y1M3Jjw6zAUKx4ugLJZo+FkPYjhsc1Hidd/1o2tUwhKAhCC0LpQJIjcG0 -TwEDmAU3webBO7EInxXWi53h89AK038/D/xNbCdtBNgMOU32Ie1JgK53OZh6M0PuwHbi8SCQd7AP -8PIC1iVguj6zJ/vJ7if7AfYgUJ3SIbF21TCdwtmb7wL5Ke09wAazbklYLIR7B949gFdRBu+kPco0 -dub3YwkWTMjjuul0KmwUyE762LkXi7Ac8E681eirArXANDLxFiC4FboaGGcgwckenWM2u4QUlBty -IxtP2fQXcy03JmE2EHYSNK2BhUQiThmVPIsNGb8zSXlw1o2uCX12Mr9G4GieBDZImj2zYY9PgADn -VeEfK9bJ3mN7ack8drrS+sVCBCoIYTvwDGERcqObH3OJ2Hpmp3J0QAwRTmvWLAUcE6DkmvHK0E+l -LGqBUSFzsElXXMgk1JJBPGjuPKzNjWvU8VWw1JRQZuqv8owy0o9a3hu+1DTe9NhgG2yDJZPvWmsW -qWt04yqtn9L5pT5q1fqlJ3SseGJXSzlPnFrrzXkRGAtTaIUOtoM594QqpWBUUMO2HZx+TxX/1Y6x -oBnZmUbrmSfnXO3IFTrfrlupj1uikSpkXFch57IwSqybNyAXvneFUqtubE5Ra6RcreC5+gU+pw+p -IO+2h+cG22BfEFaTiv6N19zS22Su3pL9LVfmRa/IkysYNG8BBjPoOSy1F5JW+/C65s1N9GQe7CN8 -rrv0AnuH784ZTy9gtvDWA2ge9GWy57DUaE5y/hL8os/F2saEVwh6m+ww2WNYKhXaPkv/Qa6rrjLZ -CoVVT0EGmQd8nexpst+T/RJ7FPhrWOppn6CdE50MG5soo7FedgCY2pP0z98fw1JxGlIhiqUsrZtp -OcuWsnozzQdZvzeBnQCY1BkM07cX04LPPix1mFEGPEKUHsXOJjqTNx9ndr1xHxgD6QR29qYwJ8co -8cKHG854i2h1sM9lFqpItuxsZHo3/2imrbqam9tvtLAQblCBr71+DP/98UeAAQDKLu+cxVe7aAAA -AABJRU5ErkJggg=="> -</image> -</svg> diff --git a/examples/declarative/dial/DialLibrary/overlay.png b/examples/declarative/dial/DialLibrary/overlay.png Binary files differnew file mode 100644 index 0000000..3860a7b --- /dev/null +++ b/examples/declarative/dial/DialLibrary/overlay.png diff --git a/examples/declarative/dial/DialLibrary/overlay.svg b/examples/declarative/dial/DialLibrary/overlay.svg deleted file mode 100644 index 8530dd5..0000000 --- a/examples/declarative/dial/DialLibrary/overlay.svg +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In --> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ - <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> -]> -<svg version="1.1" - xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" - x="0px" y="0px" width="210px" height="210px" viewBox="-21.12 -18.396 210 210" enable-background="new -21.12 -18.396 210 210" - xml:space="preserve"> -<defs> -</defs> -<image overflow="visible" opacity="0.5" enable-background="new " width="48" height="48" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAxCAYAAABznEEcAAAACXBIWXMAAAsSAAALEgHS3X78AAAA -GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA/JJREFUeNrsWolum0AQZQHfOdrc -//93bZO2OVwTx2YL0hvpaTK7C7iJUhSkJ2wMu/N2jp0ZnGWfx8c43BuPx9+9+s1/FBKOzs4YM0TC -09kfSsod8JxGblzLjNVn1MY1/9YktNCCAuBrztCECC7YA3ytNxk3gAALXQIToFRkNAkWftfgBdgB -TKozEdeDgAgmgk+BGWEKMkxEDibQCr5t8EzYAkKINXMwCV59WfV5gwWwBBa4PlUaYRKigVbYqsGm -wR9gA1SknX0XIq4HgQkEFMGPGhwTVkRkEiHxQgTWDR4JT0Roi3uTRFwPAjMS/qTBaYMvwAkREbMq -yC88kRAzEgIPDX4D9/guZJ67EHEJJ2YCKwjaCn/W4BznMxAZSqIV/idwh/M9flsrIqazlwktiA8s -oIGWwAVwhfM5rh9DU7MO5vSMlX7EuAs8x894I+zWXUmwFkrY+BImcwbBbxpcN7jEtVPyCQm1oegk -oXUDAkw8N+7dKzJOEykTvjBVWjiHBq6BltBXaEFWs1SmpPcJiVBzFc1yQ2NbtYeY+0fRgcAxBBUT -ugEuDVOa014xoT2lJHLWtYII643wJeXcRcQXxJnFkUUDN/gsBLRJlLSyevcuAqmKIzPRm+E2FW41 -CZlANrQjRJ4LrLz4wQVFpGVgp3YR8D1sdjWtfAUSFUWonRWlLBIxU7pSfqCdMjfSc2ek6i6QqnP0 -qtQuvg2F2jJQG+SUH0mKsQKW5MRWnuQ6ZAie7ue9SLKBlcoA2PlZTp+pEGhlqhMiwoneJBCF+iSU -obyM55kbpvqqVskTGSsPPqUBYyl33/rk4LnyRN3AUaQIFD+HFFg6oKTmcykSlvPlEbiBwqdMKzaf -FRxMTaQqu/fqwnSeqw+JQUX8wKPXXHngQauor42C/l/0j7yRtYbms1o9pia8UdRr8OBDm2HeyHBT -85kaCpGwuhKcw1gp8lAtHDxXHtECJ2KV6kyECnk/0ISYAM9TBZI/H/MJHlh3JdaAFPK6/q07OCX/ -VhvVnnQ/ZC7Om3ahBSs6pB0zKmAWgdTDRXqwMZ/bUca6Rm3d1tm3DX7g8y80D6RxoMm8IqGJcHdv -Rs0yKx3IEl1vHzAf0fIDmgQtge8gcYtGwiO1cfYqoAQ1YeU0sYrMJUymplRbN9AsAkJCOh/rkBZS -mnCRnMZKBVKheacqtk2CwC1M6cnQQpJE6N1DHilmaiUs18hb1XfdULvmXhH4BggB0UKlqrqsCwld -eDhl59o8QgJzdSZR54m6fndKA0LgDgRECxLSzcg3ig7gqHuxo+mKj+b9xGjeFI3mnd1o3p6O5j12 -alfPsv/oHwVdx3uX/3Z8Hh/l+CvAAIH3kc3b00M7AAAAAElFTkSuQmCC" transform="matrix(1 0 0 1 57.8799 59.604)"> -</image> -<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-26.0957" y1="-12.2373" x2="-17.2345" y2="-44.2323" gradientTransform="matrix(1 0 0 -1 102.5 51.208)"> - <stop offset="0" style="stop-color:#FFFFFF"/> - <stop offset="1" style="stop-color:#000000"/> -</linearGradient> -<circle fill="url(#SVGID_1_)" cx="80.88" cy="79.604" r="15"/> -<radialGradient id="SVGID_2_" cx="-28.9624" cy="-17.0811" r="25.2655" gradientTransform="matrix(1 0 0 -1 102.5 51.208)" gradientUnits="userSpaceOnUse"> - <stop offset="0" style="stop-color:#FFFFFF"/> - <stop offset="1" style="stop-color:#616161"/> -</radialGradient> -<path fill="url(#SVGID_2_)" d="M80.88,92.603c-7.167,0-12.999-5.832-12.999-13c-0.001-7.166,5.832-12.999,12.999-12.999 - s13,5.832,13,12.999C93.879,86.771,88.047,92.603,80.88,92.603L80.88,92.603z"/> -<path opacity="0.5" fill="#FFFFFF" enable-background="new " d="M10.697,75.919c27.161-27.154,64.439-42.608,102.867-42.608 - c11.422,0,22.744,1.386,33.739,4.018C133.183,14.903,108.235,0,79.768,0C35.712,0,0,35.714,0,79.768c0,2.589,0.14,5.14,0.387,7.648 - C3.609,83.419,7.044,79.58,10.697,75.919z"/> -</svg> diff --git a/examples/statemachine/clockticking/clockticking.pro b/examples/statemachine/clockticking/clockticking.pro deleted file mode 100644 index bff9cb8..0000000 --- a/examples/statemachine/clockticking/clockticking.pro +++ /dev/null @@ -1,10 +0,0 @@ -QT = core -TEMPLATE = app -TARGET = -win32: CONFIG += console -mac:CONFIG -= app_bundle -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/examples/statemachine/composition/composition.pro b/examples/statemachine/composition/composition.pro deleted file mode 100644 index 6a976cb..0000000 --- a/examples/statemachine/composition/composition.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/examples/statemachine/composition/main.cpp b/examples/statemachine/composition/main.cpp deleted file mode 100644 index 0afff66..0000000 --- a/examples/statemachine/composition/main.cpp +++ /dev/null @@ -1,104 +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 QtCore 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 <QtGui> -#ifdef QT_STATEMACHINE_SOLUTION -#include <qstatemachine.h> -#include <qstate.h> -#include <qfinalstate.h> -#endif - -int main(int argc, char **argv) -{ - QApplication app(argc, argv); - QLabel label; - label.setAlignment(Qt::AlignCenter); - - QStateMachine machine; - - QState *s1 = new QState(); - s1->setObjectName("s1"); - s1->assignProperty(&label, "text", "In S1, hang on..."); - s1->assignProperty(&label, "geometry", QRect(100, 100, 200, 100)); - - QState *s1_timer = new QState(s1); - s1_timer->setObjectName("s1_timer"); - QTimer t1; - t1.setInterval(2000); - QObject::connect(s1_timer, SIGNAL(entered()), &t1, SLOT(start())); - QFinalState *s1_done = new QFinalState(s1); - s1_done->setObjectName("s1_done"); - s1_timer->addTransition(&t1, SIGNAL(timeout()), s1_done); - s1->setInitialState(s1_timer); - - QState *s2 = new QState(); - s2->setObjectName("s2"); - s2->assignProperty(&label, "text", "In S2, I'm gonna quit on you..."); - s2->assignProperty(&label, "geometry", QRect(300, 300, 300, 100)); -// s2->invokeMethodOnEntry(&label, "setNum", QList<QVariant>() << 123); -// s2->invokeMethodOnEntry(&label, "showMaximized"); - - QState *s2_timer = new QState(s2); - s2_timer->setObjectName("s2_timer"); - QTimer t2; - t2.setInterval(2000); - QObject::connect(s2_timer, SIGNAL(entered()), &t2, SLOT(start())); - QFinalState *s2_done = new QFinalState(s2); - s2_done->setObjectName("s2_done"); - s2_timer->addTransition(&t2, SIGNAL(timeout()), s2_done); - s2->setInitialState(s2_timer); - - s1->addTransition(s1, SIGNAL(finished()), s2); - - QFinalState *s3 = new QFinalState(); - s3->setObjectName("s3"); - s2->addTransition(s2, SIGNAL(finished()), s3); - - machine.addState(s1); - machine.addState(s2); - machine.addState(s3); - machine.setInitialState(s1); - QObject::connect(&machine, SIGNAL(finished()), &app, SLOT(quit())); - machine.start(); - - label.show(); - return app.exec(); -} diff --git a/examples/statemachine/errorstateplugins/errorstateplugins.pro b/examples/statemachine/errorstateplugins/errorstateplugins.pro deleted file mode 100644 index 5b6b758..0000000 --- a/examples/statemachine/errorstateplugins/errorstateplugins.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = random_ai \ - spin_ai_with_error \ - spin_ai \ - seek_ai - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins -sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS errorstateplugins.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins -INSTALLS += target sources diff --git a/examples/statemachine/eventtransitions/main.cpp b/examples/statemachine/eventtransitions/main.cpp index f564b7e..aba0c73 100644 --- a/examples/statemachine/eventtransitions/main.cpp +++ b/examples/statemachine/eventtransitions/main.cpp @@ -46,6 +46,7 @@ #include <qeventtransition.h> #endif +//! [0] class Window : public QWidget { public: @@ -54,7 +55,9 @@ public: { QPushButton *button = new QPushButton(this); button->setGeometry(QRect(100, 100, 100, 100)); +//! [0] +//! [1] QStateMachine *machine = new QStateMachine(this); QState *s1 = new QState(); @@ -62,15 +65,21 @@ public: QState *s2 = new QState(); s2->assignProperty(button, "text", "Inside"); +//! [1] +//! [2] QEventTransition *enterTransition = new QEventTransition(button, QEvent::Enter); enterTransition->setTargetState(s2); s1->addTransition(enterTransition); +//! [2] +//! [3] QEventTransition *leaveTransition = new QEventTransition(button, QEvent::Leave); leaveTransition->setTargetState(s1); s2->addTransition(leaveTransition); +//! [3] +//! [4] QState *s3 = new QState(); s3->assignProperty(button, "text", "Pressing..."); @@ -81,16 +90,20 @@ public: QEventTransition *releaseTransition = new QEventTransition(button, QEvent::MouseButtonRelease); releaseTransition->setTargetState(s2); s3->addTransition(releaseTransition); +//! [4] +//! [5] machine->addState(s1); machine->addState(s2); machine->addState(s3); + machine->setInitialState(s1); - QObject::connect(machine, SIGNAL(finished()), qApp, SLOT(quit())); machine->start(); } }; +//! [5] +//! [6] int main(int argc, char **argv) { QApplication app(argc, argv); @@ -100,3 +113,4 @@ int main(int argc, char **argv) return app.exec(); } +//! [6] diff --git a/examples/statemachine/factorial/main.cpp b/examples/statemachine/factorial/main.cpp index 2b63690..1065eb8 100644 --- a/examples/statemachine/factorial/main.cpp +++ b/examples/statemachine/factorial/main.cpp @@ -48,6 +48,7 @@ #include <qfinalstate.h> #endif +//! [0] class Factorial : public QObject { Q_OBJECT @@ -55,10 +56,8 @@ class Factorial : public QObject Q_PROPERTY(int fac READ fac WRITE setFac) public: Factorial(QObject *parent = 0) - : QObject(parent) + : QObject(parent), m_x(-1), m_fac(1) { - m_fac = 1; - m_x = -1; } int x() const @@ -71,7 +70,7 @@ public: if (x == m_x) return; m_x = x; - emit xChanged(); + emit xChanged(x); } int fac() const @@ -85,28 +84,34 @@ public: } Q_SIGNALS: - void xChanged(); + void xChanged(int value); private: int m_x; int m_fac; }; +//! [0] +//! [1] class FactorialLoopTransition : public QSignalTransition { public: FactorialLoopTransition(Factorial *fact) - : QSignalTransition(fact, SIGNAL(xChanged())), m_fact(fact) + : QSignalTransition(fact, SIGNAL(xChanged(int))), m_fact(fact) {} - virtual bool eventTest(QEvent *) const + virtual bool eventTest(QEvent *e) { - return m_fact->property("x").toInt() > 1; + if (!QSignalTransition::eventTest(e)) + return false; + QSignalEvent *se = static_cast<QSignalEvent*>(e); + return se->arguments().at(0).toInt() > 1; } - virtual void onTransition(QEvent *) + virtual void onTransition(QEvent *e) { - int x = m_fact->property("x").toInt(); + QSignalEvent *se = static_cast<QSignalEvent*>(e); + int x = se->arguments().at(0).toInt(); int fac = m_fact->property("fac").toInt(); m_fact->setProperty("fac", x * fac); m_fact->setProperty("x", x - 1); @@ -115,17 +120,22 @@ public: private: Factorial *m_fact; }; +//! [1] +//! [2] class FactorialDoneTransition : public QSignalTransition { public: FactorialDoneTransition(Factorial *fact) - : QSignalTransition(fact, SIGNAL(xChanged())), m_fact(fact) + : QSignalTransition(fact, SIGNAL(xChanged(int))), m_fact(fact) {} - virtual bool eventTest(QEvent *) const + virtual bool eventTest(QEvent *e) { - return m_fact->property("x").toInt() <= 1; + if (!QSignalTransition::eventTest(e)) + return false; + QSignalEvent *se = static_cast<QSignalEvent*>(e); + return se->arguments().at(0).toInt() <= 1; } virtual void onTransition(QEvent *) @@ -136,35 +146,37 @@ public: private: Factorial *m_fact; }; +//! [2] +//! [3] int main(int argc, char **argv) { QCoreApplication app(argc, argv); - Factorial factorial; - QStateMachine machine; +//! [3] - QState *computing = new QState(machine.rootState()); - computing->addTransition(new FactorialLoopTransition(&factorial)); +//! [4] + QState *compute = new QState(machine.rootState()); + compute->assignProperty(&factorial, "fac", 1); + compute->assignProperty(&factorial, "x", 6); + compute->addTransition(new FactorialLoopTransition(&factorial)); +//! [4] +//! [5] QFinalState *done = new QFinalState(machine.rootState()); FactorialDoneTransition *doneTransition = new FactorialDoneTransition(&factorial); doneTransition->setTargetState(done); - computing->addTransition(doneTransition); - - QState *initialize = new QState(machine.rootState()); - initialize->assignProperty(&factorial, "x", 6); - FactorialLoopTransition *enterLoopTransition = new FactorialLoopTransition(&factorial); - enterLoopTransition->setTargetState(computing); - initialize->addTransition(enterLoopTransition); + compute->addTransition(doneTransition); +//! [5] +//! [6] + machine.setInitialState(compute); QObject::connect(&machine, SIGNAL(finished()), &app, SLOT(quit())); - - machine.setInitialState(initialize); machine.start(); return app.exec(); } +//! [6] #include "main.moc" diff --git a/examples/statemachine/helloworld/helloworld.pro b/examples/statemachine/helloworld/helloworld.pro deleted file mode 100644 index ac79117..0000000 --- a/examples/statemachine/helloworld/helloworld.pro +++ /dev/null @@ -1,10 +0,0 @@ -TEMPLATE = app -TARGET = -QT = core -win32: CONFIG += console -mac:CONFIG -= app_bundle -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/examples/statemachine/pauseandresume/main.cpp b/examples/statemachine/pauseandresume/main.cpp deleted file mode 100644 index 5bacb41..0000000 --- a/examples/statemachine/pauseandresume/main.cpp +++ /dev/null @@ -1,102 +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 QtCore 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 <QtGui> -#ifdef QT_STATEMACHINE_SOLUTION -#include <qstatemachine.h> -#include <qstate.h> -#include <qfinalstate.h> -#include <qhistorystate.h> -#endif - -class Window : public QWidget -{ -public: - Window(QWidget *parent = 0) - : QWidget(parent) - { - QPushButton *pb = new QPushButton("Go"); - QPushButton *pauseButton = new QPushButton("Pause"); - QPushButton *quitButton = new QPushButton("Quit"); - QVBoxLayout *vbox = new QVBoxLayout(this); - vbox->addWidget(pb); - vbox->addWidget(pauseButton); - vbox->addWidget(quitButton); - - QStateMachine *machine = new QStateMachine(this); - - QState *process = new QState(machine->rootState()); - process->setObjectName("process"); - - QState *s1 = new QState(process); - s1->setObjectName("s1"); - QState *s2 = new QState(process); - s2->setObjectName("s2"); - s1->addTransition(pb, SIGNAL(clicked()), s2); - s2->addTransition(pb, SIGNAL(clicked()), s1); - - QHistoryState *h = new QHistoryState(process); - h->setDefaultState(s1); - - QState *interrupted = new QState(machine->rootState()); - interrupted->setObjectName("interrupted"); - QFinalState *terminated = new QFinalState(machine->rootState()); - terminated->setObjectName("terminated"); - interrupted->addTransition(pauseButton, SIGNAL(clicked()), h); - interrupted->addTransition(quitButton, SIGNAL(clicked()), terminated); - - process->addTransition(pauseButton, SIGNAL(clicked()), interrupted); - process->addTransition(quitButton, SIGNAL(clicked()), terminated); - - process->setInitialState(s1); - machine->setInitialState(process); - QObject::connect(machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit())); - machine->start(); - } -}; - -int main(int argc, char **argv) -{ - QApplication app(argc, argv); - Window win; - win.show(); - return app.exec(); -} diff --git a/examples/statemachine/pauseandresume/pauseandresume.pro b/examples/statemachine/pauseandresume/pauseandresume.pro deleted file mode 100644 index 6a976cb..0000000 --- a/examples/statemachine/pauseandresume/pauseandresume.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/examples/statemachine/pingpong/main.cpp b/examples/statemachine/pingpong/main.cpp index eb8fd5d..331627e 100644 --- a/examples/statemachine/pingpong/main.cpp +++ b/examples/statemachine/pingpong/main.cpp @@ -47,6 +47,7 @@ #include <qabstracttransition.h> #endif +//! [0] class PingEvent : public QEvent { public: @@ -60,7 +61,9 @@ public: PongEvent() : QEvent(QEvent::Type(QEvent::User+3)) {} }; +//! [0] +//! [1] class Pinger : public QState { public: @@ -74,14 +77,16 @@ protected: fprintf(stdout, "ping?\n"); } }; +//! [1] +//! [3] class PongTransition : public QAbstractTransition { public: PongTransition() {} protected: - virtual bool eventTest(QEvent *e) const { + virtual bool eventTest(QEvent *e) { return (e->type() == QEvent::User+3); } virtual void onTransition(QEvent *) @@ -90,14 +95,16 @@ protected: fprintf(stdout, "ping?\n"); } }; +//! [3] +//! [2] class PingTransition : public QAbstractTransition { public: PingTransition() {} protected: - virtual bool eventTest(QEvent *e) const { + virtual bool eventTest(QEvent *e) { return (e->type() == QEvent::User+2); } virtual void onTransition(QEvent *) @@ -106,7 +113,9 @@ protected: fprintf(stdout, "pong!\n"); } }; +//! [2] +//! [4] int main(int argc, char **argv) { QCoreApplication app(argc, argv); @@ -114,7 +123,9 @@ int main(int argc, char **argv) QStateMachine machine; QState *group = new QState(QState::ParallelStates); group->setObjectName("group"); +//! [4] +//! [5] Pinger *pinger = new Pinger(group); pinger->setObjectName("pinger"); pinger->addTransition(new PongTransition()); @@ -122,10 +133,13 @@ int main(int argc, char **argv) QState *ponger = new QState(group); ponger->setObjectName("ponger"); ponger->addTransition(new PingTransition()); +//! [5] +//! [6] machine.addState(group); machine.setInitialState(group); machine.start(); return app.exec(); } +//! [6] diff --git a/examples/statemachine/statemachine.pro b/examples/statemachine/statemachine.pro index ba32c12..5074a3c 100644 --- a/examples/statemachine/statemachine.pro +++ b/examples/statemachine/statemachine.pro @@ -1,14 +1,12 @@ TEMPLATE = subdirs SUBDIRS = \ - clockticking \ - composition \ eventtransitions \ factorial \ - helloworld \ - pauseandresume \ pingpong \ trafficlight \ - twowaybutton + twowaybutton \ + tankgame \ + tankgameplugins # install target.path = $$[QT_INSTALL_EXAMPLES]/statemachine diff --git a/examples/statemachine/errorstate/gameitem.cpp b/examples/statemachine/tankgame/gameitem.cpp index 1a2af71..1a2af71 100644 --- a/examples/statemachine/errorstate/gameitem.cpp +++ b/examples/statemachine/tankgame/gameitem.cpp diff --git a/examples/statemachine/errorstate/gameitem.h b/examples/statemachine/tankgame/gameitem.h index 43b8785..43b8785 100644 --- a/examples/statemachine/errorstate/gameitem.h +++ b/examples/statemachine/tankgame/gameitem.h diff --git a/examples/statemachine/tankgame/gameovertransition.cpp b/examples/statemachine/tankgame/gameovertransition.cpp new file mode 100644 index 0000000..cec786e --- /dev/null +++ b/examples/statemachine/tankgame/gameovertransition.cpp @@ -0,0 +1,39 @@ +#include "gameovertransition.h" +#include "tankitem.h" + +#include <QSignalEvent> +#include <QSignalMapper> + +GameOverTransition::GameOverTransition(QAbstractState *targetState) + : QSignalTransition(new QSignalMapper(), SIGNAL(mapped(QObject*))) +{ + setTargetState(targetState); + + QSignalMapper *mapper = qobject_cast<QSignalMapper *>(senderObject()); + mapper->setParent(this); +} + +void GameOverTransition::addTankItem(TankItem *tankItem) +{ + m_tankItems.append(tankItem); + + QSignalMapper *mapper = qobject_cast<QSignalMapper *>(senderObject()); + mapper->setMapping(tankItem, tankItem); + connect(tankItem, SIGNAL(aboutToBeDestroyed()), mapper, SLOT(map())); +} + +bool GameOverTransition::eventTest(QEvent *e) +{ + bool ret = QSignalTransition::eventTest(e); + + if (ret) { + QSignalEvent *signalEvent = static_cast<QSignalEvent *>(e); + QObject *sender = qvariant_cast<QObject *>(signalEvent->arguments().at(0)); + TankItem *tankItem = qobject_cast<TankItem *>(sender); + m_tankItems.removeAll(tankItem); + + return m_tankItems.size() <= 1; + } else { + return false; + } +}
\ No newline at end of file diff --git a/examples/statemachine/tankgame/gameovertransition.h b/examples/statemachine/tankgame/gameovertransition.h new file mode 100644 index 0000000..9a86b83 --- /dev/null +++ b/examples/statemachine/tankgame/gameovertransition.h @@ -0,0 +1,22 @@ +#ifndef GAMEOVERTRANSITION_H +#define GAMEOVERTRANSITION_H + +#include <QSignalTransition> + +class TankItem; +class GameOverTransition: public QSignalTransition +{ + Q_OBJECT +public: + GameOverTransition(QAbstractState *targetState); + + void addTankItem(TankItem *tankItem); + +protected: + bool eventTest(QEvent *event); + +private: + QList<TankItem *> m_tankItems; +}; + +#endif diff --git a/examples/statemachine/errorstate/main.cpp b/examples/statemachine/tankgame/main.cpp index 26fc1bb..26fc1bb 100644 --- a/examples/statemachine/errorstate/main.cpp +++ b/examples/statemachine/tankgame/main.cpp diff --git a/examples/statemachine/errorstate/mainwindow.cpp b/examples/statemachine/tankgame/mainwindow.cpp index 39b8663..fcc0325 100644 --- a/examples/statemachine/errorstate/mainwindow.cpp +++ b/examples/statemachine/tankgame/mainwindow.cpp @@ -2,6 +2,7 @@ #include "tankitem.h" #include "rocketitem.h" #include "plugin.h" +#include "gameovertransition.h" #include <QStateMachine> #include <QGraphicsView> @@ -12,6 +13,9 @@ #include <QTimer> #include <QFileDialog> #include <QPluginLoader> +#include <QApplication> +#include <QInputDialog> +#include <QMessageBox> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), m_scene(0), m_machine(0), m_runningState(0), m_started(false) @@ -50,7 +54,7 @@ void MainWindow::init() { TankItem *item = new TankItem(this); - item->setPos(m_scene->sceneRect().topLeft() + QPointF(15.0, 15.0)); + item->setPos(m_scene->sceneRect().topLeft() + QPointF(30.0, 30.0)); item->setDirection(45.0); item->setColor(Qt::red); @@ -60,7 +64,7 @@ void MainWindow::init() { TankItem *item = new TankItem(this); - item->setPos(m_scene->sceneRect().topRight() + QPointF(-15.0, 15.0)); + item->setPos(m_scene->sceneRect().topRight() + QPointF(-30.0, 30.0)); item->setDirection(135.0); item->setColor(Qt::green); @@ -70,7 +74,7 @@ void MainWindow::init() { TankItem *item = new TankItem(this); - item->setPos(m_scene->sceneRect().bottomRight() + QPointF(-15.0, -15.0)); + item->setPos(m_scene->sceneRect().bottomRight() + QPointF(-30.0, -30.0)); item->setDirection(225.0); item->setColor(Qt::blue); @@ -80,7 +84,7 @@ void MainWindow::init() { TankItem *item = new TankItem(this); - item->setPos(m_scene->sceneRect().bottomLeft() + QPointF(15.0, -15.0)); + item->setPos(m_scene->sceneRect().bottomLeft() + QPointF(30.0, -30.0)); item->setDirection(315.0); item->setColor(Qt::yellow); @@ -122,30 +126,45 @@ void MainWindow::init() stoppedState->assignProperty(this, "started", false); m_machine->setInitialState(stoppedState); - QState *spawnsAvailable = new QState(stoppedState); - spawnsAvailable->setObjectName("spawnsAvailable"); +//! [5] + QState *spawnsAvailable = new QState(stoppedState); spawnsAvailable->assignProperty(addTankAction, "enabled", true); - QState *noSpawnsAvailable = new QState(stoppedState); - noSpawnsAvailable->setObjectName("noSpawnsAvailable"); + QState *noSpawnsAvailable = new QState(stoppedState); noSpawnsAvailable->assignProperty(addTankAction, "enabled", false); +//! [5] + spawnsAvailable->setObjectName("spawnsAvailable"); + noSpawnsAvailable->setObjectName("noSpawnsAvailable"); spawnsAvailable->addTransition(this, SIGNAL(mapFull()), noSpawnsAvailable); - QHistoryState *hs = new QHistoryState(stoppedState); +//! [3] + QHistoryState *hs = new QHistoryState(stoppedState); hs->setDefaultState(spawnsAvailable); +//! [3] + hs->setObjectName("hs"); stoppedState->setInitialState(hs); +//! [0] m_runningState = new QState(QState::ParallelStates, m_machine->rootState()); +//! [0] m_runningState->setObjectName("runningState"); m_runningState->assignProperty(addTankAction, "enabled", false); m_runningState->assignProperty(runGameAction, "enabled", false); m_runningState->assignProperty(stopGameAction, "enabled", true); + + QState *gameOverState = new QState(m_machine->rootState()); + gameOverState->setObjectName("gameOverState"); + gameOverState->assignProperty(stopGameAction, "enabled", false); + connect(gameOverState, SIGNAL(entered()), this, SLOT(gameOver())); stoppedState->addTransition(runGameAction, SIGNAL(triggered()), m_runningState); m_runningState->addTransition(stopGameAction, SIGNAL(triggered()), stoppedState); + m_gameOverTransition = new GameOverTransition(gameOverState); + m_runningState->addTransition(m_gameOverTransition); + QTimer *timer = new QTimer(this); timer->setInterval(100); connect(timer, SIGNAL(timeout()), this, SLOT(runStep())); @@ -175,6 +194,22 @@ void MainWindow::runStep() } } +void MainWindow::gameOver() +{ + QList<QGraphicsItem *> items = m_scene->items(); + + TankItem *lastTankStanding = 0; + foreach (QGraphicsItem *item, items) { + if (GameItem *gameItem = qgraphicsitem_cast<GameItem *>(item)) { + if (lastTankStanding = qobject_cast<TankItem *>(gameItem)) + break; + } + } + + QMessageBox::information(this, "Game over!", + QString::fromLatin1("The tank played by '%1' has won!").arg(lastTankStanding->objectName())); +} + void MainWindow::addRocket() { TankItem *tankItem = qobject_cast<TankItem *>(sender()); @@ -193,25 +228,74 @@ void MainWindow::addTank() { Q_ASSERT(!m_spawns.isEmpty()); - QString fileName = QFileDialog::getOpenFileName(this, "Select plugin file", "plugins/", "*.dll"); - QPluginLoader loader(fileName); + QDir pluginsDir(qApp->applicationDirPath()); +#if defined(Q_OS_WIN) + if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release") + pluginsDir.cdUp(); +#elif defined(Q_OS_MAC) + if (pluginsDir.dirName() == "MacOS") { + pluginsDir.cdUp(); + pluginsDir.cdUp(); + pluginsDir.cdUp(); + } +#endif + + pluginsDir.cd("plugins"); + + QStringList itemNames; + QList<Plugin *> items; + foreach (QString fileName, pluginsDir.entryList(QDir::Files)) { + QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); + QObject *possiblePlugin = loader.instance(); + if (Plugin *plugin = qobject_cast<Plugin *>(possiblePlugin)) { + QString objectName = possiblePlugin->objectName(); + if (objectName.isEmpty()) + objectName = fileName; + + itemNames.append(objectName); + items.append(plugin); + } + } + + if (items.isEmpty()) { + QMessageBox::information(this, "No tank types found", "Please build the errorstateplugins directory"); + return; + } + + bool ok; +//! [1] + QString selectedName = QInputDialog::getItem(this, "Select a tank type", "Tank types", + itemNames, 0, false, &ok); +//! [1] - Plugin *plugin = qobject_cast<Plugin *>(loader.instance()); - if (plugin != 0) { - TankItem *tankItem = m_spawns.takeLast(); - m_scene->addItem(tankItem); - connect(tankItem, SIGNAL(cannonFired()), this, SLOT(addRocket())); - if (m_spawns.isEmpty()) - emit mapFull(); - - QState *region = new QState(m_runningState); - QState *pluginState = plugin->create(region, tankItem); - region->setInitialState(pluginState); - - // If the plugin has an error it is disabled - QState *errorState = new QState(region); - errorState->assignProperty(tankItem, "enabled", false); - pluginState->setErrorState(errorState); + if (ok && !selectedName.isEmpty()) { + int idx = itemNames.indexOf(selectedName); + if (Plugin *plugin = idx >= 0 ? items.at(idx) : 0) { + TankItem *tankItem = m_spawns.takeLast(); + tankItem->setObjectName(selectedName); + tankItem->setToolTip(selectedName); + m_scene->addItem(tankItem); + connect(tankItem, SIGNAL(cannonFired()), this, SLOT(addRocket())); + if (m_spawns.isEmpty()) + emit mapFull(); + + m_gameOverTransition->addTankItem(tankItem); + + QState *region = new QState(m_runningState); + region->setObjectName(QString::fromLatin1("region%1").arg(m_spawns.size())); +//! [2] + QState *pluginState = plugin->create(region, tankItem); +//! [2] + region->setInitialState(pluginState); + + // If the plugin has an error it is disabled +//! [4] + QState *errorState = new QState(region); + errorState->setObjectName(QString::fromLatin1("errorState%1").arg(m_spawns.size())); + errorState->assignProperty(tankItem, "enabled", false); + pluginState->setErrorState(errorState); +//! [4] + } } } diff --git a/examples/statemachine/errorstate/mainwindow.h b/examples/statemachine/tankgame/mainwindow.h index 622dabe..40e1595 100644 --- a/examples/statemachine/errorstate/mainwindow.h +++ b/examples/statemachine/tankgame/mainwindow.h @@ -7,6 +7,7 @@ class QGraphicsScene; class QStateMachine; class QState; +class GameOverTransition; class TankItem; class MainWindow: public QMainWindow { @@ -23,6 +24,7 @@ public slots: void addTank(); void addRocket(); void runStep(); + void gameOver(); signals: void mapFull(); @@ -35,6 +37,7 @@ private: QStateMachine *m_machine; QState *m_runningState; + GameOverTransition *m_gameOverTransition; QList<TankItem *> m_spawns; QTime m_time; diff --git a/examples/statemachine/errorstate/plugin.h b/examples/statemachine/tankgame/plugin.h index 2b48d43..2b48d43 100644 --- a/examples/statemachine/errorstate/plugin.h +++ b/examples/statemachine/tankgame/plugin.h diff --git a/examples/statemachine/errorstate/rocketitem.cpp b/examples/statemachine/tankgame/rocketitem.cpp index c324980..c324980 100644 --- a/examples/statemachine/errorstate/rocketitem.cpp +++ b/examples/statemachine/tankgame/rocketitem.cpp diff --git a/examples/statemachine/errorstate/rocketitem.h b/examples/statemachine/tankgame/rocketitem.h index 189a1dd..189a1dd 100644 --- a/examples/statemachine/errorstate/rocketitem.h +++ b/examples/statemachine/tankgame/rocketitem.h diff --git a/examples/statemachine/errorstate/errorstate.pro b/examples/statemachine/tankgame/tankgame.pro index b93a691..46cfe2e 100644 --- a/examples/statemachine/errorstate/errorstate.pro +++ b/examples/statemachine/tankgame/tankgame.pro @@ -5,9 +5,9 @@ TEMPLATE = app TARGET = DEPENDPATH += . -INCLUDEPATH += C:/dev/kinetic/examples/statemachine/errorstate/. . +INCLUDEPATH += C:/dev/kinetic/examples/statemachine/tankgame/. . # Input -HEADERS += mainwindow.h plugin.h tankitem.h rocketitem.h gameitem.h -SOURCES += main.cpp mainwindow.cpp tankitem.cpp rocketitem.cpp gameitem.cpp +HEADERS += mainwindow.h plugin.h tankitem.h rocketitem.h gameitem.h gameovertransition.h +SOURCES += main.cpp mainwindow.cpp tankitem.cpp rocketitem.cpp gameitem.cpp gameovertransition.cpp CONFIG += console diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/tankgame/tankitem.cpp index 5506a7e..c322d21 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/tankgame/tankitem.cpp @@ -113,6 +113,7 @@ void TankItem::idle(qreal elapsed) void TankItem::hitByRocket() { + emit aboutToBeDestroyed(); deleteLater(); } diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/tankgame/tankitem.h index cefed69..9475397 100644 --- a/examples/statemachine/errorstate/tankitem.h +++ b/examples/statemachine/tankgame/tankitem.h @@ -35,11 +35,13 @@ public: qreal distanceToObstacle() const; qreal distanceToObstacle(QGraphicsItem **item) const; +//! [0] signals: void tankSpotted(qreal direction, qreal distance); void collision(const QLineF &collidedLine); void actionCompleted(); void cannonFired(); + void aboutToBeDestroyed(); public slots: void moveForwards(qreal length = 10.0); @@ -48,6 +50,7 @@ public slots: void turnTo(qreal degrees = 0.0); void stop(); void fireCannon(); +//! [0] protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai.pro b/examples/statemachine/tankgameplugins/random_ai/random_ai.pro index f290250..5bc0b26 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai.pro +++ b/examples/statemachine/tankgameplugins/random_ai/random_ai.pro @@ -4,10 +4,10 @@ INCLUDEPATH += ../.. HEADERS = random_ai_plugin.h SOURCES = random_ai_plugin.cpp TARGET = $$qtLibraryTarget(random_ai) -DESTDIR = ../../errorstate/plugins +DESTDIR = ../../tankgame/plugins #! [0] # install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgame/plugins sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS random_ai.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/random_ai
\ No newline at end of file +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins/random_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp index c196247..c196247 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp +++ b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.h index 3db464b..f5e3b6f 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h +++ b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.h @@ -4,7 +4,7 @@ #include <QObject> #include <QState> -#include <errorstate/plugin.h> +#include <tankgame/plugin.h> class SelectActionState: public QState { @@ -56,6 +56,8 @@ class RandomAiPlugin: public QObject, public Plugin Q_OBJECT Q_INTERFACES(Plugin) public: + RandomAiPlugin() { setObjectName("Random"); } + virtual QState *create(QState *parentState, QObject *tank); }; diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.cpp index 2fb05d4..2fb05d4 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp +++ b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.cpp diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.h index 34d203e..9d4aabc 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h +++ b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.h @@ -1,7 +1,7 @@ #ifndef SEEK_AI_H #define SEEK_AI_H -#include <errorstate/plugin.h> +#include <tankgame/plugin.h> #include <QState> #include <QFinalState> @@ -81,7 +81,7 @@ public: } protected: - bool eventTest(QEvent *event) const + bool eventTest(QEvent *event) { bool b = QSignalTransition::eventTest(event); if (b) { @@ -105,7 +105,7 @@ protected: } private: - mutable QLineF m_lastLine; + QLineF m_lastLine; QObject *m_tank; QState *m_turnTo; }; @@ -137,16 +137,20 @@ public: ChaseState(QObject *tank, QState *parentState = 0) : QState(parentState), m_tank(tank) { QState *fireCannon = new QState(this); + fireCannon->setObjectName("fireCannon"); connect(fireCannon, SIGNAL(entered()), tank, SLOT(fireCannon())); setInitialState(fireCannon); - m_goToLocation = new GoToLocationState(this); + m_goToLocation = new GoToLocationState(tank, this); + m_goToLocation->setObjectName("goToLocation"); fireCannon->addTransition(tank, SIGNAL(actionCompleted()), m_goToLocation); m_turnToDirection = new QState(this); + m_turnToDirection->setObjectName("turnToDirection"); m_goToLocation->addTransition(tank, SIGNAL(actionCompleted()), m_turnToDirection); QFinalState *finalState = new QFinalState(this); + finalState->setObjectName("finalState"); m_turnToDirection->addTransition(tank, SIGNAL(actionCompleted()), finalState); } @@ -176,7 +180,7 @@ public: } protected: - bool eventTest(QEvent *event) const + bool eventTest(QEvent *event) { bool b = QSignalTransition::eventTest(event); if (b) { @@ -196,6 +200,8 @@ class SeekAi: public QObject, public Plugin Q_OBJECT Q_INTERFACES(Plugin) public: + SeekAi() { setObjectName("Seek and destroy"); } + virtual QState *create(QState *parentState, QObject *tank); }; diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.pro index 11bd242..0d8bf2e 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro +++ b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.pro @@ -4,10 +4,10 @@ INCLUDEPATH += ../.. HEADERS = seek_ai.h SOURCES = seek_ai.cpp TARGET = $$qtLibraryTarget(seek_ai) -DESTDIR = ../../errorstate/plugins +DESTDIR = ../../tankgame/plugins #! [0] # install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgame/plugins sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS seek_ai.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/seek_ai
\ No newline at end of file +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins/seek_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.cpp index de95f41..de95f41 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp +++ b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.cpp diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.h index 4b4629c..d8d3d73 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h +++ b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.h @@ -1,7 +1,7 @@ #ifndef SPIN_AI_H #define SPIN_AI_H -#include <errorstate/plugin.h> +#include <tankgame/plugin.h> #include <QObject> #include <QState> @@ -18,7 +18,7 @@ public: public slots: void spin() { - m_tank->setProperty("direction", 90.0); + m_tank->setProperty("direction", m_tank->property("direction").toDouble() + 90.0); } protected: @@ -28,6 +28,11 @@ protected: spin(); } + void onExit(QEvent *) + { + disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); + } + private: QObject *m_tank; @@ -38,6 +43,8 @@ class SpinAi: public QObject, public Plugin Q_OBJECT Q_INTERFACES(Plugin) public: + SpinAi() { setObjectName("Spin and destroy"); } + virtual QState *create(QState *parentState, QObject *tank); }; diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.pro index c2fd937..8ab4da0 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro +++ b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.pro @@ -4,10 +4,10 @@ INCLUDEPATH += ../.. HEADERS = spin_ai.h SOURCES = spin_ai.cpp TARGET = $$qtLibraryTarget(spin_ai) -DESTDIR = ../../errorstate/plugins +DESTDIR = ../../tankgame/plugins #! [0] # install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgame/plugins sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS spin_ai.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/spin_ai
\ No newline at end of file +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins/spin_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.cpp index 5499ba3..5499ba3 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp +++ b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.cpp diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.h index 9a96a8b..456ba01 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h +++ b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.h @@ -1,7 +1,7 @@ #ifndef SPIN_AI_WITH_ERROR_H #define SPIN_AI_WITH_ERROR_H -#include <errorstate/plugin.h> +#include <tankgame/plugin.h> #include <QObject> #include <QState> @@ -18,7 +18,7 @@ public: public slots: void spin() { - m_tank->setProperty("direction", 90.0); + m_tank->setProperty("direction", m_tank->property("direction").toDouble() + 90.0); } protected: @@ -28,6 +28,11 @@ protected: spin(); } + void onExit(QEvent *) + { + disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); + } + private: QObject *m_tank; @@ -38,6 +43,8 @@ class SpinAiWithError: public QObject, public Plugin Q_OBJECT Q_INTERFACES(Plugin) public: + SpinAiWithError() { setObjectName("Spin and destroy with runtime error in state machine"); } + virtual QState *create(QState *parentState, QObject *tank); }; diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.pro index 31f4c7f..124cf98 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro +++ b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.pro @@ -4,10 +4,10 @@ INCLUDEPATH += ../.. HEADERS = spin_ai_with_error.h SOURCES = spin_ai_with_error.cpp TARGET = $$qtLibraryTarget(spin_ai_with_error) -DESTDIR = ../../errorstate/plugins +DESTDIR = ../../tankgame/plugins #! [0] # install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgame/plugins sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS spin_ai_with_error.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/spin_ai_with_error
\ No newline at end of file +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins/spin_ai_with_error
\ No newline at end of file diff --git a/examples/statemachine/tankgameplugins/tankgameplugins.pro b/examples/statemachine/tankgameplugins/tankgameplugins.pro new file mode 100644 index 0000000..a098e03 --- /dev/null +++ b/examples/statemachine/tankgameplugins/tankgameplugins.pro @@ -0,0 +1,11 @@ +TEMPLATE = subdirs +SUBDIRS = random_ai \ + spin_ai_with_error \ + spin_ai \ + seek_ai + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS tankgameplugins.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins +INSTALLS += target sources diff --git a/examples/statemachine/trafficlight/main.cpp b/examples/statemachine/trafficlight/main.cpp index 3c47a51..8a46fff 100644 --- a/examples/statemachine/trafficlight/main.cpp +++ b/examples/statemachine/trafficlight/main.cpp @@ -87,27 +87,6 @@ private: //! [0] //! [1] -class LightState : public QState -{ -public: - LightState(LightWidget *light, int duration, QState *parent = 0) - : QState(parent) - { - QTimer *timer = new QTimer(this); - timer->setInterval(duration); - timer->setSingleShot(true); - QState *timing = new QState(this); - QObject::connect(timing, SIGNAL(entered()), light, SLOT(turnOn())); - QObject::connect(timing, SIGNAL(entered()), timer, SLOT(start())); - QObject::connect(timing, SIGNAL(exited()), light, SLOT(turnOff())); - QFinalState *done = new QFinalState(this); - timing->addTransition(timer, SIGNAL(timeout()), done); - setInitialState(timing); - } -}; -//! [1] - -//! [2] class TrafficLightWidget : public QWidget { public: @@ -139,6 +118,24 @@ private: LightWidget *m_yellow; LightWidget *m_green; }; +//! [1] + +//! [2] +QState *createLightState(LightWidget *light, int duration, QState *parent = 0) +{ + QState *lightState = new QState(parent); + QTimer *timer = new QTimer(lightState); + timer->setInterval(duration); + timer->setSingleShot(true); + QState *timing = new QState(lightState); + QObject::connect(timing, SIGNAL(entered()), light, SLOT(turnOn())); + QObject::connect(timing, SIGNAL(entered()), timer, SLOT(start())); + QObject::connect(timing, SIGNAL(exited()), light, SLOT(turnOff())); + QFinalState *done = new QFinalState(lightState); + timing->addTransition(timer, SIGNAL(timeout()), done); + lightState->setInitialState(timing); + return lightState; +} //! [2] //! [3] @@ -154,15 +151,15 @@ public: vbox->setMargin(0); QStateMachine *machine = new QStateMachine(this); - LightState *redGoingYellow = new LightState(widget->redLight(), 3000); + QState *redGoingYellow = createLightState(widget->redLight(), 3000); redGoingYellow->setObjectName("redGoingYellow"); - LightState *yellowGoingGreen = new LightState(widget->yellowLight(), 1000); + QState *yellowGoingGreen = createLightState(widget->yellowLight(), 1000); yellowGoingGreen->setObjectName("yellowGoingGreen"); redGoingYellow->addTransition(redGoingYellow, SIGNAL(finished()), yellowGoingGreen); - LightState *greenGoingYellow = new LightState(widget->greenLight(), 3000); + QState *greenGoingYellow = createLightState(widget->greenLight(), 3000); greenGoingYellow->setObjectName("greenGoingYellow"); yellowGoingGreen->addTransition(yellowGoingGreen, SIGNAL(finished()), greenGoingYellow); - LightState *yellowGoingRed = new LightState(widget->yellowLight(), 1000); + QState *yellowGoingRed = createLightState(widget->yellowLight(), 1000); yellowGoingRed->setObjectName("yellowGoingRed"); greenGoingYellow->addTransition(greenGoingYellow, SIGNAL(finished()), yellowGoingRed); yellowGoingRed->addTransition(yellowGoingRed, SIGNAL(finished()), redGoingYellow); diff --git a/examples/statemachine/twowaybutton/main.cpp b/examples/statemachine/twowaybutton/main.cpp index 61a0f32..a2c6e45 100644 --- a/examples/statemachine/twowaybutton/main.cpp +++ b/examples/statemachine/twowaybutton/main.cpp @@ -45,34 +45,42 @@ #include <qstatemachine.h> #endif +//! [0] int main(int argc, char **argv) { QApplication app(argc, argv); - QPushButton button; - QStateMachine machine; - QState *first = new QState(); - first->setObjectName("first"); +//! [0] +//! [1] QState *off = new QState(); off->assignProperty(&button, "text", "Off"); off->setObjectName("off"); - first->addTransition(off); QState *on = new QState(); on->setObjectName("on"); on->assignProperty(&button, "text", "On"); +//! [1] + +//! [2] off->addTransition(&button, SIGNAL(clicked()), on); on->addTransition(&button, SIGNAL(clicked()), off); +//! [2] - machine.addState(first); +//! [3] machine.addState(off); machine.addState(on); - machine.setInitialState(first); +//! [3] + +//! [4] + machine.setInitialState(off); machine.start(); +//! [4] +//! [5] button.resize(100, 50); button.show(); return app.exec(); } +//! [5] diff --git a/examples/tools/contiguouscache/contiguouscache.pro b/examples/tools/contiguouscache/contiguouscache.pro new file mode 100644 index 0000000..f840514 --- /dev/null +++ b/examples/tools/contiguouscache/contiguouscache.pro @@ -0,0 +1,9 @@ +HEADERS = randomlistmodel.h +SOURCES = randomlistmodel.cpp \ + main.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/tools/contiguouscache +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS contiguouscache.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/tools/contiguouscache +INSTALLS += target sources diff --git a/examples/tools/contiguouscache/main.cpp b/examples/tools/contiguouscache/main.cpp new file mode 100644 index 0000000..291aaf4 --- /dev/null +++ b/examples/tools/contiguouscache/main.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples 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 "randomlistmodel.h" +#include <QListView> +#include <QApplication> + +int main(int c, char **v) +{ + QApplication a(c, v); + + QListView view; + view.setUniformItemSizes(true); + view.setModel(new RandomListModel(&view)); + view.show(); + + return a.exec(); +} diff --git a/examples/statemachine/clockticking/main.cpp b/examples/tools/contiguouscache/randomlistmodel.cpp index ea8e692..b1c7204 100644 --- a/examples/statemachine/clockticking/main.cpp +++ b/examples/tools/contiguouscache/randomlistmodel.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -38,86 +38,60 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "randomlistmodel.h" +#include <stdlib.h> -#include <QtCore> -#include <stdio.h> -#ifdef QT_STATEMACHINE_SOLUTION -#include <qstatemachine.h> -#include <qstate.h> -#include <qabstracttransition.h> -#endif +static const int bufferSize(500); +static const int lookAhead(100); +static const int halfLookAhead(lookAhead/2); -class ClockEvent : public QEvent +RandomListModel::RandomListModel(QObject *parent) +: QAbstractListModel(parent), m_rows(bufferSize), m_count(10000) { -public: - ClockEvent() : QEvent(QEvent::Type(QEvent::User+2)) - {} -}; - -class ClockState : public QState -{ -public: - ClockState(QState *parent) - : QState(parent) {} - -protected: - virtual void onEntry(QEvent *) - { - fprintf(stdout, "ClockState entered; posting the initial tick\n"); - machine()->postEvent(new ClockEvent()); - } -}; +} -class ClockTransition : public QAbstractTransition +RandomListModel::~RandomListModel() { -public: - ClockTransition() {} - -protected: - virtual bool eventTest(QEvent *e) const { - return (e->type() == QEvent::User+2); - } - virtual void onTransition(QEvent *) - { - fprintf(stdout, "ClockTransition triggered; posting another tick with a delay of 1 second\n"); - machine()->postEvent(new ClockEvent(), 1000); - } -}; +} -class ClockListener : public QAbstractTransition +int RandomListModel::rowCount(const QModelIndex &) const { -public: - ClockListener() {} - -protected: - virtual bool eventTest(QEvent *e) const { - return (e->type() == QEvent::User+2); - } - virtual void onTransition(QEvent *) - { - fprintf(stdout, "ClockListener heard a tick!\n"); - } -}; + return m_count; +} -int main(int argc, char **argv) +//! [0] +QVariant RandomListModel::data(const QModelIndex &index, int role) const { - QCoreApplication app(argc, argv); + if (role != Qt::DisplayRole) + return QVariant(); - QStateMachine machine; - QState *group = new QState(QState::ParallelStates); - group->setObjectName("group"); + int row = index.row(); - ClockState *clock = new ClockState(group); - clock->setObjectName("clock"); - clock->addTransition(new ClockTransition()); + if (row > m_rows.lastIndex()) { + if (row - m_rows.lastIndex() > lookAhead) + cacheRows(row-halfLookAhead, qMin(m_count, row+halfLookAhead)); + else while (row > m_rows.lastIndex()) + m_rows.append(fetchRow(m_rows.lastIndex()+1)); + } else if (row < m_rows.firstIndex()) { + if (m_rows.firstIndex() - row > lookAhead) + cacheRows(qMax(0, row-halfLookAhead), row+halfLookAhead); + else while (row < m_rows.firstIndex()) + m_rows.prepend(fetchRow(m_rows.firstIndex()-1)); + } - QState *listener = new QState(group); - listener->setObjectName("listener"); - listener->addTransition(new ClockListener()); + return m_rows.at(row); +} - machine.addState(group); - machine.setInitialState(group); - machine.start(); +void RandomListModel::cacheRows(int from, int to) const +{ + for (int i = from; i <= to; ++i) + m_rows.insert(i, fetchRow(i)); +} +//![0] - return app.exec(); +//![1] +QString RandomListModel::fetchRow(int position) const +{ + return QString::number(rand() % ++position); } +//![1] diff --git a/examples/statemachine/helloworld/main.cpp b/examples/tools/contiguouscache/randomlistmodel.h index fbe34b5..d32bf16 100644 --- a/examples/statemachine/helloworld/main.cpp +++ b/examples/tools/contiguouscache/randomlistmodel.h @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -38,41 +38,29 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef RANDOMLISTMODEL_H +#define RANDOMLISTMODEL_H -#include <QtCore> -#ifdef QT_STATEMACHINE_SOLUTION -#include <qstatemachine.h> -#include <qstate.h> -#include <qfinalstate.h> -#endif +#include <QContiguousCache> +#include <QAbstractListModel> -class S0 : public QState +class QTimer; +class RandomListModel : public QAbstractListModel { + Q_OBJECT public: - S0(QState *parent = 0) - : QState(parent) {} - - virtual void onEntry(QEvent *) - { - fprintf(stdout, "Hello world!\n"); - } -}; + RandomListModel(QObject *parent = 0); + ~RandomListModel(); -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); + int rowCount(const QModelIndex & = QModelIndex()) const; + QVariant data(const QModelIndex &, int) const; - QStateMachine machine; - QState *s0 = new S0(); - QFinalState *s1 = new QFinalState(); - s0->addTransition(s1); +private: + void cacheRows(int, int) const; + QString fetchRow(int) const; - machine.addState(s0); - machine.addState(s1); - machine.setInitialState(s0); - - QObject::connect(&machine, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit())); - machine.start(); + mutable QContiguousCache<QString> m_rows; + const int m_count; +}; - return app.exec(); -} +#endif diff --git a/examples/tools/tools.pro b/examples/tools/tools.pro index 79f0faa..c694dd8 100644 --- a/examples/tools/tools.pro +++ b/examples/tools/tools.pro @@ -5,6 +5,7 @@ SUBDIRS = codecs \ customcompleter \ echoplugin \ i18n \ + contiguouscache \ plugandpaintplugins \ plugandpaint \ regexp \ diff --git a/examples/webkit/fancybrowser/mainwindow.cpp b/examples/webkit/fancybrowser/mainwindow.cpp index bf61f9c..e24f6cf 100644 --- a/examples/webkit/fancybrowser/mainwindow.cpp +++ b/examples/webkit/fancybrowser/mainwindow.cpp @@ -43,6 +43,8 @@ #include <QtWebKit> #include "mainwindow.h" +//! [1] + MainWindow::MainWindow() { progress = 0; @@ -52,7 +54,9 @@ MainWindow::MainWindow() file.open(QIODevice::ReadOnly); jQuery = file.readAll(); file.close(); +//! [1] +//! [2] view = new QWebView(this); view->load(QUrl("http://www.google.com/ncr")); connect(view, SIGNAL(loadFinished(bool)), SLOT(adjustLocation())); @@ -70,7 +74,9 @@ MainWindow::MainWindow() toolBar->addAction(view->pageAction(QWebPage::Reload)); toolBar->addAction(view->pageAction(QWebPage::Stop)); toolBar->addWidget(locationEdit); +//! [2] +//! [3] QMenu *effectMenu = menuBar()->addMenu(tr("&Effect")); effectMenu->addAction("Highlight all links", this, SLOT(highlightAllLinks())); @@ -89,7 +95,9 @@ MainWindow::MainWindow() setCentralWidget(view); } +//! [3] +//! [4] void MainWindow::adjustLocation() { locationEdit->setText(view->url().toString()); @@ -98,11 +106,12 @@ void MainWindow::adjustLocation() void MainWindow::changeLocation() { QUrl url = QUrl(locationEdit->text()); - locationEdit->setText(url.toString()); view->load(url); view->setFocus(); } +//! [4] +//! [5] void MainWindow::adjustTitle() { if (progress <= 0 || progress >= 100) @@ -116,20 +125,26 @@ void MainWindow::setProgress(int p) progress = p; adjustTitle(); } +//! [5] +//! [6] void MainWindow::finishLoading(bool) { progress = 100; adjustTitle(); view->page()->mainFrame()->evaluateJavaScript(jQuery); } +//! [6] +//! [7] void MainWindow::highlightAllLinks() { QString code = "$('a').each( function () { $(this).css('background-color', 'yellow') } )"; view->page()->mainFrame()->evaluateJavaScript(code); } +//! [7] +//! [8] void MainWindow::rotateImages(bool toggle) { QString code = "$('img').each( function () { $(this).css('-webkit-transition', '-webkit-transform 2s') } )"; @@ -140,7 +155,9 @@ void MainWindow::rotateImages(bool toggle) code = "$('img').each( function () { $(this).css('-webkit-transform', 'rotate(0deg)') } )"; view->page()->mainFrame()->evaluateJavaScript(code); } +//! [8] +//! [9] void MainWindow::removeGifImages() { QString code = "$('[src*=gif]').remove()"; @@ -164,4 +181,5 @@ void MainWindow::removeEmbeddedElements() QString code = "$('embed').remove()"; view->page()->mainFrame()->evaluateJavaScript(code); } +//! [9] diff --git a/examples/webkit/fancybrowser/mainwindow.h b/examples/webkit/fancybrowser/mainwindow.h index 9362ca7..2e1068c 100644 --- a/examples/webkit/fancybrowser/mainwindow.h +++ b/examples/webkit/fancybrowser/mainwindow.h @@ -39,13 +39,14 @@ ** ****************************************************************************/ -#include <QMainWindow> +#include <QtGui> QT_BEGIN_NAMESPACE class QWebView; class QLineEdit; QT_END_NAMESPACE +//! [1] class MainWindow : public QMainWindow { Q_OBJECT @@ -73,4 +74,5 @@ private: QWebView *view; QLineEdit *locationEdit; int progress; +//! [1] }; diff --git a/mkspecs/features/win32/ltcg.prf b/mkspecs/features/win32/ltcg.prf new file mode 100644 index 0000000..f6f1299 --- /dev/null +++ b/mkspecs/features/win32/ltcg.prf @@ -0,0 +1,5 @@ +CONFIG(release, debug|release) { + QMAKE_CFLAGS *= $$QMAKE_CFLAGS_LTCG + QMAKE_CXXFLAGS *= $$QMAKE_CXXFLAGS_LTCG + QMAKE_LFLAGS *= $$QMAKE_LFLAGS_LTCG +} diff --git a/mkspecs/win32-msvc2005/qmake.conf b/mkspecs/win32-msvc2005/qmake.conf index 00287cb..5ed8e01 100644 --- a/mkspecs/win32-msvc2005/qmake.conf +++ b/mkspecs/win32-msvc2005/qmake.conf @@ -19,9 +19,10 @@ QMAKE_YACCFLAGS = -d QMAKE_CFLAGS = -nologo -Zm200 -Zc:wchar_t- QMAKE_CFLAGS_WARN_ON = -W3 QMAKE_CFLAGS_WARN_OFF = -W0 -QMAKE_CFLAGS_RELEASE = -O2 -MD -GL +QMAKE_CFLAGS_RELEASE = -O2 -MD QMAKE_CFLAGS_DEBUG = -Zi -MDd QMAKE_CFLAGS_YACC = +QMAKE_CFLAGS_LTCG = -GL QMAKE_CXX = $$QMAKE_CC QMAKE_CXXFLAGS = $$QMAKE_CFLAGS @@ -30,6 +31,7 @@ QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC +QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG QMAKE_CXXFLAGS_STL_ON = -EHsc QMAKE_CXXFLAGS_STL_OFF = QMAKE_CXXFLAGS_RTTI_ON = -GR @@ -50,11 +52,12 @@ QMAKE_RUN_CXX_IMP_BATCH = $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ @<< QMAKE_LINK = link QMAKE_LFLAGS = /NOLOGO -QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO /LTCG +QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO QMAKE_LFLAGS_DEBUG = /DEBUG QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS \"/MANIFESTDEPENDENCY:type=\'win32\' name=\'Microsoft.Windows.Common-Controls\' version=\'6.0.0.0\' publicKeyToken=\'6595b64144ccf1df\' language=\'*\' processorArchitecture=\'*\'\" QMAKE_LFLAGS_DLL = /DLL +QMAKE_LFLAGS_LTCG = /LTCG QMAKE_LIBS_CORE = kernel32.lib user32.lib shell32.lib uuid.lib ole32.lib advapi32.lib ws2_32.lib QMAKE_LIBS_GUI = gdi32.lib comdlg32.lib oleaut32.lib imm32.lib winmm.lib winspool.lib ws2_32.lib ole32.lib user32.lib advapi32.lib diff --git a/mkspecs/win32-msvc2008/qmake.conf b/mkspecs/win32-msvc2008/qmake.conf index b56b41c..373a36d 100644 --- a/mkspecs/win32-msvc2008/qmake.conf +++ b/mkspecs/win32-msvc2008/qmake.conf @@ -19,9 +19,10 @@ QMAKE_YACCFLAGS = -d QMAKE_CFLAGS = -nologo -Zm200 -Zc:wchar_t- QMAKE_CFLAGS_WARN_ON = -W3 QMAKE_CFLAGS_WARN_OFF = -W0 -QMAKE_CFLAGS_RELEASE = -O2 -MD -GL +QMAKE_CFLAGS_RELEASE = -O2 -MD QMAKE_CFLAGS_DEBUG = -Zi -MDd QMAKE_CFLAGS_YACC = +QMAKE_CFLAGS_LTCG = -GL QMAKE_CXX = $$QMAKE_CC QMAKE_CXXFLAGS = $$QMAKE_CFLAGS @@ -30,6 +31,7 @@ QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC +QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG QMAKE_CXXFLAGS_STL_ON = -EHsc QMAKE_CXXFLAGS_STL_OFF = QMAKE_CXXFLAGS_RTTI_ON = -GR @@ -50,11 +52,12 @@ QMAKE_RUN_CXX_IMP_BATCH = $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ @<< QMAKE_LINK = link QMAKE_LFLAGS = /NOLOGO -QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO /LTCG +QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO QMAKE_LFLAGS_DEBUG = /DEBUG QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS \"/MANIFESTDEPENDENCY:type=\'win32\' name=\'Microsoft.Windows.Common-Controls\' version=\'6.0.0.0\' publicKeyToken=\'6595b64144ccf1df\' language=\'*\' processorArchitecture=\'*\'\" QMAKE_LFLAGS_DLL = /DLL +QMAKE_LFLAGS_LTCG = /LTCG QMAKE_LIBS_CORE = kernel32.lib user32.lib shell32.lib uuid.lib ole32.lib advapi32.lib ws2_32.lib QMAKE_LIBS_GUI = gdi32.lib comdlg32.lib oleaut32.lib imm32.lib winmm.lib winspool.lib ws2_32.lib ole32.lib user32.lib advapi32.lib diff --git a/mkspecs/wince50standard-mipsii-msvc2008/default_post.prf b/mkspecs/wince50standard-mipsii-msvc2008/default_post.prf index a232ba3..d423784 100644 --- a/mkspecs/wince50standard-mipsii-msvc2008/default_post.prf +++ b/mkspecs/wince50standard-mipsii-msvc2008/default_post.prf @@ -1 +1 @@ -include(../wince50standard-mipsii-msvc2005/qmake.conf) +include(../wince50standard-mipsii-msvc2005/default_post.prf) diff --git a/qmake/generators/xmloutput.cpp b/qmake/generators/xmloutput.cpp index 68d22e1..d77dd4b 100644 --- a/qmake/generators/xmloutput.cpp +++ b/qmake/generators/xmloutput.cpp @@ -277,7 +277,7 @@ void XmlOutput::closeTag() void XmlOutput::closeTo(const QString &tag) { bool cont = true; - if (!tagStack.contains(tag) && tag != QString()) { + if (!tagStack.contains(tag) && !tag.isNull()) { //warn_msg(WarnLogic, "<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().latin1(), tag.latin1()); qDebug("<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().toLatin1().constData(), tag.toLatin1().constData()); return; diff --git a/qmake/qmake.pri b/qmake/qmake.pri index 02ff38e..9147ee8 100644 --- a/qmake/qmake.pri +++ b/qmake/qmake.pri @@ -79,7 +79,6 @@ bootstrap { #Qt code qfile.h \ qabstractfileengine.h \ qfileinfo.h \ - qfileinfo_p.h \ qglobal.h \ qnumeric.h \ qhash.h \ diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp index 8c9f358..0745d39 100644 --- a/src/corelib/animation/qanimationgroup.cpp +++ b/src/corelib/animation/qanimationgroup.cpp @@ -41,23 +41,51 @@ /*! \class QAnimationGroup - \brief The QAnimationGroup class is an abstract base class for group of animations. + \brief The QAnimationGroup class is an abstract base class for groups of animations. \since 4.5 \ingroup group_animation \preliminary - QAnimationGroup represents a group of animations, such as parallel or sequential, - and lets you combine different animations into one. The group manages any animation - that inherits QAbstractAnimation. By combining groups, you can easily construct - complex animation graphs. - - The QAnimationGroup base class provides methods for adding and retrieving animations. - Besides that, you can remove animations by calling remove(), and clear the animation - group by calling clearAnimations(). You may keep track of changes in the group's animations by - listening to QEvent::ChildAdded and QEvent::ChildRemoved events. - - QAnimationGroup takes ownership of the animations it manages, and ensures that they are - deleted when the animation group is deleted. + An animation group is a container for animations (subclasses of + QAbstractAnimation). A group is usually responsible for managing + the \l{QAbstractAnimation::State}{state} of its animations, i.e., + it decides when to start, stop, resume, and pause them. Currently, + Qt provides two such groups: QParallelAnimationGroup and + QSequentialAnimationGroup. Look up their class descriptions for + details. + + Since QAnimationGroup inherits from QAbstractAnimation, you can + combine groups, and easily construct complex animation graphs. + You can query QAbstractAnimation for the group it belongs to + (using the \l{QAbstractAnimation::}{group()} function). + + To start a top-level animation group, you simply use the + \l{QAbstractAnimation::}{start()} function from + QAbstractAnimation. By a top-level animation group, we think of a + group that itself is not contained within another group. Starting + sub groups directly is not supported, and may lead to unexpected + behavior. + + \omit OK, we'll put in a snippet on this here \endomit + + QAnimationGroup provides methods for adding and retrieving + animations. Besides that, you can remove animations by calling + remove(), and clear the animation group by calling + clearAnimations(). You may keep track of changes in the group's + animations by listening to QEvent::ChildAdded and + QEvent::ChildRemoved events. + + \omit OK, let's find a snippet here as well. \endomit + + QAnimationGroup takes ownership of the animations it manages, and + ensures that they are deleted when the animation group is deleted. + + You can also use a \l{The State Machine Framework}{state machine} + to create complex animations. The framework provides a special + state, QAnimationState, that plays an animation upon entry and + transitions to a new state when the animation has finished + playing. This technique can also be combined with using animation + groups. \sa QAbstractAnimation, QVariantAnimation, {The Animation Framework} */ diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp index a75f85c..68dbb9e 100644 --- a/src/corelib/animation/qparallelanimationgroup.cpp +++ b/src/corelib/animation/qparallelanimationgroup.cpp @@ -46,8 +46,27 @@ \ingroup group_animation \preliminary - The animations are all started at the same time, and run in parallel. The animation group - finishes when the longest lasting animation has finished. + QParallelAnimationGroup--a \l{QAnimationGroup}{container for + animations}--starts all its animations when it is + \l{QAbstractAnimation::start()}{started} itself, i.e., runs all + animations in parallel. The animation group finishes when the + longest lasting animation has finished. + + You can treat QParallelAnimation as any other QAbstractAnimation, + e.g., pause, resume, or add it to other animation groups. + + \code + QParallelAnimationGroup *group = new QParallelAnimationGroup; + group->addAnimation(anim1); + group->addAnimation(anim2); + + group->start(); + \endcode + + In this example, \c anim1 and \c anim2 are two + \l{QPropertyAnimation}s that have already been set up. + + \sa QAnimationGroup, QPropertyAnimation, {The Animation Framework} */ #ifndef QT_NO_ANIMATION diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp index 86c3049..cf3bb3b 100644 --- a/src/corelib/animation/qpauseanimation.cpp +++ b/src/corelib/animation/qpauseanimation.cpp @@ -45,6 +45,22 @@ \since 4.5 \ingroup group_animation \preliminary + + If you wish to introduce a delay between animations in a + QSequentialAnimationGroup, you can insert a QPauseAnimation. This + class does not animate anything, but does not + \l{QAbstractAnimation::finished()}{finish} before a specified + number of milliseconds have elapsed from when it was started. You + specify the duration of the pause in the constructor. It can also + be set directly with setDuration(). + + It is not necessary to construct a QPauseAnimation yourself. + QSequentialAnimationGroup provides the convenience functions + \l{QSequentialAnimationGroup::}{addPause()} and + \l{QSequentialAnimationGroup::}{insertPauseAt()}. These functions + simply take the number of milliseconds the pause should last. + + \sa QSequentialAnimationGroup */ #ifndef QT_NO_ANIMATION diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index ed20e667..4bdffa4 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -48,14 +48,14 @@ QPropertyAnimation interpolates over \l{Qt's Property System}{Qt properties}. As property values are stored in \l{QVariant}s, the class inherits QVariantAnimation, and supports animation of the - same \l{QVariant::Type}{variant types} as its super class. + same \l{QVariant::Type}{variant types} as its super class. A class declaring properties must be a QObject. To make it possible to animate a property, it must provide a setter (so that QPropertyAnimation can set the property's value). Note that this makes it possible to animate many of Qt's widgets. Let's look at an example: - + \code QPropertyAnimation animation(myWidget, "geometry"); animation.setDuration(10000); diff --git a/src/corelib/animation/qpropertyanimation_p.h b/src/corelib/animation/qpropertyanimation_p.h index ed3666d..9d9dd31 100644 --- a/src/corelib/animation/qpropertyanimation_p.h +++ b/src/corelib/animation/qpropertyanimation_p.h @@ -70,7 +70,6 @@ public: { } - QPointer<QObject> target; //for the QProperty diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp index 45673c2..c610b4f 100644 --- a/src/corelib/animation/qsequentialanimationgroup.cpp +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -46,13 +46,36 @@ \ingroup group_animation \preliminary - The first animation in the group is started first, and when it finishes, the next animation - is started, and so on. The animation group finishes when the last animation has finished. + QSequentialAnimationGroup is a QAnimationGroup that runs its + animations in sequence, i.e., it starts one animation after + another has finished playing. The animations are played in the + order they are added to the group (using + \l{QAnimationGroup::}{addAnimation()} or + \l{QAnimationGroup::}{insertAnimationAt()}). The animation group + finishes when its last animation has finished. - At each moment there is at most one animation that is active in the group, called currentAnimation. - An empty group has no current animation. + At each moment there is at most one animation that is active in + the group; it is returned by currentAnimation(). An empty group + has no current animation. - You can call addPause() or insertPause() to add a pause to a sequential animation group. + A sequential animation group can be treated as any other + animation, i.e., it can be started, stopped, and added to other + groups. You can also call addPause() or insertPauseAt() to add a + pause to a sequential animation group. + + \code + QSequentialAnimationGroup group; + + group.addAnimation(anim1); + group.addAnimation(anim2); + + group.start(); + \endcode + + In this example, \c anim1 and \c anim2 are two already set up + \l{QPropertyAnimation}s. + + \sa QAnimationGroup, QAbstractAnimation, {The Animation Framework} */ #ifndef QT_NO_ANIMATION diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index 331024e..e27cde8 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -64,13 +64,15 @@ QT_BEGIN_NAMESPACE shared functionality. QVariantAnimation cannot be used directly as it is an abstract - class; it does not implement \l{updateCurrentValue()}. The class - performs interpolation over \l{QVariant}s, but leaves using the - interpolated values to its subclasses. Currently, Qt provides - QPropertyAnimation, which animates Qt \l{Qt's Property System} - {properties}. See the QPropertyAnimation class description if you - wish to animate such properties. - + class; it does not implement + \l{QAbstractAnimation::}{updateCurrentValue()} from + QAbstractAnimation. The class performs interpolation over + \l{QVariant}s, but leaves using the interpolated values to its + subclasses. Currently, Qt provides QPropertyAnimation, which + animates Qt \l{Qt's Property System}{properties}. See the + QPropertyAnimation class description if you wish to animate such + properties. + You can then set start and end values for the property by calling setStartValue() and setEndValue(), and finally call start() to start the animation. QVariantAnimation will interpolate the @@ -109,12 +111,12 @@ QT_BEGIN_NAMESPACE \o \l{QMetaType::}{QSizeF} \o \l{QMetaType::}{QRect} \o \l{QMetaType::}{QRectF} - \endlist + \endlist If you need to interpolate other variant types, including custom types, you have to implement interpolation for these yourself. You do this by reimplementing interpolated(), which returns - interpolation values for the value being interpolated. + interpolation values for the value being interpolated. \omit We need some snippets around here. \endomit @@ -150,7 +152,7 @@ template<> Q_INLINE_TEMPLATE QRectF _q_interpolate(const QRectF &f, const QRectF f.getRect(&x1, &y1, &w1, &h1); qreal x2, y2, w2, h2; t.getRect(&x2, &y2, &w2, &h2); - return QRectF( _q_interpolate(x1, x2, progress), _q_interpolate(y1, y2, progress), + return QRectF(_q_interpolate(x1, x2, progress), _q_interpolate(y1, y2, progress), _q_interpolate(w1, w2, progress), _q_interpolate(h1, h2, progress)); } @@ -172,47 +174,61 @@ void QVariantAnimationPrivate::convertValues(int t) if (pair.second.userType() != t) pair.second.convert(static_cast<QVariant::Type>(t)); } - currentInterval.start.first = 2; // this will force the refresh - interpolator = 0; // if the type changed we need to update the interpolator + interpolator = 0; // if the type changed we need to update the interpolator } /*! - \fn void QVariantAnimation::updateCurrentValue(const QVariant &value) = 0; - This pure virtual function is called when the animated value is changed. - \a value is the new value. + \internal + The goal of this function is to update the currentInterval member. As a consequence, we also + need to update the currentValue. + Set \a force to true to always recalculate the interval. */ - -void QVariantAnimationPrivate::updateCurrentValue() +void QVariantAnimationPrivate::recalculateCurrentInterval(bool force/*=false*/) { - Q_Q(QVariantAnimation); + // can't interpolate if we have only 1 key value + if (keyValues.count() <= 1) + return; + const qreal progress = easing.valueForProgress(((duration == 0) ? qreal(1) : qreal(currentTime) / qreal(duration))); - if (progress < currentInterval.start.first || progress > currentInterval.end.first) { + if (force || progress < currentInterval.start.first || progress > currentInterval.end.first) { //let's update currentInterval - QVariantAnimation::KeyValues::const_iterator itStart = qLowerBound(keyValues.constBegin(), keyValues.constEnd(), qMakePair(progress, QVariant()), animationValueLessThan); + QVariantAnimation::KeyValues::const_iterator itStart = qLowerBound(keyValues.constBegin(), + keyValues.constEnd(), + qMakePair(progress, QVariant()), + animationValueLessThan); QVariantAnimation::KeyValues::const_iterator itEnd = itStart; // If we are at the end we should continue to use the last keyValues in case of extrapolation (progress > 1.0). // This is because the easing function can return a value slightly outside the range [0, 1] if (itStart != keyValues.constEnd()) { - - //this can't happen because we always prepend the default start value there - if (itStart == keyValues.begin()) { + // this can't happen because we always prepend the default start value there + if (itStart == keyValues.constBegin()) { ++itEnd; - if (itEnd == keyValues.constEnd()) - return; //there is no upper bound } else { --itStart; } - //update all the values of the currentInterval + // update all the values of the currentInterval currentInterval.start = *itStart; currentInterval.end = *itEnd; } } + setCurrentValueForProgress(progress); +} + +void QVariantAnimationPrivate::setCurrentValue() +{ + const qreal progress = easing.valueForProgress(((duration == 0) ? qreal(1) : qreal(currentTime) / qreal(duration))); + setCurrentValueForProgress(progress); +} - const qreal startProgress = currentInterval.start.first, - endProgress = currentInterval.end.first; +void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress) +{ + Q_Q(QVariantAnimation); + + const qreal startProgress = currentInterval.start.first; + const qreal endProgress = currentInterval.end.first; const qreal localProgress = (progress - startProgress) / (endProgress - startProgress); QVariant ret = q->interpolated(currentInterval.start.second, @@ -225,11 +241,10 @@ void QVariantAnimationPrivate::updateCurrentValue() #endif if (currentValue != ret) { //the value has changed - emit q->valueChanged(currentValue); + emit q->valueChanged(currentValue); } } - QVariant QVariantAnimationPrivate::valueAt(qreal step) const { QVariantAnimation::KeyValues::const_iterator result = @@ -240,7 +255,6 @@ QVariant QVariantAnimationPrivate::valueAt(qreal step) const return QVariant(); } - void QVariantAnimationPrivate::setValueAt(qreal step, const QVariant &value) { if (step < qreal(0.0) || step > qreal(1.0)) { @@ -255,15 +269,14 @@ void QVariantAnimationPrivate::setValueAt(qreal step, const QVariant &value) keyValues.insert(result, pair); } else { if (value.isValid()) - result->second = value; //remove the previous value + result->second = value; // replaces the previous value else if (step == 0 && !hasStartValue && defaultStartValue.isValid()) - result->second = defaultStartValue; //we reset to the default start value + result->second = defaultStartValue; // resets to the default start value else - keyValues.erase(result); //replace the previous value + keyValues.erase(result); // removes the previous value } - currentInterval.start.first = 2; // this will force the refresh - updateCurrentValue(); + recalculateCurrentInterval(/*force=*/true); } void QVariantAnimationPrivate::setDefaultStartValue(const QVariant &value) @@ -322,7 +335,7 @@ void QVariantAnimation::setEasingCurve(const QEasingCurve &easing) { Q_D(QVariantAnimation); d->easing = easing; - d->updateCurrentValue(); + d->recalculateCurrentInterval(); } Q_GLOBAL_STATIC(QVector<QVariantAnimation::Interpolator>, registeredInterpolators) @@ -433,7 +446,7 @@ void QVariantAnimation::setDuration(int msecs) if (d->duration == msecs) return; d->duration = msecs; - d->updateCurrentValue(); + d->recalculateCurrentInterval(); } /*! @@ -543,8 +556,8 @@ void QVariantAnimation::setKeyValues(const KeyValues &keyValues) Q_D(QVariantAnimation); d->keyValues = keyValues; qSort(d->keyValues.begin(), d->keyValues.end(), animationValueLessThan); - d->currentInterval.start.first = 2; // this will force the refresh d->hasStartValue = !d->keyValues.isEmpty() && d->keyValues.at(0).first == 0; + d->recalculateCurrentInterval(/*force=*/true); } /*! @@ -569,7 +582,7 @@ QVariant QVariantAnimation::currentValue() const { Q_D(const QVariantAnimation); if (!d->currentValue.isValid()) - const_cast<QVariantAnimationPrivate*>(d)->updateCurrentValue(); + const_cast<QVariantAnimationPrivate*>(d)->recalculateCurrentInterval(); return d->currentValue; } @@ -585,12 +598,10 @@ bool QVariantAnimation::event(QEvent *event) \reimp */ void QVariantAnimation::updateState(QAbstractAnimation::State oldState, - QAbstractAnimation::State newState) + QAbstractAnimation::State newState) { Q_UNUSED(oldState); Q_UNUSED(newState); - Q_D(QVariantAnimation); - d->currentValue = QVariant(); // this will force the refresh } /*! @@ -633,7 +644,7 @@ void QVariantAnimation::updateCurrentTime(int msecs) { Q_D(QVariantAnimation); Q_UNUSED(msecs); - d->updateCurrentValue(); + d->recalculateCurrentInterval(); } QT_END_NAMESPACE diff --git a/src/corelib/animation/qvariantanimation_p.h b/src/corelib/animation/qvariantanimation_p.h index 14a3ef6..9e81649 100644 --- a/src/corelib/animation/qvariantanimation_p.h +++ b/src/corelib/animation/qvariantanimation_p.h @@ -108,7 +108,9 @@ public: quint32 changedSignalMask; - void updateCurrentValue(); + void setCurrentValue(); + void setCurrentValueForProgress(const qreal progress); + void recalculateCurrentInterval(bool force=false); void setValueAt(qreal, const QVariant &); QVariant valueAt(qreal step) const; void convertValues(int t); diff --git a/src/corelib/arch/qatomic_mips.h b/src/corelib/arch/qatomic_mips.h index b263aab..ea9954b 100644 --- a/src/corelib/arch/qatomic_mips.h +++ b/src/corelib/arch/qatomic_mips.h @@ -103,16 +103,25 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() #if defined(Q_CC_GNU) && !defined(Q_OS_IRIX) +#if _MIPS_SIM == _ABIO32 +#define SET_MIPS2 ".set mips2\n\t" +#else +#define SET_MIPS2 +#endif + inline bool QBasicAtomicInt::ref() { register int originalValue; register int newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "addiu %[newValue], %[originalValue], %[one]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -125,12 +134,15 @@ inline bool QBasicAtomicInt::deref() { register int originalValue; register int newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "addiu %[newValue], %[originalValue], %[minusOne]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -143,7 +155,9 @@ inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) { register int result; register int tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" "bnez %[result], 0f\n" @@ -153,6 +167,7 @@ inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) "beqz %[tempValue], 0b\n" "nop\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -166,7 +181,9 @@ inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) { register int result; register int tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" "bnez %[result], 0f\n" @@ -177,6 +194,7 @@ inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) "nop\n" "sync\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -190,7 +208,9 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) { register int result; register int tempValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" "ll %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" @@ -201,6 +221,7 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) "beqz %[tempValue], 0b\n" "nop\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -219,12 +240,15 @@ inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) { register int originalValue; register int tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" "sc %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -237,13 +261,16 @@ inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) { register int originalValue; register int tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" "sc %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" "sync\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -256,13 +283,16 @@ inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) { register int originalValue; register int tempValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" "ll %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" "sc %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -280,12 +310,15 @@ inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) { register int originalValue; register int newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -298,13 +331,16 @@ inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) { register int originalValue; register int newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" "ll %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" "sync\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -317,13 +353,16 @@ inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) { register int originalValue; register int newValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" "ll %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" "sc %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -350,7 +389,9 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValu { register T *result; register T *tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" "bnez %[result], 0f\n" @@ -360,6 +401,7 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValu "beqz %[tempValue], 0b\n" "nop\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -374,7 +416,9 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValu { register T *result; register T *tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" "bnez %[result], 0f\n" @@ -385,6 +429,7 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValu "nop\n" "sync\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -399,7 +444,9 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValu { register T *result; register T *tempValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" LLP" %[result], %[_q_value]\n" "xor %[result], %[result], %[expectedValue]\n" @@ -410,6 +457,7 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValu "beqz %[tempValue], 0b\n" "nop\n" "0:\n" + ".set pop\n" : [result] "=&r" (result), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -430,12 +478,15 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue) { register T *originalValue; register T *tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" SCP" %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -449,13 +500,16 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue) { register T *originalValue; register T *tempValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" SCP" %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" "sync\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -469,13 +523,16 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue) { register T *originalValue; register T *tempValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" LLP" %[originalValue], %[_q_value]\n" "move %[tempValue], %[newValue]\n" SCP" %[tempValue], %[_q_value]\n" "beqz %[tempValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [tempValue] "=&r" (tempValue), [_q_value] "+m" (_q_value) @@ -495,12 +552,15 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueTo { register T *originalValue; register T *newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" SCP" %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -514,13 +574,16 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueTo { register T *originalValue; register T *newValue; - asm volatile("0:\n" + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" LLP" %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" SCP" %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" "sync\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) @@ -534,13 +597,16 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueTo { register T *originalValue; register T *newValue; - asm volatile("sync\n" + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" "0:\n" LLP" %[originalValue], %[_q_value]\n" "addu %[newValue], %[originalValue], %[valueToAdd]\n" SCP" %[newValue], %[_q_value]\n" "beqz %[newValue], 0b\n" "nop\n" + ".set pop\n" : [originalValue] "=&r" (originalValue), [_q_value] "+m" (_q_value), [newValue] "=&r" (newValue) diff --git a/src/corelib/concurrent/qfuturewatcher.cpp b/src/corelib/concurrent/qfuturewatcher.cpp index ea35e9e..39d7698 100644 --- a/src/corelib/concurrent/qfuturewatcher.cpp +++ b/src/corelib/concurrent/qfuturewatcher.cpp @@ -465,7 +465,7 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event) break; emit q->progressValueChanged(event->index1); - if (event->text != QString()) // ### + if (!event->text.isNull()) // ### q->progressTextChanged(event->text); break; case QFutureCallOutEvent::ProgressRange: diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 3690d4b..8f37e25 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -10,9 +10,9 @@ HEADERS += \ io/qdiriterator.h \ io/qfile.h \ io/qfileinfo.h \ - io/qfileinfo_p.h \ io/qiodevice.h \ io/qiodevice_p.h \ + io/qnoncontiguousbytedevice_p.h \ io/qprocess.h \ io/qprocess_p.h \ io/qtextstream.h \ @@ -38,6 +38,7 @@ SOURCES += \ io/qfile.cpp \ io/qfileinfo.cpp \ io/qiodevice.cpp \ + io/qnoncontiguousbytedevice.cpp \ io/qprocess.cpp \ io/qtextstream.cpp \ io/qtemporaryfile.cpp \ diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 8334146..9b0fbe5 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -51,6 +51,7 @@ #include <QtCore/qstring.h> #include <QtCore/qvector.h> #include <QtCore/qset.h> +#include <QtCore/qcontiguouscache.h> QT_BEGIN_HEADER @@ -232,6 +233,24 @@ inline QDebug operator<<(QDebug debug, const QSet<T> &set) return operator<<(debug, set.toList()); } +#if defined(FORCE_UREF) +template <class T> +inline QDebug &operator<<(QDebug debug, const QContiguousCache<T> &cache) +#else +template <class T> +inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache) +#endif +{ + debug.nospace() << "QContiguousCache("; + for (int i = cache.firstIndex(); i <= cache.lastIndex(); ++i) { + debug << cache[i]; + if (i != cache.lastIndex()) + debug << ", "; + } + debug << ")"; + return debug.space(); +} + #if !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); } diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h deleted file mode 100644 index 7d66581..0000000 --- a/src/corelib/io/qfileinfo_p.h +++ /dev/null @@ -1,145 +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 QtCore 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 QFILEINFO_P_H -#define QFILEINFO_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of QIODevice. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qfileinfo.h" - -QT_BEGIN_NAMESPACE - -class QFileInfoPrivate -{ -public: - QFileInfoPrivate(const QFileInfo *copy=0); - ~QFileInfoPrivate(); - - void initFileEngine(const QString &); - - enum Access { - ReadAccess, - WriteAccess, - ExecuteAccess - }; - bool hasAccess(Access access) const; - - uint getFileFlags(QAbstractFileEngine::FileFlags) const; - QDateTime &getFileTime(QAbstractFileEngine::FileTime) const; - QString getFileName(QAbstractFileEngine::FileName) const; - - enum { - CachedFileFlags = 0x01, - CachedLinkTypeFlag = 0x02, - CachedBundleTypeFlag= 0x04, - CachedMTime = 0x10, - CachedCTime = 0x20, - CachedATime = 0x40, - CachedSize = 0x08 - }; - - struct Data - { - inline Data() - : ref(1), fileEngine(0), cache_enabled(1) - { - clear(); - } - - inline Data(const Data ©) - : ref(1), fileEngine(QAbstractFileEngine::create(copy.fileName)), - fileName(copy.fileName), cache_enabled(copy.cache_enabled) - { - clear(); - } - - inline ~Data() - { - delete fileEngine; - } - - inline void clear() - { - fileNames.clear(); - fileFlags = 0; - cachedFlags = 0; - } - - mutable QAtomicInt ref; - - QAbstractFileEngine *fileEngine; - mutable QString fileName; - mutable QHash<int, QString> fileNames; - mutable uint cachedFlags : 31; - mutable uint cache_enabled : 1; - mutable uint fileFlags; - mutable qint64 fileSize; - mutable QDateTime fileTimes[3]; - - inline bool getCachedFlag(uint c) const - { return cache_enabled ? (cachedFlags & c) : 0; } - - inline void setCachedFlag(uint c) - { if (cache_enabled) cachedFlags |= c; } - } *data; - - inline void reset() { - detach(); - data->clear(); - } - - void detach(); -}; - - -QT_END_NAMESPACE -#endif - diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 8a0a3f5..7a6a85b 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -780,7 +780,7 @@ QString QFSFileEngine::fileName(FileName file) const #endif if (len > 0) { QString ret; - if (S_ISDIR(d->st.st_mode) && s[0] != '/') { + if (d->doStat() && S_ISDIR(d->st.st_mode) && s[0] != '/') { QDir parent(d->filePath); parent.cdUp(); ret = parent.path(); diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp new file mode 100644 index 0000000..6233fde --- /dev/null +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -0,0 +1,542 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 "qnoncontiguousbytedevice_p.h" +#include <QObject> +#include <QBuffer> +#include <QDebug> +#include <QFile> + +QT_BEGIN_NAMESPACE + +/*! + \class QNonContiguousByteDevice + \brief A QNonContiguousByteDevice is a representation of a + file, array or buffer that allows access with a read pointer. + \since 4.6 + + \inmodule QtCore + + The goal of this class is to have a data representation that + allows us to avoid doing a memcpy as we have to do with QIODevice. + + \sa QNonContiguousByteDeviceFactory + + \internal +*/ +/*! + \fn virtual const char* QNonContiguousByteDevice::readPointer(qint64 maximumLength, qint64 &len) + + Return a byte pointer for at most \a maximumLength bytes of that device. + if \a maximumLength is -1, the caller does not care about the length and + the device may return what it desires to. + The actual number of bytes the pointer is valid for is returned in + the \a len variable. + \a len will be -1 if EOF or an error occurs. + If it was really EOF can then afterwards be checked with atEnd() + Returns 0 if it is not possible to read at that position. + + \sa atEnd() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::advanceReadPointer(qint64 amount) + + will advance the internal read pointer by \a amount bytes. + The old readPointer is invalid after this call. + + \sa readPointer() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::atEnd() + + Returns true if everything has been read and the read + pointer cannot be advanced anymore. + + \sa readPointer(), advanceReadPointer(), reset() + + \internal +*/ +/*! + \fn virtual bool QNonContiguousByteDevice::reset() + + Moves the internal read pointer back to the beginning. + Returns false if this was not possible. + + \sa atEnd(), disableReset() + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::disableReset() + + Disable the reset() call, e.g. it will always + do nothing and return false. + + \sa reset() + + \internal +*/ +/*! + \fn virtual qint64 QNonContiguousByteDevice::size() + + Returns the size of the complete device or -1 if unknown. + May also return less/more than what can be actually read with readPointer() + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::readyRead() + + Emitted when there is data available + + \internal +*/ +/*! + \fn void QNonContiguousByteDevice::readProgress(qint64 current, qint64 total) + + Emitted when data has been "read" by advancing the read pointer + + \internal +*/ + +QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0), resetDisabled(false) +{ +}; + +QNonContiguousByteDevice::~QNonContiguousByteDevice() +{ +}; + +void QNonContiguousByteDevice::disableReset() +{ + resetDisabled = true; +} + +QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice() +{ + buffer = b; + byteArray = QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(), buffer->size() - buffer->pos()); + arrayImpl = new QNonContiguousByteDeviceByteArrayImpl(&byteArray); + arrayImpl->setParent(this); + connect(arrayImpl, SIGNAL(readyRead()), SIGNAL(readyRead())); + connect(arrayImpl, SIGNAL(readProgress(qint64,qint64)), SIGNAL(readProgress(qint64,qint64))); +} + +QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl() +{ +} + +const char* QNonContiguousByteDeviceBufferImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + return arrayImpl->readPointer(maximumLength, len); +} + +bool QNonContiguousByteDeviceBufferImpl::advanceReadPointer(qint64 amount) +{ + return arrayImpl->advanceReadPointer(amount); +} + +bool QNonContiguousByteDeviceBufferImpl::atEnd() +{ + return arrayImpl->atEnd(); +} + +bool QNonContiguousByteDeviceBufferImpl::reset() +{ + if (resetDisabled) + return false; + return arrayImpl->reset(); +} + +qint64 QNonContiguousByteDeviceBufferImpl::size() +{ + return arrayImpl->size(); +} + +QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0) +{ + byteArray = ba; +} + +QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl() +{ +} + +const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (atEnd()) { + len = -1; + return 0; + } + + if (maximumLength != -1) + len = qMin(maximumLength, size() - currentPosition); + else + len = size() - currentPosition; + + return byteArray->constData() + currentPosition; +} + +bool QNonContiguousByteDeviceByteArrayImpl::advanceReadPointer(qint64 amount) +{ + currentPosition += amount; + emit readProgress(currentPosition, size()); + return true; +} + +bool QNonContiguousByteDeviceByteArrayImpl::atEnd() +{ + return currentPosition >= size(); +} + +bool QNonContiguousByteDeviceByteArrayImpl::reset() +{ + if (resetDisabled) + return false; + + currentPosition = 0; + return true; +} + +qint64 QNonContiguousByteDeviceByteArrayImpl::size() +{ + return byteArray->size(); +} + +QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb) + : QNonContiguousByteDevice(), currentPosition(0) +{ + ringBuffer = rb; +} + +QNonContiguousByteDeviceRingBufferImpl::~QNonContiguousByteDeviceRingBufferImpl() +{ +}; + +const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (atEnd()) { + len = -1; + return 0; + } + + const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len); + + if (maximumLength != -1) + len = qMin(len, maximumLength); + + return returnValue; +}; + +bool QNonContiguousByteDeviceRingBufferImpl::advanceReadPointer(qint64 amount) +{ + currentPosition += amount; + emit readProgress(currentPosition, size()); + return true; +}; + +bool QNonContiguousByteDeviceRingBufferImpl::atEnd() +{ + return currentPosition >= size(); +}; + +bool QNonContiguousByteDeviceRingBufferImpl::reset() +{ + if (resetDisabled) + return false; + + currentPosition = 0; + return true; +}; + +qint64 QNonContiguousByteDeviceRingBufferImpl::size() +{ + return ringBuffer->size(); +}; + +QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d) + : QNonContiguousByteDevice(), + currentReadBuffer(0), currentReadBufferSize(16*1024), + currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0), + eof(false) +{ + device = d; + initialPosition = d->pos(); + connect(device, SIGNAL(readyRead()), this, SIGNAL(readyRead()), Qt::QueuedConnection); + connect(device, SIGNAL(readChannelFinished()), this, SIGNAL(readyRead()), Qt::QueuedConnection); +}; + +QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl() +{ + delete currentReadBuffer; +}; + +const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len) +{ + if (eof == true) { + len = -1; + return 0; + } + + if (currentReadBuffer == 0) + currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc + + if (maximumLength == -1) + maximumLength = currentReadBufferSize; + + if (currentReadBufferAmount - currentReadBufferPosition > 0) { + len = currentReadBufferAmount - currentReadBufferPosition; + return currentReadBuffer->data() + currentReadBufferPosition; + } + + qint64 haveRead = device->read(currentReadBuffer->data(), qMin(maximumLength, currentReadBufferSize)); + + if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) { + eof = true; + len = -1; + // size was unknown before, emit a readProgress with the final size + if (size() == -1) + emit readProgress(totalAdvancements, totalAdvancements); + return 0; + } + + currentReadBufferAmount = haveRead; + currentReadBufferPosition = 0; + + len = haveRead; + return currentReadBuffer->data(); +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount) +{ + totalAdvancements += amount; + + // normal advancement + currentReadBufferPosition += amount; + + // advancing over that what has actually been read before + if (currentReadBufferPosition > currentReadBufferAmount) { + qint64 i = currentReadBufferPosition - currentReadBufferAmount; + while (i > 0) { + if (device->getChar(0) == false) { + emit readProgress(totalAdvancements - i, size()); + return false; // ### FIXME handle eof + } + i--; + } + + currentReadBufferPosition = 0; + currentReadBufferAmount = 0; + } + + if (size() == -1) + emit readProgress(totalAdvancements, totalAdvancements); + else + emit readProgress(totalAdvancements, size()); + + return true; +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::atEnd() +{ + return eof == true; +}; + +bool QNonContiguousByteDeviceIoDeviceImpl::reset() +{ + if (resetDisabled) + return false; + + if (device->seek(initialPosition)) { + eof = false; // assume eof is false, it will be true after a read has been attempted + return true; + } + + return false; +}; + +qint64 QNonContiguousByteDeviceIoDeviceImpl::size() +{ + // note that this is different from the size() implementation of QIODevice! + + if (device->isSequential()) + return -1; + + return device->size() - initialPosition; +}; + +QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) +{ + byteDevice = bd; + connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead())); + + open(ReadOnly); +} + +QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice() +{ + +} + +bool QByteDeviceWrappingIoDevice::isSequential() const +{ + return (byteDevice->size() == -1); +} + +bool QByteDeviceWrappingIoDevice::atEnd() const +{ + return byteDevice->atEnd(); +} + +bool QByteDeviceWrappingIoDevice::reset() +{ + return byteDevice->reset(); +} + +qint64 QByteDeviceWrappingIoDevice::size() const +{ + if (isSequential()) + return 0; + + return byteDevice->size(); +} + + +qint64 QByteDeviceWrappingIoDevice::readData( char * data, qint64 maxSize) +{ + qint64 len; + const char *readPointer = byteDevice->readPointer(maxSize, len); + if (len == -1) + return -1; + + memcpy(data, readPointer, len); + byteDevice->advanceReadPointer(len); + return len; +} + +qint64 QByteDeviceWrappingIoDevice::writeData( const char* data, qint64 maxSize) +{ + return -1; +} + +/*! + \class QNonContiguousByteDeviceFactory + \since 4.6 + + \inmodule QtCore + + Creates a QNonContiguousByteDevice out of a QIODevice, + QByteArray etc. + + \sa QNonContiguousByteDevice + + \internal +*/ + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device); + + Create a QNonContiguousByteDevice out of a QIODevice. + For QFile, QBuffer and all other QIoDevice, sequential or not. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *device) +{ + // shortcut if it is a QBuffer + if (QBuffer* buffer = qobject_cast<QBuffer*>(device)) { + return new QNonContiguousByteDeviceBufferImpl(buffer); + } + + // ### FIXME special case if device is a QFile that supports map() + // then we can actually deal with the file without using read/peek + + // generic QIODevice + return new QNonContiguousByteDeviceIoDeviceImpl(device); // FIXME +}; + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer); + + Create a QNonContiguousByteDevice out of a QRingBuffer. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer) +{ + return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer); +}; + +/*! + \fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray); + + Create a QNonContiguousByteDevice out of a QByteArray. + + \internal +*/ +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray) +{ + return new QNonContiguousByteDeviceByteArrayImpl(byteArray); +}; + +/*! + \fn static QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice); + + Wrap the \a byteDevice (possibly again) into a QIODevice. + + \internal +*/ +QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice) +{ + // ### FIXME if it already has been based on QIoDevice, we could that one out again + // and save some calling + + // needed for FTP backend + + return new QByteDeviceWrappingIoDevice(byteDevice); +} + +QT_END_NAMESPACE + diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h new file mode 100644 index 0000000..2a7e40b --- /dev/null +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 QNONCONTIGUOUSBYTEDEVICE_H +#define QNONCONTIGUOUSBYTEDEVICE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QObject> +#include <QtCore/qbytearray.h> +#include <QtCore/qbuffer.h> +#include <QtCore/qiodevice.h> +#include "private/qringbuffer_p.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QNonContiguousByteDevice : public QObject +{ + Q_OBJECT +public: + virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0; + virtual bool advanceReadPointer(qint64 amount) = 0; + virtual bool atEnd() = 0; + virtual bool reset() = 0; + void disableReset(); + virtual qint64 size() = 0; + +protected: + QNonContiguousByteDevice(); + virtual ~QNonContiguousByteDevice(); + + bool resetDisabled; +signals: + void readyRead(); + void readProgress(qint64 current, qint64 total); +}; + +class Q_CORE_EXPORT QNonContiguousByteDeviceFactory +{ +public: + static QNonContiguousByteDevice* create(QIODevice *device); + static QNonContiguousByteDevice* create(QByteArray *byteArray); + static QNonContiguousByteDevice* create(QRingBuffer *ringBuffer); + static QIODevice* wrap(QNonContiguousByteDevice* byteDevice); +}; + +// the actual implementations +// + +class QNonContiguousByteDeviceByteArrayImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba); + ~QNonContiguousByteDeviceByteArrayImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QByteArray* byteArray; + qint64 currentPosition; +}; + +class QNonContiguousByteDeviceRingBufferImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb); + ~QNonContiguousByteDeviceRingBufferImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QRingBuffer* ringBuffer; + qint64 currentPosition; +}; + + +class QNonContiguousByteDeviceIoDeviceImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d); + ~QNonContiguousByteDeviceIoDeviceImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QIODevice* device; + QByteArray* currentReadBuffer; + qint64 currentReadBufferSize; + qint64 currentReadBufferAmount; + qint64 currentReadBufferPosition; + qint64 totalAdvancements; + bool eof; + qint64 initialPosition; +}; + +class QNonContiguousByteDeviceBufferImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +public: + QNonContiguousByteDeviceBufferImpl(QBuffer *b); + ~QNonContiguousByteDeviceBufferImpl(); + const char* readPointer(qint64 maximumLength, qint64 &len); + bool advanceReadPointer(qint64 amount); + bool atEnd(); + bool reset(); + qint64 size(); +protected: + QBuffer* buffer; + QByteArray byteArray; + QNonContiguousByteDeviceByteArrayImpl* arrayImpl; +}; + +// ... and the reverse thing +class QByteDeviceWrappingIoDevice : public QIODevice +{ + Q_OBJECT +public: + QByteDeviceWrappingIoDevice (QNonContiguousByteDevice *bd); + ~QByteDeviceWrappingIoDevice (); + virtual bool isSequential () const; + virtual bool atEnd () const; + virtual bool reset (); + virtual qint64 size () const; +protected: + virtual qint64 readData ( char * data, qint64 maxSize ); + virtual qint64 writeData ( const char * data, qint64 maxSize ); + + QNonContiguousByteDevice *byteDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index c21cf87..77ef096 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1710,7 +1710,7 @@ QString QCoreApplication::applicationDirPath() } QCoreApplicationPrivate *d = self->d_func(); - if (d->cachedApplicationDirPath == QString()) + if (d->cachedApplicationDirPath.isNull()) d->cachedApplicationDirPath = QFileInfo(applicationFilePath()).path(); return d->cachedApplicationDirPath; } @@ -1738,7 +1738,7 @@ QString QCoreApplication::applicationFilePath() } QCoreApplicationPrivate *d = self->d_func(); - if (d->cachedApplicationFilePath != QString()) + if (!d->cachedApplicationFilePath.isNull()) return d->cachedApplicationFilePath; #if defined( Q_WS_WIN ) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index b53e91f..b504604 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1173,8 +1173,9 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; and versatile, but may prove less memory and speed efficient than storing specific types in standard data structures. - QVariant also supports the notion of null values, where you have - a defined type with no value set. + QVariant also supports the notion of null values, where you can + have a defined type with no value set. However, note that QVariant + types can only be cast when they have had a value set. \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 1 diff --git a/src/corelib/statemachine/qabstractstate.cpp b/src/corelib/statemachine/qabstractstate.cpp index 3f84314..7e59a7d 100644 --- a/src/corelib/statemachine/qabstractstate.cpp +++ b/src/corelib/statemachine/qabstractstate.cpp @@ -129,36 +129,16 @@ void QAbstractStatePrivate::emitExited() Constructs a new state with the given \a parent state. */ QAbstractState::QAbstractState(QState *parent) - : QObject( -#ifndef QT_STATEMACHINE_SOLUTION - *new QAbstractStatePrivate, -#endif - parent) -#ifdef QT_STATEMACHINE_SOLUTION - , d_ptr(new QAbstractStatePrivate) -#endif + : QObject(*new QAbstractStatePrivate, parent) { -#ifdef QT_STATEMACHINE_SOLUTION - d_ptr->q_ptr = this; -#endif } /*! \internal */ QAbstractState::QAbstractState(QAbstractStatePrivate &dd, QState *parent) - : QObject( -#ifndef QT_STATEMACHINE_SOLUTION - dd, -#endif - parent) -#ifdef QT_STATEMACHINE_SOLUTION - , d_ptr(&dd) -#endif + : QObject(dd, parent) { -#ifdef QT_STATEMACHINE_SOLUTION - d_ptr->q_ptr = this; -#endif } /*! @@ -166,9 +146,6 @@ QAbstractState::QAbstractState(QAbstractStatePrivate &dd, QState *parent) */ QAbstractState::~QAbstractState() { -#ifdef QT_STATEMACHINE_SOLUTION - delete d_ptr; -#endif } /*! diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h index f6b4b21..d0ebb52 100644 --- a/src/corelib/statemachine/qabstractstate.h +++ b/src/corelib/statemachine/qabstractstate.h @@ -76,9 +76,6 @@ protected: bool event(QEvent *e); protected: -#ifdef QT_STATEMACHINE_SOLUTION - QAbstractStatePrivate *d_ptr; -#endif QAbstractState(QAbstractStatePrivate &dd, QState *parent); private: diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h index 6c09696..1a99d6c 100644 --- a/src/corelib/statemachine/qabstractstate_p.h +++ b/src/corelib/statemachine/qabstractstate_p.h @@ -53,9 +53,7 @@ // We mean it. // -#ifndef QT_STATEMACHINE_SOLUTION #include <private/qobject_p.h> -#endif QT_BEGIN_NAMESPACE @@ -63,9 +61,7 @@ class QStateMachine; class QAbstractState; class Q_CORE_EXPORT QAbstractStatePrivate -#ifndef QT_STATEMACHINE_SOLUTION : public QObjectPrivate -#endif { Q_DECLARE_PUBLIC(QAbstractState) @@ -82,10 +78,6 @@ public: void emitEntered(); void emitExited(); - -#ifdef QT_STATEMACHINE_SOLUTION - QAbstractState *q_ptr; -#endif }; QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp index 1897aa6..a930581 100644 --- a/src/corelib/statemachine/qabstracttransition.cpp +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -125,9 +125,9 @@ QStateMachine *QAbstractTransitionPrivate::machine() const return 0; } -bool QAbstractTransitionPrivate::callEventTest(QEvent *e) const +bool QAbstractTransitionPrivate::callEventTest(QEvent *e) { - Q_Q(const QAbstractTransition); + Q_Q(QAbstractTransition); return q->eventTest(e); } @@ -147,18 +147,8 @@ QState *QAbstractTransitionPrivate::sourceState() const Constructs a new QAbstractTransition object with the given \a sourceState. */ QAbstractTransition::QAbstractTransition(QState *sourceState) - : QObject( -#ifndef QT_STATEMACHINE_SOLUTION - *new QAbstractTransitionPrivate, -#endif - sourceState) -#ifdef QT_STATEMACHINE_SOLUTION - , d_ptr(new QAbstractTransitionPrivate) -#endif + : QObject(*new QAbstractTransitionPrivate, sourceState) { -#ifdef QT_STATEMACHINE_SOLUTION - d_ptr->q_ptr = this; -#endif } /*! @@ -167,20 +157,9 @@ QAbstractTransition::QAbstractTransition(QState *sourceState) */ QAbstractTransition::QAbstractTransition(const QList<QAbstractState*> &targets, QState *sourceState) - : QObject( -#ifndef QT_STATEMACHINE_SOLUTION - *new QAbstractTransitionPrivate, -#endif - sourceState) -#ifdef QT_STATEMACHINE_SOLUTION - , d_ptr(new QAbstractTransitionPrivate) -#endif + : QObject(*new QAbstractTransitionPrivate, sourceState) { -#ifdef QT_STATEMACHINE_SOLUTION - d_ptr->q_ptr = this; -#endif - Q_D(QAbstractTransition); - d->targetStates = targets; + setTargetStates(targets); } /*! @@ -188,18 +167,8 @@ QAbstractTransition::QAbstractTransition(const QList<QAbstractState*> &targets, */ QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd, QState *parent) - : QObject( -#ifndef QT_STATEMACHINE_SOLUTION - dd, -#endif - parent) -#ifdef QT_STATEMACHINE_SOLUTION - , d_ptr(&dd) -#endif + : QObject(dd, parent) { -#ifdef QT_STATEMACHINE_SOLUTION - d_ptr->q_ptr = this; -#endif } /*! @@ -208,20 +177,9 @@ QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd, QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd, const QList<QAbstractState*> &targets, QState *parent) - : QObject( -#ifndef QT_STATEMACHINE_SOLUTION - dd, -#endif - parent) -#ifdef QT_STATEMACHINE_SOLUTION - , d_ptr(&dd) -#endif + : QObject(dd, parent) { -#ifdef QT_STATEMACHINE_SOLUTION - d_ptr->q_ptr = this; -#endif - Q_D(QAbstractTransition); - d->targetStates = targets; + setTargetStates(targets); } /*! @@ -229,9 +187,6 @@ QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd, */ QAbstractTransition::~QAbstractTransition() { -#ifdef QT_STATEMACHINE_SOLUTION - delete d_ptr; -#endif } /*! @@ -265,7 +220,7 @@ void QAbstractTransition::setTargetState(QAbstractState* target) if (!target) d->targetStates.clear(); else - d->targetStates = QList<QAbstractState*>() << target; + setTargetStates(QList<QAbstractState*>() << target); } /*! @@ -275,7 +230,13 @@ void QAbstractTransition::setTargetState(QAbstractState* target) QList<QAbstractState*> QAbstractTransition::targetStates() const { Q_D(const QAbstractTransition); - return d->targetStates; + QList<QAbstractState*> result; + for (int i = 0; i < d->targetStates.size(); ++i) { + QAbstractState *target = d->targetStates.at(i); + if (target) + result.append(target); + } + return result; } /*! @@ -284,7 +245,22 @@ QList<QAbstractState*> QAbstractTransition::targetStates() const void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets) { Q_D(QAbstractTransition); - d->targetStates = targets; + + for (int i=0; i<targets.size(); ++i) { + QAbstractState *target = targets.at(i); + if (!target) { + qWarning("QAbstractTransition::setTargetStates: target state(s) cannot be null"); + return; + } + if (target->machine() != 0 && target->machine()->rootState() == target) { + qWarning("QAbstractTransition::setTargetStates: root state cannot be target of transition"); + return; + } + } + + d->targetStates.clear(); + for (int i = 0; i < targets.size(); ++i) + d->targetStates.append(targets.at(i)); } /*! diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h index e207944..c63d55a 100644 --- a/src/corelib/statemachine/qabstracttransition.h +++ b/src/corelib/statemachine/qabstracttransition.h @@ -88,16 +88,13 @@ public: #endif protected: - virtual bool eventTest(QEvent *event) const = 0; + virtual bool eventTest(QEvent *event) = 0; virtual void onTransition(QEvent *event) = 0; bool event(QEvent *e); protected: -#ifdef QT_STATEMACHINE_SOLUTION - QAbstractTransitionPrivate *d_ptr; -#endif QAbstractTransition(QAbstractTransitionPrivate &dd, QState *parent); QAbstractTransition(QAbstractTransitionPrivate &dd, const QList<QAbstractState*> &targets, QState *parent); diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h index b4e1c88..a6db220 100644 --- a/src/corelib/statemachine/qabstracttransition_p.h +++ b/src/corelib/statemachine/qabstracttransition_p.h @@ -53,11 +53,10 @@ // We mean it. // -#ifndef QT_STATEMACHINE_SOLUTION #include <private/qobject_p.h> -#endif #include <QtCore/qlist.h> +#include <QtCore/qpointer.h> QT_BEGIN_NAMESPACE @@ -67,9 +66,7 @@ class QStateMachine; class QAbstractTransition; class Q_CORE_EXPORT QAbstractTransitionPrivate -#ifndef QT_STATEMACHINE_SOLUTION : public QObjectPrivate -#endif { Q_DECLARE_PUBLIC(QAbstractTransition) public: @@ -78,20 +75,16 @@ public: static QAbstractTransitionPrivate *get(QAbstractTransition *q); static const QAbstractTransitionPrivate *get(const QAbstractTransition *q); - bool callEventTest(QEvent *e) const; + bool callEventTest(QEvent *e); void callOnTransition(QEvent *e); QState *sourceState() const; QStateMachine *machine() const; - QList<QAbstractState*> targetStates; + QList<QPointer<QAbstractState> > targetStates; #ifndef QT_NO_ANIMATION QList<QAbstractAnimation*> animations; #endif - -#ifdef QT_STATEMACHINE_SOLUTION - QAbstractTransition *q_ptr; -#endif }; QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp index 86259e4..74eb577 100644 --- a/src/corelib/statemachine/qeventtransition.cpp +++ b/src/corelib/statemachine/qeventtransition.cpp @@ -252,14 +252,10 @@ void QEventTransition::setEventObject(QObject *object) /*! \reimp */ -bool QEventTransition::eventTest(QEvent *event) const +bool QEventTransition::eventTest(QEvent *event) { Q_D(const QEventTransition); -#ifdef QT_STATEMACHINE_SOLUTION - if (event->type() == QEvent::Type(QEvent::User-3)) { -#else if (event->type() == QEvent::Wrapped) { -#endif QWrappedEvent *we = static_cast<QWrappedEvent*>(event); return (we->object() == d->object) && (we->event()->type() == d->eventType); diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h index a128cee..3530bdd 100644 --- a/src/corelib/statemachine/qeventtransition.h +++ b/src/corelib/statemachine/qeventtransition.h @@ -42,11 +42,7 @@ #ifndef QEVENTTRANSITION_H #define QEVENTTRANSITION_H -#ifndef QT_STATEMACHINE_SOLUTION #include <QtCore/qabstracttransition.h> -#else -#include "qabstracttransition.h" -#endif #include <QtCore/qcoreevent.h> QT_BEGIN_HEADER @@ -60,9 +56,7 @@ class Q_CORE_EXPORT QEventTransition : public QAbstractTransition { Q_OBJECT Q_PROPERTY(QObject* eventObject READ eventObject WRITE setEventObject) -#ifndef QT_STATEMACHINE_SOLUTION Q_PROPERTY(QEvent::Type eventType READ eventType WRITE setEventType) -#endif public: QEventTransition(QState *sourceState = 0); QEventTransition(QObject *object, QEvent::Type type, QState *sourceState = 0); @@ -77,7 +71,7 @@ public: void setEventType(QEvent::Type type); protected: - bool eventTest(QEvent *event) const; + bool eventTest(QEvent *event); void onTransition(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qfinalstate.h b/src/corelib/statemachine/qfinalstate.h index eb8aa0f..fa68394 100644 --- a/src/corelib/statemachine/qfinalstate.h +++ b/src/corelib/statemachine/qfinalstate.h @@ -42,11 +42,7 @@ #ifndef QFINALSTATE_H #define QFINALSTATE_H -#ifndef QT_STATEMACHINE_SOLUTION #include <QtCore/qabstractstate.h> -#else -#include "qabstractstate.h" -#endif QT_BEGIN_HEADER diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h index d0f75de..a0682bd 100644 --- a/src/corelib/statemachine/qhistorystate.h +++ b/src/corelib/statemachine/qhistorystate.h @@ -42,11 +42,7 @@ #ifndef QHISTORYSTATE_H #define QHISTORYSTATE_H -#ifndef QT_STATEMACHINE_SOLUTION #include <QtCore/qabstractstate.h> -#else -#include "qabstractstate.h" -#endif QT_BEGIN_HEADER diff --git a/src/corelib/statemachine/qsignaleventgenerator_p.h b/src/corelib/statemachine/qsignaleventgenerator_p.h index d18def8..cf0ea1e 100644 --- a/src/corelib/statemachine/qsignaleventgenerator_p.h +++ b/src/corelib/statemachine/qsignaleventgenerator_p.h @@ -62,11 +62,7 @@ class QStateMachine; class QSignalEventGenerator : public QObject { public: - QSignalEventGenerator( -#ifdef QT_STATEMACHINE_SOLUTION - int signalIndex, -#endif - QStateMachine *parent); + QSignalEventGenerator(QStateMachine *parent); static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const; @@ -74,9 +70,6 @@ public: virtual int qt_metacall(QMetaObject::Call, int, void **argv); private: -#ifdef QT_STATEMACHINE_SOLUTION - int signalIndex; -#endif Q_DISABLE_COPY(QSignalEventGenerator) }; diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp index d5833bd..4caa917 100644 --- a/src/corelib/statemachine/qsignaltransition.cpp +++ b/src/corelib/statemachine/qsignaltransition.cpp @@ -225,14 +225,10 @@ void QSignalTransition::setSignal(const QByteArray &signal) true if the event's sender and signal index match this transition, and returns false otherwise. */ -bool QSignalTransition::eventTest(QEvent *event) const +bool QSignalTransition::eventTest(QEvent *event) { Q_D(const QSignalTransition); -#ifndef QT_STATEMACHINE_SOLUTION if (event->type() == QEvent::Signal) { -#else - if (event->type() == QEvent::Type(QEvent::User-1)) { -#endif if (d->signalIndex == -1) return false; QSignalEvent *se = static_cast<QSignalEvent*>(event); diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h index 98a9ae7..b485785 100644 --- a/src/corelib/statemachine/qsignaltransition.h +++ b/src/corelib/statemachine/qsignaltransition.h @@ -42,11 +42,7 @@ #ifndef QSIGNALTRANSITION_H #define QSIGNALTRANSITION_H -#ifndef QT_STATEMACHINE_SOLUTION #include <QtCore/qabstracttransition.h> -#else -#include "qabstracttransition.h" -#endif QT_BEGIN_HEADER @@ -76,7 +72,7 @@ public: void setSignal(const QByteArray &signal); protected: - bool eventTest(QEvent *event) const; + bool eventTest(QEvent *event); void onTransition(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index 4c9e033..e42e463 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -193,9 +193,6 @@ QList<QAbstractState*> QStatePrivate::childStates() const { QList<QAbstractState*> result; QList<QObject*>::const_iterator it; -#ifdef QT_STATEMACHINE_SOLUTION - const QObjectList &children = q_func()->children(); -#endif for (it = children.constBegin(); it != children.constEnd(); ++it) { QAbstractState *s = qobject_cast<QAbstractState*>(*it); if (!s || qobject_cast<QHistoryState*>(s)) @@ -209,9 +206,6 @@ QList<QHistoryState*> QStatePrivate::historyStates() const { QList<QHistoryState*> result; QList<QObject*>::const_iterator it; -#ifdef QT_STATEMACHINE_SOLUTION - const QObjectList &children = q_func()->children(); -#endif for (it = children.constBegin(); it != children.constEnd(); ++it) { QHistoryState *h = qobject_cast<QHistoryState*>(*it); if (h) @@ -224,9 +218,6 @@ QList<QAbstractTransition*> QStatePrivate::transitions() const { QList<QAbstractTransition*> result; QList<QObject*>::const_iterator it; -#ifdef QT_STATEMACHINE_SOLUTION - const QObjectList &children = q_func()->children(); -#endif for (it = children.constBegin(); it != children.constEnd(); ++it) { QAbstractTransition *t = qobject_cast<QAbstractTransition*>(*it); if (t) @@ -280,11 +271,15 @@ QAbstractState *QState::errorState() const void QState::setErrorState(QAbstractState *state) { Q_D(QState); - if (state != 0 && QAbstractStatePrivate::get(state)->machine() != d->machine()) { + if (state != 0 && state->machine() != machine()) { qWarning("QState::setErrorState: error state cannot belong " "to a different state machine"); return; } + if (state != 0 && state->machine() != 0 && state->machine()->rootState() == state) { + qWarning("QStateMachine::setErrorState: root state cannot be error state"); + return; + } d->errorState = state; } @@ -301,7 +296,14 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition) qWarning("QState::addTransition: cannot add null transition"); return 0; } - const QList<QAbstractState*> &targets = QAbstractTransitionPrivate::get(transition)->targetStates; + + // machine() will always be non-null for root state + if (machine() != 0 && machine()->rootState() == this) { + qWarning("QState::addTransition: cannot add transition from root state"); + return 0; + } + + const QList<QPointer<QAbstractState> > &targets = QAbstractTransitionPrivate::get(transition)->targetStates; for (int i = 0; i < targets.size(); ++i) { QAbstractState *t = targets.at(i); if (!t) { @@ -316,6 +318,8 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition) } } transition->setParent(this); + if (machine() != 0 && machine()->configuration().contains(this)) + QStateMachinePrivate::get(machine())->registerTransitions(this); return transition; } @@ -335,6 +339,15 @@ QSignalTransition *QState::addTransition(QObject *sender, const char *signal, qWarning("QState::addTransition: signal cannot be null"); return 0; } + if (!target) { + qWarning("QState::addTransition: cannot add transition to null state"); + return 0; + } + if (*signal && sender->metaObject()->indexOfSignal(signal+1) == -1) { + qWarning("QState::addTransition: no such signal %s::%s", + sender->metaObject()->className(), signal+1); + return 0; + } QSignalTransition *trans = new QSignalTransition(sender, signal, QList<QAbstractState*>() << target); addTransition(trans); return trans; @@ -350,7 +363,7 @@ public: : QAbstractTransition(QList<QAbstractState*>() << target) {} protected: void onTransition(QEvent *) {} - bool eventTest(QEvent *) const { return true; } + bool eventTest(QEvent *) { return true; } }; } // namespace @@ -361,9 +374,12 @@ protected: */ QAbstractTransition *QState::addTransition(QAbstractState *target) { + if (!target) { + qWarning("QState::addTransition: cannot add transition to null state"); + return 0; + } UnconditionalTransition *trans = new UnconditionalTransition(target); - addTransition(trans); - return trans; + return addTransition(trans); } /*! diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h index 73955d7..6729c69 100644 --- a/src/corelib/statemachine/qstate.h +++ b/src/corelib/statemachine/qstate.h @@ -42,11 +42,7 @@ #ifndef QSTATE_H #define QSTATE_H -#ifndef QT_STATEMACHINE_SOLUTION #include <QtCore/qabstractstate.h> -#else -#include "qabstractstate.h" -#endif QT_BEGIN_HEADER diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index ff3fb7d..744515b 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -54,10 +54,8 @@ #include "qfinalstate.h" #include "qhistorystate.h" #include "qhistorystate_p.h" -#ifndef QT_STATEMACHINE_SOLUTION #include "private/qobject_p.h" #include "private/qthread_p.h" -#endif #ifndef QT_NO_STATEMACHINE_EVENTFILTER #include "qeventtransition.h" @@ -68,11 +66,7 @@ #ifndef QT_NO_ANIMATION #include "qpropertyanimation.h" #include "qanimationgroup.h" -# ifndef QT_STATEMACHINE_SOLUTION -# include <private/qvariantanimation_p.h> -# else -# include "qvariantanimation_p.h" -# endif +#include <private/qvariantanimation_p.h> #endif #include <QtCore/qmetaobject.h> @@ -89,68 +83,98 @@ QT_BEGIN_NAMESPACE \since 4.6 \ingroup statemachine - The QStateMachine class provides a hierarchical finite state machine based - on \l{Statecharts: A visual formalism for complex systems}{Statecharts} - concepts and notation. QStateMachine is part of \l{The State Machine - Framework}. - - A state machine manages a set of states (QAbstractState objects) and - transitions (QAbstractTransition objects) between those states; the states - and the transitions collectively define a state graph. Once a state graph - has been defined, the state machine can execute it. QStateMachine's - execution algorithm is based on the \l{State Chart XML: State Machine - Notation for Control Abstraction}{State Chart XML (SCXML)} algorithm. - - The QState class provides a state that you can use to set properties and - invoke methods on QObjects when the state is entered or exited. This is + QStateMachine is based on the concepts and notation of + \l{Statecharts: A visual formalism for complex + systems}{Statecharts}. QStateMachine is part of \l{The State + Machine Framework}. + + A state machine manages a set of states (classes that inherit from + QAbstractState) and transitions (descendants of + QAbstractTransition) between those states; these states and + transitions define a state graph. Once a state graph has been + built, the state machine can execute it. \l{QStateMachine}'s + execution algorithm is based on the \l{State Chart XML: State + Machine Notation for Control Abstraction}{State Chart XML (SCXML)} + algorithm. The framework's \l{The State Machine + Framework}{overview} gives several state graphs and the code to + build them. + + The rootState() is the parent of all top-level states in the + machine; it is used, for instance, when the state graph is + deleted. It is created by the machine. + + Use the addState() function to add a state to the state machine. + All top-level states are added to the root state. States are + removed with the removeState() function. Removing states while the + machine is running is discouraged. + + Before the machine can be started, the \l{initialState}{initial + state} must be set. The initial state is the state that the + machine enters when started. You can then start() the state + machine. The started() signal is emitted when the initial state is + entered. + + The machine is event driven and keeps its own event loop. Events + are posted to the machine through postEvent(). Note that this + means that it executes asynchronously, and that it will not + progress without a running event loop. You will normally not have + to post events to the machine directly as Qt's transitions, e.g., + QEventTransition and its subclasses, handle this. But for custom + transitions triggered by events, postEvent() is useful. + + The state machine processes events and takes transitions until a + top-level final state is entered; the state machine then emits the + finished() signal. You can also stop() the state machine + explicitly. The stopped() signal is emitted in this case. + + The following snippet shows a state machine that will finish when a button + is clicked: + + \code + QPushButton button; + + QStateMachine machine; + QState *s1 = new QState(); + s1->assignProperty(&button, "text", "Click me"); + + QFinalState *s2 = new QFinalState(); + s1->addTransition(&button, SIGNAL(clicked()), s2); + + machine.addState(s1); + machine.addState(s2); + machine.setInitialState(s1); + machine.start(); + \endcode + + This code example uses QState, which inherits QAbstractState. The + QState class provides a state that you can use to set properties + and invoke methods on \l{QObject}s when the state is entered or + exited. It also contains convenience functions for adding + transitions, e.g., \l{QSignalTransition}s as in this example. See + the QState class description for further details. + + If an error is encountered, the machine will enter the + \l{errorState}{error state}, which is a special state created by + the machine. The types of errors possible are described by the + \l{QStateMachine::}{Error} enum. After the error state is entered, + the type of the error can be retrieved with error(). The execution + of the state graph will not stop when the error state is entered. + So it is possible to handle the error, for instance, by connecting + to the \l{QAbstractState::}{entered()} signal of the error state. + It is also possible to set a custom error state with + setErrorState(). + + \omit This stuff will be moved elsewhere +This is typically used in conjunction with \l{Signals and Slots}{signals}; the signals determine the flow of the state graph, whereas the states' property assignments and method invocations are the actions. - Use the addState() function to add a state to the state machine; - alternatively, pass the machine's rootState() to the state constructor. Use - the removeState() function to remove a state from the state machine. - - The following snippet shows a state machine that will finish when a button - is clicked: - - \code - QPushButton button; - - QStateMachine machine; - QState *s1 = new QState(); - s1->assignProperty(&button, "text", "Click me"); - - QFinalState *s2 = new QFinalState(); - s1->addTransition(&button, SIGNAL(clicked()), s2); - - machine.addState(s1); - machine.addState(s2); - machine.setInitialState(s1); - machine.start(); - \endcode - - The setInitialState() function sets the state machine's initial state; this - state is entered when the state machine is started. - - The start() function starts the state machine. The state machine executes - asynchronously, i.e. you need to run an event loop in order for it to make - progress. The started() signal is emitted when the state machine has entered - the initial state. - - The state machine processes events and takes transitions until a top-level - final state is entered; the state machine then emits the finished() signal. - - The stop() function stops the state machine. The stopped() signal is emitted - when the state machine has stopped. - The postEvent() function posts an event to the state machine. This is useful when you are using custom events to trigger transitions. + \endomit - The rootState() function returns the state machine's root state. All - top-level states have the root state as their parent. - - \sa QAbstractState, QAbstractTransition + \sa QAbstractState, QAbstractTransition, QState, {The State Machine Framework} */ /*! @@ -212,9 +236,7 @@ QStateMachinePrivate::QStateMachinePrivate() globalRestorePolicy = QStateMachine::DoNotRestoreProperties; rootState = 0; initialErrorStateForRoot = 0; -#ifndef QT_STATEMACHINE_SOLUTION signalEventGenerator = 0; -#endif #ifndef QT_NO_ANIMATION animationsEnabled = true; #endif @@ -1011,6 +1033,8 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta } Q_ASSERT(currentErrorState != 0); + Q_ASSERT(currentErrorState != rootState); + QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext); addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); } @@ -1100,7 +1124,7 @@ public: InitialTransition(QAbstractState *target) : QAbstractTransition(QList<QAbstractState*>() << target) {} protected: - virtual bool eventTest(QEvent *) const { return true; } + virtual bool eventTest(QEvent *) { return true; } virtual void onTransition(QEvent *) {} }; @@ -1222,10 +1246,12 @@ void QStateMachinePrivate::_q_process() break; case Finished: state = NotRunning; + unregisterAllTransitions(); emit q->finished(); break; case Stopped: state = NotRunning; + unregisterAllTransitions(); emit q->stopped(); break; } @@ -1270,8 +1296,6 @@ void QStateMachinePrivate::unregisterTransition(QAbstractTransition *transition) #endif } -#ifndef QT_STATEMACHINE_SOLUTION - static int senderSignalIndex(const QObject *sender) { QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject*>(sender)); @@ -1288,8 +1312,6 @@ static int senderSignalIndex(const QObject *sender) return d->currentSender->signal; } -#endif - void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transition) { Q_Q(QStateMachine); @@ -1307,14 +1329,12 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio sender->metaObject()->className(), signal.constData()); return; } - QList<int> &connectedSignalIndexes = connections[sender]; - if (!connectedSignalIndexes.contains(signalIndex)) { -#ifndef QT_STATEMACHINE_SOLUTION + QVector<int> &connectedSignalIndexes = connections[sender]; + if (connectedSignalIndexes.size() <= signalIndex) + connectedSignalIndexes.resize(signalIndex+1); + if (connectedSignalIndexes.at(signalIndex) == 0) { if (!signalEventGenerator) signalEventGenerator = new QSignalEventGenerator(q); -#else - QSignalEventGenerator *signalEventGenerator = new QSignalEventGenerator(signalIndex, q); -#endif bool ok = QMetaObject::connect(sender, signalIndex, signalEventGenerator, signalEventGenerator->metaObject()->methodOffset()); if (!ok) { @@ -1325,8 +1345,8 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio #endif return; } - connectedSignalIndexes.append(signalIndex); } + ++connectedSignalIndexes[signalIndex]; QSignalTransitionPrivate::get(transition)->signalIndex = signalIndex; #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": added signal transition from" << transition->sourceState() @@ -1340,20 +1360,35 @@ void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transit int signalIndex = QSignalTransitionPrivate::get(transition)->signalIndex; if (signalIndex == -1) return; // not registered -#ifndef QT_STATEMACHINE_SOLUTION + QSignalTransitionPrivate::get(transition)->signalIndex = -1; const QObject *sender = QSignalTransitionPrivate::get(transition)->sender; - QList<int> &connectedSignalIndexes = connections[sender]; - Q_ASSERT(connectedSignalIndexes.contains(signalIndex)); - Q_ASSERT(signalEventGenerator != 0); - bool ok = QMetaObject::disconnect(sender, signalIndex, signalEventGenerator, - signalEventGenerator->metaObject()->methodOffset()); - if (ok) { - connectedSignalIndexes.removeOne(signalIndex); - if (connectedSignalIndexes.isEmpty()) + QVector<int> &connectedSignalIndexes = connections[sender]; + Q_ASSERT(connectedSignalIndexes.size() > signalIndex); + Q_ASSERT(connectedSignalIndexes.at(signalIndex) != 0); + if (--connectedSignalIndexes[signalIndex] == 0) { + Q_ASSERT(signalEventGenerator != 0); + QMetaObject::disconnect(sender, signalIndex, signalEventGenerator, + signalEventGenerator->metaObject()->methodOffset()); + int sum = 0; + for (int i = 0; i < connectedSignalIndexes.size(); ++i) + sum += connectedSignalIndexes.at(i); + if (sum == 0) connections.remove(sender); - QSignalTransitionPrivate::get(transition)->signalIndex = -1; } -#endif +} + +void QStateMachinePrivate::unregisterAllTransitions() +{ + { + QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState); + for (int i = 0; i < transitions.size(); ++i) + unregisterSignalTransition(transitions.at(i)); + } + { + QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState); + for (int i = 0; i < transitions.size(); ++i) + unregisterEventTransition(transitions.at(i)); + } } #ifndef QT_NO_STATEMACHINE_EVENTFILTER @@ -1369,12 +1404,10 @@ void QStateMachinePrivate::registerEventTransition(QEventTransition *transition) QObject *object = QEventTransitionPrivate::get(transition)->object; if (!object) return; -#ifndef QT_STATEMACHINE_SOLUTION QObjectPrivate *od = QObjectPrivate::get(object); if (!od->eventFilters.contains(q)) -#endif object->installEventFilter(q); - qobjectEvents[object].insert(transition->eventType()); + ++qobjectEvents[object][transition->eventType()]; QEventTransitionPrivate::get(transition)->registered = true; #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": added event transition from" << transition->sourceState() @@ -1389,11 +1422,18 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio if (!QEventTransitionPrivate::get(transition)->registered) return; QObject *object = QEventTransitionPrivate::get(transition)->object; - QSet<QEvent::Type> &events = qobjectEvents[object]; - events.remove(transition->eventType()); - if (events.isEmpty()) { - qobjectEvents.remove(object); - object->removeEventFilter(q); + QHash<QEvent::Type, int> &events = qobjectEvents[object]; + Q_ASSERT(events.value(transition->eventType()) > 0); + if (--events[transition->eventType()] == 0) { + events.remove(transition->eventType()); + int sum = 0; + QHash<QEvent::Type, int>::const_iterator it; + for (it = events.constBegin(); it != events.constEnd(); ++it) + sum += it.value(); + if (sum == 0) { + qobjectEvents.remove(object); + object->removeEventFilter(q); + } } QEventTransitionPrivate::get(transition)->registered = false; } @@ -1402,8 +1442,8 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int signalIndex, void **argv) { - const QList<int> &connectedSignalIndexes = connections[sender]; - Q_ASSERT(connectedSignalIndexes.contains(signalIndex)); + const QVector<int> &connectedSignalIndexes = connections[sender]; + Q_ASSERT(connectedSignalIndexes.at(signalIndex) != 0); const QMetaObject *meta = sender->metaObject(); QMetaMethod method = meta->method(signalIndex); QList<QByteArray> parameterTypes = method.parameterTypes(); @@ -1426,36 +1466,16 @@ void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int sig Constructs a new state machine with the given \a parent. */ QStateMachine::QStateMachine(QObject *parent) - : QObject( -#ifndef QT_STATEMACHINE_SOLUTION - *new QStateMachinePrivate, -#endif - parent) -#ifdef QT_STATEMACHINE_SOLUTION - , d_ptr(new QStateMachinePrivate) -#endif + : QObject(*new QStateMachinePrivate, parent) { -#ifdef QT_STATEMACHINE_SOLUTION - d_ptr->q_ptr = this; -#endif } /*! \internal */ QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent) - : QObject( -#ifndef QT_STATEMACHINE_SOLUTION - dd, -#endif - parent) -#ifdef QT_STATEMACHINE_SOLUTION - , d_ptr(&dd) -#endif + : QObject(dd, parent) { -#ifdef QT_STATEMACHINE_SOLUTION - d_ptr->q_ptr = this; -#endif } /*! @@ -1463,9 +1483,6 @@ QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent) */ QStateMachine::~QStateMachine() { -#ifdef QT_STATEMACHINE_SOLUTION - delete d_ptr; -#endif } namespace { @@ -2065,11 +2082,9 @@ int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a) if (_c == QMetaObject::InvokeMetaMethod) { switch (_id) { case 0: { -#ifndef QT_STATEMACHINE_SOLUTION // ### in Qt 4.6 we can use QObject::senderSignalIndex() int signalIndex = senderSignalIndex(this); Q_ASSERT(signalIndex != -1); -#endif QStateMachine *machine = qobject_cast<QStateMachine*>(parent()); QStateMachinePrivate::get(machine)->handleTransitionSignal(sender(), signalIndex, _a); break; @@ -2081,15 +2096,8 @@ int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a) return _id; } -QSignalEventGenerator::QSignalEventGenerator( -#ifdef QT_STATEMACHINE_SOLUTION - int sigIdx, -#endif - QStateMachine *parent) +QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent) : QObject(parent) -#ifdef QT_STATEMACHINE_SOLUTION - , signalIndex(sigIdx) -#endif { } @@ -2120,13 +2128,8 @@ QSignalEventGenerator::QSignalEventGenerator( */ QSignalEvent::QSignalEvent(const QObject *sender, int signalIndex, const QList<QVariant> &arguments) - : -#ifndef QT_STATEMACHINE_SOLUTION - QEvent(QEvent::Signal) -#else - QEvent(QEvent::Type(QEvent::User-1)) -#endif - , m_sender(sender), m_signalIndex(signalIndex), m_arguments(arguments) + : QEvent(QEvent::Signal), m_sender(sender), + m_signalIndex(signalIndex), m_arguments(arguments) { } @@ -2185,12 +2188,7 @@ QSignalEvent::~QSignalEvent() and \a event. */ QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event) -#ifdef QT_STATEMACHINE_SOLUTION - : QEvent(QEvent::Type(QEvent::User-3)) -#else - : QEvent(QEvent::Wrapped) -#endif - , m_object(object), m_event(event) + : QEvent(QEvent::Wrapped), m_object(object), m_event(event) { } diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index 5dc6c0b..2a98a9a 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -42,11 +42,7 @@ #ifndef QSTATEMACHINE_H #define QSTATEMACHINE_H -#ifndef QT_STATEMACHINE_SOLUTION -# include <QtCore/qabstractstate.h> -#else -# include "qabstractstate.h" -#endif +#include <QtCore/qabstractstate.h> #include <QtCore/qlist.h> #include <QtCore/qobject.h> @@ -151,9 +147,6 @@ protected: bool event(QEvent *e); protected: -#ifdef QT_STATEMACHINE_SOLUTION - QStateMachinePrivate *d_ptr; -#endif QStateMachine(QStateMachinePrivate &dd, QObject *parent); private: diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index bb4a78c..dfa5575 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -53,14 +53,13 @@ // We mean it. // -#ifndef QT_STATEMACHINE_SOLUTION #include <private/qobject_p.h> -#endif #include <QtCore/qcoreevent.h> #include <QtCore/qhash.h> #include <QtCore/qlist.h> #include <QtCore/qpair.h> #include <QtCore/qset.h> +#include <QtCore/qvector.h> #include "qstate.h" #include "qstate_p.h" @@ -83,9 +82,7 @@ class QAbstractAnimation; class QStateMachine; class Q_CORE_EXPORT QStateMachinePrivate -#ifndef QT_STATEMACHINE_SOLUTION : public QObjectPrivate -#endif { Q_DECLARE_PUBLIC(QStateMachine) public: @@ -150,6 +147,7 @@ public: void unregisterEventTransition(QEventTransition *transition); #endif void unregisterTransition(QAbstractTransition *transition); + void unregisterAllTransitions(); void handleTransitionSignal(const QObject *sender, int signalIndex, void **args); void scheduleProcess(); @@ -198,12 +196,11 @@ public: #endif // QT_NO_ANIMATION -#ifndef QT_STATEMACHINE_SOLUTION QSignalEventGenerator *signalEventGenerator; -#endif - QHash<const QObject*, QList<int> > connections; + + QHash<const QObject*, QVector<int> > connections; #ifndef QT_NO_STATEMACHINE_EVENTFILTER - QHash<QObject*, QSet<QEvent::Type> > qobjectEvents; + QHash<QObject*, QHash<QEvent::Type, int> > qobjectEvents; #endif QHash<int, QEvent*> delayedEvents; @@ -213,10 +210,6 @@ public: }; static const Handler *handler; - -#ifdef QT_STATEMACHINE_SOLUTION - QStateMachine *q_ptr; -#endif }; QT_END_NAMESPACE diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp new file mode 100644 index 0000000..7db3a5a --- /dev/null +++ b/src/corelib/tools/qcontiguouscache.cpp @@ -0,0 +1,435 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 "qcontiguouscache.h" +#include <QDebug> + +QT_BEGIN_NAMESPACE + +void QContiguousCacheData::dump() const +{ + qDebug() << "capacity:" << alloc; + qDebug() << "count:" << count; + qDebug() << "start:" << start; + qDebug() << "offset:" << offset; +} + +/*! \class QContiguousCache + \brief The QContiguousCache class is a template class that provides a contiguous cache. + \ingroup tools + \ingroup shared + \reentrant + + The QContiguousCache class provides an efficient way of caching items for + display in a user interface view. Unlike QCache, it adds a restriction + that elements within the cache are contiguous. This has the advantage + of matching how user interface views most commonly request data, as + a set of rows localized around the current scrolled position. This + restriction allows the cache to consume less memory and processor + cycles than QCache. The QContiguousCache class also can provide + an upper bound on memory usage via setCapacity(). + + The simplest way of using a contiguous cache is to use the append() + and prepend(). + +\code +MyRecord record(int row) const +{ + Q_ASSERT(row >= 0 && row < count()); + + while(row > cache.lastIndex()) + cache.append(slowFetchRecord(cache.lastIndex()+1)); + while(row < cache.firstIndex()) + cache.prepend(slowFetchRecord(cache.firstIndex()-1)); + + return cache.at(row); +} +\endcode + + If the cache is full then the item at the opposite end of the cache from + where the new item is appended or prepended will be removed. + + This usage can be further optimized by using the insert() function + in the case where the requested row is a long way from the currently cached + items. If there is a gap between where the new item is inserted and the currently + cached items then the existing cached items are first removed to retain + the contiguous nature of the cache. Hence it is important to take some care then + when using insert() in order to avoid unwanted clearing of the cache. + + The range of valid indexes for the QContiguousCache class are from + 0 to INT_MAX. Calling prepend() such that the first index would become less + than 0 or append() such that the last index would become greater + than INT_MAX can result in the indexes of the cache being invalid. + When the cache indexes are invalid it is important to call + normalizeIndexes() before calling any of containsIndex(), firstIndex(), + lastIndex(), at() or the [] operator. Calling these + functions when the cache has invalid indexes will result in undefined + behavior. The indexes can be checked by using areIndexesValid() + + In most cases the indexes will not exceed 0 to INT_MAX, and + normalizeIndexes() will not need to be used. + + See the \l{Contiguous Cache Example}{Contiguous Cache} example. +*/ + +/*! \fn QContiguousCache::QContiguousCache(int capacity) + + Constructs a cache with the given \a capacity. + + \sa setCapacity() +*/ + +/*! \fn QContiguousCache::QContiguousCache(const QContiguousCache<T> &other) + + Constructs a copy of \a other. + + This operation takes \l{constant time}, because QContiguousCache is + \l{implicitly shared}. This makes returning a QContiguousCache from a + function very fast. If a shared instance is modified, it will be + copied (copy-on-write), and that takes \l{linear time}. + + \sa operator=() +*/ + +/*! \fn QContiguousCache::~QContiguousCache() + + Destroys the cache. +*/ + +/*! \fn void QContiguousCache::detach() + + \internal +*/ + +/*! \fn bool QContiguousCache::isDetached() const + + \internal +*/ + +/*! \fn void QContiguousCache::setSharable(bool sharable) + + \internal +*/ + +/*! \fn QContiguousCache<T> &QContiguousCache::operator=(const QContiguousCache<T> &other) + + Assigns \a other to this cache and returns a reference to this cache. +*/ + +/*! \fn bool QContiguousCache::operator==(const QContiguousCache<T> &other) const + + Returns true if \a other is equal to this cache; otherwise returns false. + + Two caches are considered equal if they contain the same values at the same + indexes. This function requires the value type to implement the \c operator==(). + + \sa operator!=() +*/ + +/*! \fn bool QContiguousCache::operator!=(const QContiguousCache<T> &other) const + + Returns true if \a other is not equal to this cache; otherwise + returns false. + + Two caches are considered equal if they contain the same values at the same + indexes. This function requires the value type to implement the \c operator==(). + + \sa operator==() +*/ + +/*! \fn int QContiguousCache::capacity() const + + Returns the number of items the cache can store before it is full. + When a cache contains a number of items equal to its capacity, adding new + items will cause items farthest from the added item to be removed. + + \sa setCapacity(), size() +*/ + +/*! \fn int QContiguousCache::count() const + + \overload + + Same as size(). +*/ + +/*! \fn int QContiguousCache::size() const + + Returns the number of items contained within the cache. + + \sa capacity() +*/ + +/*! \fn bool QContiguousCache::isEmpty() const + + Returns true if no items are stored within the cache. + + \sa size(), capacity() +*/ + +/*! \fn bool QContiguousCache::isFull() const + + Returns true if the number of items stored within the cache is equal + to the capacity of the cache. + + \sa size(), capacity() +*/ + +/*! \fn int QContiguousCache::available() const + + Returns the number of items that can be added to the cache before it becomes full. + + \sa size(), capacity(), isFull() +*/ + +/*! \fn void QContiguousCache::clear() + + Removes all items from the cache. The capacity is unchanged. +*/ + +/*! \fn void QContiguousCache::setCapacity(int size) + + Sets the capacity of the cache to the given \a size. A cache can hold a + number of items equal to its capacity. When inserting, appending or prepending + items to the cache, if the cache is already full then the item farthest from + the added item will be removed. + + If the given \a size is smaller than the current count of items in the cache + then only the last \a size items from the cache will remain. + + \sa capacity(), isFull() +*/ + +/*! \fn const T &QContiguousCache::at(int i) const + + Returns the item at index position \a i in the cache. \a i must + be a valid index position in the cache (i.e, firstIndex() <= \a i <= lastIndex()). + + The indexes in the cache refer to the number of positions the item is from the + first item appended into the cache. That is to say a cache with a capacity of + 100, that has had 150 items appended will have a valid index range of + 50 to 149. This allows inserting and retrieving items into the cache based + on a theoretical infinite list + + \sa firstIndex(), lastIndex(), insert(), operator[]() +*/ + +/*! \fn T &QContiguousCache::operator[](int i) + + Returns the item at index position \a i as a modifiable reference. If + the cache does not contain an item at the given index position \a i + then it will first insert an empty item at that position. + + In most cases it is better to use either at() or insert(). + + Note that using non-const operators can cause QContiguousCache to do a deep + copy. + + \sa insert(), at() +*/ + +/*! \fn const T &QContiguousCache::operator[](int i) const + + \overload + + Same as at(\a i). +*/ + +/*! \fn void QContiguousCache::append(const T &value) + + Inserts \a value at the end of the cache. If the cache is already full + the item at the start of the cache will be removed. + + \sa prepend(), insert(), isFull() +*/ + +/*! \fn void QContiguousCache::prepend(const T &value) + + Inserts \a value at the start of the cache. If the cache is already full + the item at the end of the cache will be removed. + + \sa append(), insert(), isFull() +*/ + +/*! \fn void QContiguousCache::insert(int i, const T &value) + + Inserts the \a value at the index position \a i. If the cache already contains + an item at \a i then that value is replaced. If \a i is either one more than + lastIndex() or one less than firstIndex() it is the equivalent to an append() + or a prepend(). + + If the given index \a i is not within the current range of the cache nor adjacent + to the bounds of the cache's index range, the cache is first cleared before + inserting the item. At this point the cache will have a size of 1. It is + worthwhile taking effort to insert items in an order that starts adjacent + to the current index range for the cache. + + The range of valid indexes for the QContiguousCache class are from + 0 to INT_MAX. Inserting outside of this range has undefined behavior. + + + \sa prepend(), append(), isFull(), firstIndex(), lastIndex() +*/ + +/*! \fn bool QContiguousCache::containsIndex(int i) const + + Returns true if the cache's index range includes the given index \a i. + + \sa firstIndex(), lastIndex() +*/ + +/*! \fn int QContiguousCache::firstIndex() const + + Returns the first valid index in the cache. The index will be invalid if the + cache is empty. + + \sa capacity(), size(), lastIndex() +*/ + +/*! \fn int QContiguousCache::lastIndex() const + + Returns the last valid index in the cache. The index will be invalid if the cache is empty. + + \sa capacity(), size(), firstIndex() +*/ + + +/*! \fn T &QContiguousCache::first() + + Returns a reference to the first item in the cache. This function + assumes that the cache isn't empty. + + \sa last(), isEmpty() +*/ + +/*! \fn T &QContiguousCache::last() + + Returns a reference to the last item in the cache. This function + assumes that the cache isn't empty. + + \sa first(), isEmpty() +*/ + +/*! \fn const T& QContiguousCache::first() const + + \overload +*/ + +/*! \fn const T& QContiguousCache::last() const + + \overload +*/ + +/*! \fn void QContiguousCache::removeFirst() + + Removes the first item from the cache. This function assumes that + the cache isn't empty. + + \sa removeLast() +*/ + +/*! \fn void QContiguousCache::removeLast() + + Removes the last item from the cache. This function assumes that + the cache isn't empty. + + \sa removeFirst() +*/ + +/*! \fn T QContiguousCache::takeFirst() + + Removes the first item in the cache and returns it. This function + assumes that the cache isn't empty. + + If you don't use the return value, removeFirst() is more efficient. + + \sa takeLast(), removeFirst() +*/ + +/*! \fn T QContiguousCache::takeLast() + + Removes the last item in the cache and returns it. This function + assumes that the cache isn't empty. + + If you don't use the return value, removeLast() is more efficient. + + \sa takeFirst(), removeLast() +*/ + +/*! \fn void QContiguousCache::normalizeIndexes() + + Moves the first index and last index of the cache + such that they point to valid indexes. The function does not modify + the contents of the cache or the ordering of elements within the cache. + + It is provided so that index overflows can be corrected when using the + cache as a circular buffer. + + \code + QContiguousCache<int> cache(10); + cache.insert(INT_MAX, 1); // cache contains one value and has valid indexes, INT_MAX to INT_MAX + cache.append(2); // cache contains two values but does not have valid indexes. + cache.normalizeIndexes(); // cache has two values, 1 and 2. New first index will be in the range of 0 to capacity(). + \endcode + + \sa areIndexesValid(), append(), prepend() +*/ + +/*! \fn bool QContiguousCache::areIndexesValid() const + + Returns whether the indexes for items stored in the cache are valid. + Indexes can become invalid if items are appended after the index position + INT_MAX or prepended before the index position 0. This is only expected + to occur in very long lived circular buffer style usage of the + contiguous cache. Indexes can be made valid again by calling + normalizeIndexs(). + + \sa normalizeIndexes(), append(), prepend() +*/ + +/*! \fn void QContiguousCache::dump() const + + \internal + + Sends information about the cache's internal structure to qDebug() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h new file mode 100644 index 0000000..5cd1582 --- /dev/null +++ b/src/corelib/tools/qcontiguouscache.h @@ -0,0 +1,424 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 QCONTIGUOUSCACHE_H +#define QCONTIGUOUSCACHE_H + +#include <QtCore/qatomic.h> +#include <limits.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +struct Q_CORE_EXPORT QContiguousCacheData +{ + QBasicAtomicInt ref; + int alloc; + int count; + int start; + int offset; + uint sharable : 1; + + void dump() const; +}; + +template <typename T> +struct QContiguousCacheTypedData +{ + QBasicAtomicInt ref; + int alloc; + int count; + int start; + int offset; + uint sharable : 1; + + T array[1]; +}; + +template<typename T> +class QContiguousCache { + typedef QContiguousCacheTypedData<T> Data; + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; }; +public: + explicit QContiguousCache(int capacity = 0); + QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); } + + inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(d); } + + inline void detach() { if (d->ref != 1) detach_helper(); } + inline bool isDetached() const { return d->ref == 1; } + inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } + + QContiguousCache<T> &operator=(const QContiguousCache<T> &other); + bool operator==(const QContiguousCache<T> &other) const; + inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); } + + inline int capacity() const {return d->alloc; } + inline int count() const { return d->count; } + inline int size() const { return d->count; } + + inline bool isEmpty() const { return d->count == 0; } + inline bool isFull() const { return d->count == d->alloc; } + inline int available() const { return d->alloc - d->count; } + + void clear(); + void setCapacity(int size); + + const T &at(int pos) const; + T &operator[](int i); + const T &operator[](int i) const; + + void append(const T &value); + void prepend(const T &value); + void insert(int pos, const T &value); + + inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; } + inline int firstIndex() const { return d->offset; } + inline int lastIndex() const { return d->offset + d->count - 1; } + + inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; } + inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; } + inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; } + inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; } + + void removeFirst(); + T takeFirst(); + void removeLast(); + T takeLast(); + + inline bool areIndexesValid() const + { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; } + + inline void normalizeIndexes() { d->offset = d->start; } + // debug + void dump() const { p->dump(); } +private: + void detach_helper(); + + QContiguousCacheData *malloc(int aalloc); + void free(Data *x); + int sizeOfTypedData() { + // this is more or less the same as sizeof(Data), except that it doesn't + // count the padding at the end + return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); + } +}; + +template <typename T> +void QContiguousCache<T>::detach_helper() +{ + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + + x.p = malloc(d->alloc); + x.d->ref = 1; + x.d->count = d->count; + x.d->start = d->start; + x.d->offset = d->offset; + x.d->alloc = d->alloc; + x.d->sharable = true; + + T *dest = x.d->array + x.d->start; + T *src = d->array + d->start; + int count = x.d->count; + while (count--) { + if (QTypeInfo<T>::isComplex) { + new (dest) T(*src); + } else { + *dest = *src; + } + dest++; + if (dest == x.d->array + x.d->alloc) + dest = x.d->array; + src++; + if (src == d->array + d->alloc) + src = d->array; + } + + if (!d->ref.deref()) + free(d); + d = x.d; +} + +template <typename T> +void QContiguousCache<T>::setCapacity(int asize) +{ + if (asize == d->alloc) + return; + detach(); + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + x.p = malloc(asize); + x.d->alloc = asize; + x.d->count = qMin(d->count, asize); + x.d->offset = d->offset + d->count - x.d->count; + x.d->start = x.d->offset % x.d->alloc; + T *dest = x.d->array + (x.d->start + x.d->count-1) % x.d->alloc; + T *src = d->array + (d->start + d->count-1) % d->alloc; + int count = x.d->count; + while (count--) { + if (QTypeInfo<T>::isComplex) { + new (dest) T(*src); + } else { + *dest = *src; + } + if (dest == x.d->array) + dest = x.d->array + x.d->alloc; + dest--; + if (src == d->array) + src = d->array + d->alloc; + src--; + } + /* free old */ + free(d); + d = x.d; +} + +template <typename T> +void QContiguousCache<T>::clear() +{ + if (d->ref == 1) { + if (QTypeInfo<T>::isComplex) { + int count = d->count; + T * i = d->array + d->start; + T * e = d->array + d->alloc; + while (count--) { + i->~T(); + i++; + if (i == e) + i = d->array; + } + } + d->count = d->start = d->offset = 0; + } else { + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + x.p = malloc(d->alloc); + x.d->ref = 1; + x.d->alloc = d->alloc; + x.d->count = x.d->start = x.d->offset = 0; + x.d->sharable = true; + if (!d->ref.deref()) free(d); + d = x.d; + } +} + +template <typename T> +inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc) +{ + return static_cast<QContiguousCacheData *>(qMalloc(sizeOfTypedData() + (aalloc - 1) * sizeof(T))); +} + +template <typename T> +QContiguousCache<T>::QContiguousCache(int capacity) +{ + p = malloc(capacity); + d->ref = 1; + d->alloc = capacity; + d->count = d->start = d->offset = 0; + d->sharable = true; +} + +template <typename T> +QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &other) +{ + other.d->ref.ref(); + if (!d->ref.deref()) + free(d); + d = other.d; + if (!d->sharable) + detach_helper(); + return *this; +} + +template <typename T> +bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const +{ + if (other.d == d) + return true; + if (other.d->start != d->start + || other.d->count != d->count + || other.d->offset != d->offset + || other.d->alloc != d->alloc) + return false; + for (int i = firstIndex(); i <= lastIndex(); ++i) + if (!(at(i) == other.at(i))) + return false; + return true; +} + +template <typename T> +void QContiguousCache<T>::free(Data *x) +{ + if (QTypeInfo<T>::isComplex) { + int count = d->count; + T * i = d->array + d->start; + T * e = d->array + d->alloc; + while (count--) { + i->~T(); + i++; + if (i == e) + i = d->array; + } + } + qFree(x); +} +template <typename T> +void QContiguousCache<T>::append(const T &value) +{ + detach(); + if (QTypeInfo<T>::isComplex) { + if (d->count == d->alloc) + (d->array + (d->start+d->count) % d->alloc)->~T(); + new (d->array + (d->start+d->count) % d->alloc) T(value); + } else { + d->array[(d->start+d->count) % d->alloc] = value; + } + + if (d->count == d->alloc) { + d->start++; + d->start %= d->alloc; + d->offset++; + } else { + d->count++; + } +} + +template<typename T> +void QContiguousCache<T>::prepend(const T &value) +{ + detach(); + if (d->start) + d->start--; + else + d->start = d->alloc-1; + d->offset--; + + if (d->count != d->alloc) + d->count++; + else + if (d->count == d->alloc) + (d->array + d->start)->~T(); + + if (QTypeInfo<T>::isComplex) + new (d->array + d->start) T(value); + else + d->array[d->start] = value; +} + +template<typename T> +void QContiguousCache<T>::insert(int pos, const T &value) +{ + Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range"); + detach(); + if (containsIndex(pos)) { + if(QTypeInfo<T>::isComplex) + new (d->array + pos % d->alloc) T(value); + else + d->array[pos % d->alloc] = value; + } else if (pos == d->offset-1) + prepend(value); + else if (pos == d->offset+d->count) + append(value); + else { + // we don't leave gaps. + clear(); + d->offset = pos; + d->start = pos % d->alloc; + d->count = 1; + if (QTypeInfo<T>::isComplex) + new (d->array + d->start) T(value); + else + d->array[d->start] = value; + } +} + +template <typename T> +inline const T &QContiguousCache<T>::at(int pos) const +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; } +template <typename T> +inline const T &QContiguousCache<T>::operator[](int pos) const +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; } + +template <typename T> +inline T &QContiguousCache<T>::operator[](int pos) +{ + detach(); + if (!containsIndex(pos)) + insert(pos, T()); + return d->array[pos % d->alloc]; +} + +template <typename T> +inline void QContiguousCache<T>::removeFirst() +{ + Q_ASSERT(d->count > 0); + detach(); + d->count--; + if (QTypeInfo<T>::isComplex) + (d->array + d->start)->~T(); + d->start = (d->start + 1) % d->alloc; + d->offset++; +} + +template <typename T> +inline void QContiguousCache<T>::removeLast() +{ + Q_ASSERT(d->count > 0); + detach(); + d->count--; + if (QTypeInfo<T>::isComplex) + (d->array + (d->start + d->count) % d->alloc)->~T(); +} + +template <typename T> +inline T QContiguousCache<T>::takeFirst() +{ T t = first(); removeFirst(); return t; } + +template <typename T> +inline T QContiguousCache<T>::takeLast() +{ T t = last(); removeLast(); return t; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 21d98b5..2313e0e 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -379,6 +379,107 @@ void QHashData::checkSanity() #endif /*! + \fn uint qHash(const QPair<T1, T2> &key) + \since 4.3 + \relates QHash + + Returns the hash value for the \a key. + + Types \c T1 and \c T2 must be supported by qHash(). +*/ + +/*! \fn uint qHash(char key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(uchar key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(signed char key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(ushort key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(short key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(uint key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(int key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(ulong key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(long key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(quint64 key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(qint64 key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(QChar key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(const QByteArray &key) + \fn uint qHash(const QBitArray &key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(const QString &key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \fn uint qHash(const T *key) + \relates QHash + + Returns the hash value for the \a key. +*/ + +/*! \class QHash \brief The QHash class is a template class that provides a hash-table-based dictionary. @@ -401,7 +502,8 @@ void QHashData::checkSanity() key. With QHash, the items are arbitrarily ordered. \i The key type of a QMap must provide operator<(). The key type of a QHash must provide operator==() and a global - \l{qHash()}{qHash}(Key) function. + hash function called qHash() (see the related non-member + functions). \endlist Here's an example QHash with QString keys and \c int values: @@ -732,7 +834,6 @@ void QHashData::checkSanity() */ /*! \fn const T QHash::value(const Key &key, const T &defaultValue) const - \overload If the hash contains no item with the given \a key, the function returns @@ -1490,121 +1591,6 @@ void QHashData::checkSanity() \sa operator+=(), operator-() */ -/*! \fn uint qHash(char key) - \relates QHash - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(uchar key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(signed char key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(ushort key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(short key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(uint key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(int key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(ulong key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(long key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(quint64 key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(qint64 key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(QChar key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(const QByteArray &key) - \fn uint qHash(const QBitArray &key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(const QString &key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! \fn uint qHash(const T *key) - \relates QHash - \overload - - Returns the hash value for the \a key. -*/ - -/*! - \fn uint qHash(const QPair<T1, T2> &key) - \relates QHash - \since 4.3 - - Returns the hash value for the \a key. - - Types \c T1 and \c T2 must be supported by qHash(). -*/ - /*! \fn QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash) \relates QHash diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h index eed4ba9..02cc497 100644 --- a/src/corelib/tools/qringbuffer_p.h +++ b/src/corelib/tools/qringbuffer_p.h @@ -74,6 +74,52 @@ public: return buffers.isEmpty() ? 0 : (buffers.first().constData() + head); } + // access the bytes at a specified position + // the out-variable length will contain the amount of bytes readable + // from there, e.g. the amount still the same QByteArray + inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const { + if (buffers.isEmpty()) { + length = 0; + return 0; + } + + if (pos >= bufferSize) { + length = 0; + return 0; + } + + // special case: it is in the first buffer + int nextDataBlockSizeValue = nextDataBlockSize(); + if (pos - head < nextDataBlockSizeValue) { + length = nextDataBlockSizeValue - pos; + return buffers.at(0).constData() + head + pos; + } + + // special case: we only had one buffer and tried to read over it + if (buffers.length() == 1) { + length = 0; + return 0; + } + + // skip the first + pos -= nextDataBlockSizeValue; + + // normal case: it is somewhere in the second to the-one-before-the-tailBuffer + for (int i = 1; i < tailBuffer; i++) { + if (pos >= buffers[i].size()) { + pos -= buffers[i].size(); + continue; + } + + length = buffers[i].length() - pos; + return buffers[i].constData() + pos; + } + + // it is in the tail buffer + length = tail - pos; + return buffers[tailBuffer].constData() + pos; + } + inline void free(int bytes) { bufferSize -= bytes; if (bufferSize < 0) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 375d672..c3649e3 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -743,7 +743,9 @@ int QString::grow(int size) /*! \since 4.2 - Returns a copy of the \a string string encoded in ucs4. + Returns a copy of the \a string, where the encoding of \a string depends on + the size of wchar. If wchar is 4 bytes, the \a string is interpreted as ucs-4, + if wchar is 2 bytes it is interpreted as ucs-2. If \a size is -1 (default), the \a string has to be 0 terminated. diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index 78ce7bd..ee4f73c 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -211,7 +211,9 @@ void QTimeLinePrivate::setCurrentTime(int msecs) valueForTime() and emitting valueChanged(). By default, valueForTime() applies an interpolation algorithm to generate these value. You can choose from a set of predefined timeline algorithms by calling - setCurveShape(). By default, QTimeLine uses the EaseInOut curve shape, + setCurveShape(). + + Note that by default, QTimeLine uses the EaseInOut curve shape, which provides a value that grows slowly, then grows steadily, and finally grows slowly. For a custom timeline, you can reimplement valueForTime(), in which case QTimeLine's curveShape property is ignored. diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 41557f0..2a1c1fc 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -20,6 +20,7 @@ HEADERS += \ tools/qlocale_p.h \ tools/qlocale_data_p.h \ tools/qmap.h \ + tools/qcontiguouscache.h \ tools/qpodlist_p.h \ tools/qpoint.h \ tools/qqueue.h \ @@ -55,6 +56,7 @@ SOURCES += \ tools/qlocale.cpp \ tools/qpoint.cpp \ tools/qmap.cpp \ + tools/qcontiguouscache.cpp \ tools/qrect.cpp \ tools/qregexp.cpp \ tools/qshareddata.cpp \ diff --git a/src/declarative/3rdparty/qlistmodelinterface.h b/src/declarative/3rdparty/qlistmodelinterface.h index 19284ca..44c4a24 100644 --- a/src/declarative/3rdparty/qlistmodelinterface.h +++ b/src/declarative/3rdparty/qlistmodelinterface.h @@ -42,9 +42,9 @@ #ifndef QLISTMODELINTERFACE_H #define QLISTMODELINTERFACE_H -#include <QHash> -#include <QVariant> -#include <qfxglobal.h> +#include <QtCore/QHash> +#include <QtCore/QVariant> +#include <QtDeclarative/qfxglobal.h> QT_BEGIN_HEADER diff --git a/src/declarative/canvas/qsimplecanvas.cpp b/src/declarative/canvas/qsimplecanvas.cpp index e1dd0e8..cd50945 100644 --- a/src/declarative/canvas/qsimplecanvas.cpp +++ b/src/declarative/canvas/qsimplecanvas.cpp @@ -621,8 +621,10 @@ QSimpleCanvas::~QSimpleCanvas() void QSimpleCanvasPrivate::paint(QPainter &p) { #if defined(QFX_RENDER_QPAINTER) - if (!isSetup) + if (!isSetup) { + ++paintVersion; root->d_func()->setupPainting(0, q->rect()); + } lrpTimer.start(); @@ -920,6 +922,7 @@ bool QSimpleCanvas::event(QEvent *e) unsigned int zero = 0; d->root->d_func()->setupPainting(0, rect(), &zero); #else + ++d->paintVersion; d->root->d_func()->setupPainting(0, rect()); #endif diff --git a/src/declarative/canvas/qsimplecanvas.h b/src/declarative/canvas/qsimplecanvas.h index d57ada4..880fae0 100644 --- a/src/declarative/canvas/qsimplecanvas.h +++ b/src/declarative/canvas/qsimplecanvas.h @@ -42,7 +42,7 @@ #ifndef QSIMPLECANVAS_H #define QSIMPLECANVAS_H -#include <qfxglobal.h> +#include <QtDeclarative/qfxglobal.h> #ifdef QFX_RENDER_OPENGL #include <QtGui/qmatrix4x4.h> diff --git a/src/declarative/canvas/qsimplecanvas_p.h b/src/declarative/canvas/qsimplecanvas_p.h index 7bc7330..9c3408e 100644 --- a/src/declarative/canvas/qsimplecanvas_p.h +++ b/src/declarative/canvas/qsimplecanvas_p.h @@ -112,6 +112,7 @@ public: #if defined(QFX_RENDER_OPENGL) ,egl(q, this), basicShadersInstance(0) #endif + , paintVersion(1) { } @@ -190,6 +191,7 @@ public: void release(QGLFramebufferObject *); void paintGL(); #endif + int paintVersion; }; #endif diff --git a/src/declarative/canvas/qsimplecanvas_software.cpp b/src/declarative/canvas/qsimplecanvas_software.cpp index 194024d..dd5e201 100644 --- a/src/declarative/canvas/qsimplecanvas_software.cpp +++ b/src/declarative/canvas/qsimplecanvas_software.cpp @@ -41,6 +41,7 @@ #include "qsimplecanvas.h" #include "qsimplecanvasitem_p.h" +#include "qsimplecanvas_p.h" QT_BEGIN_NAMESPACE @@ -48,57 +49,87 @@ QRect QSimpleCanvasItemPrivate::setupPainting(int version, const QRect &bounding { Q_Q(QSimpleCanvasItem); - QRectF boundingRectActive = q->boundingRect(); - QRect rv = - data()->transformActive.mapRect(boundingRectActive).toAlignedRect() & bounding; + bool hasContents = options & QSimpleCanvasItem::HasContents; + + QRect rv; + + if (hasContents || q->clip()) { + QRectF boundingRectActive = q->boundingRect(); + rv = data()->transformActive.mapRect(boundingRectActive).toAlignedRect() & bounding; + } + + data()->doNotPaint = rv.isEmpty(); + data()->doNotPaintChildren = data()->doNotPaint && q->clip(); QRect myBounding = bounding; if (q->clip()) myBounding &= rv; - for (int ii = 0; ii < children.count(); ++ii) { - QSimpleCanvasItem *child = children.at(ii); - - qreal visible = child->visible(); - child->d_func()->data()->activeOpacity = data()->activeOpacity; - if (visible != 1) - child->d_func()->data()->activeOpacity *= visible; - - if (child->d_func()->data()->activeOpacity != 0) { - // Calculate child's transform - qreal x = child->x(); - qreal y = child->y(); - qreal scale = child->scale(); - QSimpleCanvasItem::Flip flip = child->flip(); - - QSimpleCanvas::Matrix &am = child->d_func()->data()->transformActive; - am = data()->transformActive; - if (x != 0 || y != 0) - am.translate(x, y); - if (scale != 1) { - QPointF to = child->d_func()->transformOrigin(); - if (to.x() != 0. || to.y() != 0.) - am.translate(to.x(), to.y()); - am.scale(scale, scale); - if (to.x() != 0. || to.y() != 0.) - am.translate(-to.x(), -to.y()); - } - - if (child->d_func()->data()->transformUser) - am = *child->d_func()->data()->transformUser * am; + if (!data()->doNotPaintChildren) { + for (int ii = 0; ii < children.count(); ++ii) { + QSimpleCanvasItem *child = children.at(ii); + + int childVersion = version; + if (!child->d_func()->data()->transformValid) + childVersion = canvas->d->paintVersion; + + bool recalcNeeded = + (childVersion > child->d_func()->data()->transformVersion); + + if (recalcNeeded) { + qreal visible = child->visible(); + child->d_func()->data()->activeOpacity = data()->activeOpacity; + if (visible != 1) + child->d_func()->data()->activeOpacity *= visible; + } + + if (child->d_func()->data()->activeOpacity != 0) { + if (recalcNeeded) { + // Calculate child's transform + qreal x = child->x(); + qreal y = child->y(); + qreal scale = child->scale(); + QSimpleCanvasItem::Flip flip = child->flip(); + + QSimpleCanvas::Matrix &am = + child->d_func()->data()->transformActive; + am = data()->transformActive; + if (x != 0 || y != 0) + am.translate(x, y); + if (scale != 1) { + QPointF to = child->d_func()->transformOrigin(); + if (to.x() != 0. || to.y() != 0.) + am.translate(to.x(), to.y()); + am.scale(scale, scale); + if (to.x() != 0. || to.y() != 0.) + am.translate(-to.x(), -to.y()); + } + + if (child->d_func()->data()->transformUser) + am = *child->d_func()->data()->transformUser * am; + + if (flip) { + QRectF br = child->boundingRect(); + am.translate(br.width() / 2., br.height() / 2); + am.scale((flip & QSimpleCanvasItem::HorizontalFlip)?-1:1, + (flip & QSimpleCanvasItem::VerticalFlip)?-1:1); + am.translate(-br.width() / 2., -br.height() / 2); + } + child->d_func()->data()->transformValid = true; + child->d_func()->data()->transformVersion = childVersion; + } + rv |= child->d_func()->setupPainting(child->d_func()->data()->transformVersion, myBounding); + } + } + } - if (flip) { - QRectF br = child->boundingRect(); - am.translate(br.width() / 2., br.height() / 2); - am.scale((flip & QSimpleCanvasItem::HorizontalFlip)?-1:1, - (flip & QSimpleCanvasItem::VerticalFlip)?-1:1); - am.translate(-br.width() / 2., -br.height() / 2); - } - child->d_func()->data()->transformValid = true; - rv |= child->d_func()->setupPainting(version, myBounding); + data()->lastPaintRect = rv; + if (!data()->doNotPaintChildren) { + if (!bounding.intersects(rv)) { + data()->doNotPaintChildren = true; + data()->doNotPaint = true; } } - - data()->lastPaintRect = rv; + return rv; } @@ -153,22 +184,28 @@ void QSimpleCanvasItemPrivate::paint(QPainter &p) zOrderChildren(); int upto = 0; - for (upto = 0; upto < children.count(); ++upto) { - QSimpleCanvasItem *c = children.at(upto); - if (c->z() < 0) { - paintChild(p, c); - } else { - break; + if (!data()->doNotPaintChildren) { + for (upto = 0; upto < children.count(); ++upto) { + QSimpleCanvasItem *c = children.at(upto); + if (c->z() < 0) { + paintChild(p, c); + } else { + break; + } } } - p.setWorldTransform(data()->transformActive); - q->paintContents(p); - - for (; upto < children.count(); ++upto) { - QSimpleCanvasItem *c = children.at(upto); - paintChild(p, c); - } + if (!data()->doNotPaint) { + p.setWorldTransform(data()->transformActive); + q->paintContents(p); + } + + if (!data()->doNotPaintChildren) { + for (; upto < children.count(); ++upto) { + QSimpleCanvasItem *c = children.at(upto); + paintChild(p, c); + } + } if (clip) p.restore(); diff --git a/src/declarative/canvas/qsimplecanvasfilter.h b/src/declarative/canvas/qsimplecanvasfilter.h index cb75ddf..d05dc7e 100644 --- a/src/declarative/canvas/qsimplecanvasfilter.h +++ b/src/declarative/canvas/qsimplecanvasfilter.h @@ -43,9 +43,9 @@ #define QSIMPLECANVASFILTER_H #include <QtCore/qobject.h> -#include <qfxglobal.h> -#include <qsimplecanvasitem.h> -#include <qsimplecanvas.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qsimplecanvasitem.h> +#include <QtDeclarative/qsimplecanvas.h> QT_BEGIN_HEADER diff --git a/src/declarative/canvas/qsimplecanvasitem.cpp b/src/declarative/canvas/qsimplecanvasitem.cpp index 12c725c..3666b82 100644 --- a/src/declarative/canvas/qsimplecanvasitem.cpp +++ b/src/declarative/canvas/qsimplecanvasitem.cpp @@ -50,8 +50,9 @@ QT_BEGIN_NAMESPACE QSimpleCanvasItemData::QSimpleCanvasItemData() : buttons(Qt::NoButton), flip(QSimpleCanvasItem::NoFlip), - dirty(false), transformValid(true), x(0), y(0), z(0), visible(1), - transformUser(0), activeOpacity(1) + dirty(false), transformValid(true), doNotPaint(false), + doNotPaintChildren(false), x(0), y(0), z(0), visible(1), + transformUser(0), transformVersion(0), activeOpacity(1) { } @@ -180,10 +181,18 @@ void QSimpleCanvasItem::childrenChanged() { } +void QSimpleCanvasItem::setPaintMargin(qreal margin) +{ + Q_D(QSimpleCanvasItem); + if (margin < d->paintmargin) + update(); // schedule repaint of old boundingRect + d->paintmargin = margin; +} + QRectF QSimpleCanvasItem::boundingRect() const { Q_D(const QSimpleCanvasItem); - return QRectF(0., 0., d->width, d->height); + return QRectF(-d->paintmargin, -d->paintmargin, d->width+d->paintmargin*2, d->height+d->paintmargin*2); } void QSimpleCanvasItem::paintContents(QPainter &) @@ -934,8 +943,6 @@ QRectF QSimpleCanvasItem::mapToScene(const QRectF &r) const } } -int QSimpleCanvasItemPrivate::nextTransformVersion = 1; - void QSimpleCanvasItemPrivate::freshenTransforms() const { if (freshenNeeded()) @@ -1506,11 +1513,8 @@ void QSimpleCanvasItemPrivate::convertToGraphicsItem(QGraphicsItem *parent) q->setClipType(clip); - for (int ii = 0; ii < children.count(); ++ii) { + for (int ii = 0; ii < children.count(); ++ii) static_cast<QSimpleCanvasItemPrivate*>(children.at(ii)->d_ptr)->convertToGraphicsItem(graphicsItem); - if (children.at(ii)->z() == 0) - children.at(ii)->setZ(ii); - } } /*! diff --git a/src/declarative/canvas/qsimplecanvasitem.h b/src/declarative/canvas/qsimplecanvasitem.h index cab8492..cf23fc6 100644 --- a/src/declarative/canvas/qsimplecanvasitem.h +++ b/src/declarative/canvas/qsimplecanvasitem.h @@ -47,13 +47,13 @@ #include <QtDeclarative/qsimplecanvas.h> #include <QtCore/qobject.h> #include <QtGui/qgraphicsitem.h> -class QPainter; QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Declarative) +class QPainter; class QRect; class QSimpleCanvas; class QMouseEvent; @@ -183,6 +183,7 @@ public: }; + void setPaintMargin(qreal margin); QRectF boundingRect() const; virtual void paintContents(QPainter &); virtual void paintGLContents(GLPainter &); diff --git a/src/declarative/canvas/qsimplecanvasitem_p.h b/src/declarative/canvas/qsimplecanvasitem_p.h index cfe0bba..f0b44e0 100644 --- a/src/declarative/canvas/qsimplecanvasitem_p.h +++ b/src/declarative/canvas/qsimplecanvasitem_p.h @@ -92,6 +92,8 @@ public: QSimpleCanvasItem::Flip flip:2; bool dirty:1; bool transformValid:1; + bool doNotPaint:1; + bool doNotPaintChildren:1; qreal x; qreal y; @@ -100,6 +102,7 @@ public: QSimpleCanvas::Matrix *transformUser; QSimpleCanvas::Matrix transformActive; + int transformVersion; float activeOpacity; @@ -139,7 +142,7 @@ public: focusable(false), wantsActiveFocusPanelPendingCanvas(false), hasBeenActiveFocusPanel(false), hasFocus(false), hasActiveFocus(false), needsZOrder(false), - widthValid(false), heightValid(false), width(0), height(0), scale(1), + widthValid(false), heightValid(false), width(0), height(0), paintmargin(0), scale(1), graphicsItem(0), data_ptr(0) { } @@ -173,6 +176,7 @@ public: qreal width; qreal height; + qreal paintmargin; qreal scale; QSimpleGraphicsItem *graphicsItem; @@ -236,7 +240,6 @@ public: #endif void zOrderChildren(); - static int nextTransformVersion; bool freshenNeeded() const; void doFreshenTransforms() const; diff --git a/src/declarative/extra/qfxintegermodel.h b/src/declarative/extra/qfxintegermodel.h index 3a48a56..2f5c756 100644 --- a/src/declarative/extra/qfxintegermodel.h +++ b/src/declarative/extra/qfxintegermodel.h @@ -42,9 +42,9 @@ #ifndef QFXINTMODEL_H #define QFXINTMODEL_H -#include <QObject> -#include "qml.h" -#include <qlistmodelinterface.h> +#include <QtCore/QObject> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qlistmodelinterface.h> QT_BEGIN_HEADER diff --git a/src/declarative/extra/qmlnumberformatter.h b/src/declarative/extra/qmlnumberformatter.h index e053be5..cdd6b58 100644 --- a/src/declarative/extra/qmlnumberformatter.h +++ b/src/declarative/extra/qmlnumberformatter.h @@ -42,8 +42,8 @@ #ifndef QMLNUMBERFORMATTER_H #define QMLNUMBERFORMATTER_H -#include <qml.h> -#include "qnumberformat.h" +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qnumberformat.h> QT_BEGIN_HEADER diff --git a/src/declarative/extra/qmlsqlconnection.h b/src/declarative/extra/qmlsqlconnection.h index 2cc5774..0fff1b0 100644 --- a/src/declarative/extra/qmlsqlconnection.h +++ b/src/declarative/extra/qmlsqlconnection.h @@ -42,8 +42,8 @@ #ifndef QMLSQLCONNECTION_H #define QMLSQLCONNECTION_H -#include <qml.h> -#include <QSqlDatabase> +#include <QtDeclarative/qml.h> +#include <QtSql/QSqlDatabase> QT_BEGIN_HEADER diff --git a/src/declarative/extra/qmlsqlquery.h b/src/declarative/extra/qmlsqlquery.h index 984483c..3fff127 100644 --- a/src/declarative/extra/qmlsqlquery.h +++ b/src/declarative/extra/qmlsqlquery.h @@ -42,8 +42,8 @@ #ifndef QMLSQLQUERYMODEL_H #define QMLSQLQUERYMODEL_H -#include <qml.h> -#include <QListModelInterface> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/QListModelInterface> QT_BEGIN_HEADER diff --git a/src/declarative/extra/qmlxmllistmodel.h b/src/declarative/extra/qmlxmllistmodel.h index 1fbe923..f837040 100644 --- a/src/declarative/extra/qmlxmllistmodel.h +++ b/src/declarative/extra/qmlxmllistmodel.h @@ -42,8 +42,8 @@ #ifndef QMLXMLLISTMODEL_H #define QMLXMLLISTMODEL_H -#include <qml.h> -#include <QListModelInterface> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/QListModelInterface> QT_BEGIN_HEADER diff --git a/src/declarative/extra/qnumberformat.h b/src/declarative/extra/qnumberformat.h index 6ee333c..75224ec 100644 --- a/src/declarative/extra/qnumberformat.h +++ b/src/declarative/extra/qnumberformat.h @@ -42,9 +42,9 @@ #ifndef NUMBERFORMAT_H #define NUMBERFORMAT_H -#include "qml.h" -#include <QtGui> - +#include <QtDeclarative/qml.h> +#include <QtCore/QLocale> +#include <QtCore/QTime> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxanchors.cpp b/src/declarative/fx/qfxanchors.cpp index 53d0187..235511f 100644 --- a/src/declarative/fx/qfxanchors.cpp +++ b/src/declarative/fx/qfxanchors.cpp @@ -41,6 +41,7 @@ #include "qfxanchors_p.h" #include "qfxitem.h" +#include "qfxitem_p.h" #include <QDebug> #include <QtDeclarative/qmlinfo.h> #include <QtDeclarative/qmlbindablevalue.h> @@ -132,22 +133,175 @@ static qreal adjustedPosition(QFxItem *item, QFxAnchorLine::AnchorLine anchorLin QFxAnchors::QFxAnchors(QObject *parent) : QObject(*new QFxAnchorsPrivate(), parent) { - } -void QFxAnchors::fillChanged() +QFxAnchors::~QFxAnchors() { Q_D(QFxAnchors); - if (!d->fill) + d->remDepend(d->fill); + d->remDepend(d->centeredIn); + d->remDepend(d->left.item); + d->remDepend(d->right.item); + d->remDepend(d->top.item); + d->remDepend(d->bottom.item); + d->remDepend(d->vCenter.item); + d->remDepend(d->hCenter.item); +} + +void QFxAnchorsPrivate::fillChanged() +{ + if (!fill || !isItemComplete()) + return; + + if (fill == item->itemParent()) { //child-parent + setItemPos(QPointF(leftMargin, topMargin)); + } else if (fill->itemParent() == item->itemParent()) { //siblings + setItemPos(QPointF(fill->x()+leftMargin, fill->y()+topMargin)); + } + setItemWidth(fill->width()-leftMargin-rightMargin); + setItemHeight(fill->height()-topMargin-bottomMargin); +} + +void QFxAnchorsPrivate::centeredInChanged() +{ + if (!centeredIn || fill || !isItemComplete()) return; - if (d->fill == d->item->itemParent()) { //child-parent - d->item->setPos(QPointF(leftMargin(), topMargin())); - } else if (d->fill->itemParent() == d->item->itemParent()) { //siblings - d->item->setPos(QPointF(d->fill->x()+leftMargin(), d->fill->y()+topMargin())); + if (centeredIn == item->itemParent()) { + QPointF p((item->itemParent()->width() - item->width()) / 2., + (item->itemParent()->height() - item->height()) / 2.); + setItemPos(p); + + } else if (centeredIn->itemParent() == item->itemParent()) { + + QPointF p(centeredIn->x() + (centeredIn->width() - item->width()) / 2., + centeredIn->y() + (centeredIn->height() - item->height()) / 2.); + setItemPos(p); + } +} + +void QFxAnchorsPrivate::clearItem(QFxItem *item) +{ + if (fill == item) + fill = 0; + if (centeredIn == item) + centeredIn = 0; + if (left.item == item) { + left.item = 0; + usedAnchors &= ~QFxAnchors::HasLeftAnchor; + } + if (right.item == item) { + right.item = 0; + usedAnchors &= ~QFxAnchors::HasRightAnchor; + } + if (top.item == item) { + top.item = 0; + usedAnchors &= ~QFxAnchors::HasTopAnchor; + } + if (bottom.item == item) { + bottom.item = 0; + usedAnchors &= ~QFxAnchors::HasBottomAnchor; + } + if (vCenter.item == item) { + vCenter.item = 0; + usedAnchors &= ~QFxAnchors::HasVCenterAnchor; + } + if (hCenter.item == item) { + hCenter.item = 0; + usedAnchors &= ~QFxAnchors::HasHCenterAnchor; + } +} + +void QFxAnchorsPrivate::addDepend(QFxItem *item) +{ + Q_Q(QFxAnchors); + if (!item) + return; + QFxItemPrivate *p = + static_cast<QFxItemPrivate *>(QObjectPrivate::get(item)); + p->dependantAnchors.append(q); +} + +void QFxAnchorsPrivate::remDepend(QFxItem *item) +{ + Q_Q(QFxAnchors); + if (!item) + return; + QFxItemPrivate *p = + static_cast<QFxItemPrivate *>(QObjectPrivate::get(item)); + p->dependantAnchors.removeAll(q); +} + +bool QFxAnchorsPrivate::isItemComplete() const +{ + return item->isComponentComplete(); +} + +void QFxAnchorsPrivate::setItemHeight(qreal v) +{ + updatingMe = true; + item->setHeight(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::setItemWidth(qreal v) +{ + updatingMe = true; + item->setWidth(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::setItemX(qreal v) +{ + updatingMe = true; + item->setX(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::setItemY(qreal v) +{ + updatingMe = true; + item->setY(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::setItemPos(const QPointF &v) +{ + updatingMe = true; + item->setPos(v); + updatingMe = false; +} + +void QFxAnchorsPrivate::updateMe() +{ + if (updatingMe) { + updatingMe = false; + return; } - d->item->setWidth(d->fill->width()-leftMargin()-rightMargin()); - d->item->setHeight(d->fill->height()-topMargin()-bottomMargin()); + + fillChanged(); + centeredInChanged(); + updateHorizontalAnchors(); + updateVerticalAnchors(); +} + +void QFxAnchorsPrivate::updateOnComplete() +{ + fillChanged(); + centeredInChanged(); + updateHorizontalAnchors(); + updateVerticalAnchors(); +} + +void QFxAnchorsPrivate::update(QFxItem *, const QRectF &newG, const QRectF &oldG) +{ + fillChanged(); + centeredInChanged(); + + if (newG.x() != oldG.x() || newG.width() != oldG.width()) + updateHorizontalAnchors(); + if (newG.y() != oldG.y() || newG.height() != oldG.height()) + updateVerticalAnchors(); } /*! @@ -166,37 +320,11 @@ QFxItem *QFxAnchors::fill() const void QFxAnchors::setFill(QFxItem *f) { Q_D(QFxAnchors); - if (d->fill) { - QObject::disconnect(d->fill, SIGNAL(leftChanged()), this, SLOT(fillChanged())); - QObject::disconnect(d->fill, SIGNAL(topChanged()), this, SLOT(fillChanged())); - QObject::disconnect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged())); - QObject::disconnect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged())); - QObject::disconnect(this, SIGNAL(leftMarginChanged()), this, SLOT(fillChanged())); - QObject::disconnect(this, SIGNAL(topMarginChanged()), this, SLOT(fillChanged())); - QObject::disconnect(this, SIGNAL(rightMarginChanged()), this, SLOT(fillChanged())); - QObject::disconnect(this, SIGNAL(bottomMarginChanged()), this, SLOT(fillChanged())); - } - + d->remDepend(d->fill); d->fill = f; + d->addDepend(d->fill); - if (d->fill) { - if (d->fill == d->item->itemParent()) { //child-parent - QObject::connect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged())); - QObject::connect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged())); - } else if (f->itemParent() == d->item->itemParent()) { //siblings - QObject::connect(d->fill, SIGNAL(leftChanged()), this, SLOT(fillChanged())); - QObject::connect(d->fill, SIGNAL(topChanged()), this, SLOT(fillChanged())); - QObject::connect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged())); - QObject::connect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged())); - } else { - qmlInfo(d->item) << "Can't anchor to an item that isn't a parent or sibling."; - } - } - QObject::connect(this, SIGNAL(leftMarginChanged()), this, SLOT(fillChanged())); - QObject::connect(this, SIGNAL(topMarginChanged()), this, SLOT(fillChanged())); - QObject::connect(this, SIGNAL(rightMarginChanged()), this, SLOT(fillChanged())); - QObject::connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(fillChanged())); - fillChanged(); //### can/should we defer until component completion? + d->fillChanged(); } /*! @@ -223,163 +351,12 @@ void QFxAnchors::setCenteredIn(QFxItem* c) qmlInfo(d->item) << "Can't anchor to an item that isn't a parent or sibling."; return; } - d->centeredIn = c; - setHorizontalCenter(c->horizontalCenter()); - setVerticalCenter(c->verticalCenter()); -} - -void QFxAnchorsPrivate::connectVHelper(const QFxAnchorLine &edge) -{ - //### should we do disconnects first? (will it be called more than once?) - Q_Q(QFxAnchors); - if (edge.item == item->itemParent()) { //child-parent - switch(edge.anchorLine) { - case QFxAnchorLine::Bottom: - case QFxAnchorLine::VCenter: - QObject::connect(edge.item, SIGNAL(heightChanged()), q, SLOT(updateVerticalAnchors())); - break; - case QFxAnchorLine::Top: //no connection needed - default: - break; - } - } else if (edge.item->itemParent() == item->itemParent()) { //siblings - switch(edge.anchorLine) { - case QFxAnchorLine::Top: - QObject::connect(edge.item, SIGNAL(topChanged()), q, SLOT(updateVerticalAnchors())); - break; - case QFxAnchorLine::Bottom: - QObject::connect(edge.item, SIGNAL(bottomChanged()), q, SLOT(updateVerticalAnchors())); - break; - case QFxAnchorLine::VCenter: - QObject::connect(edge.item, SIGNAL(vcenterChanged()), q, SLOT(updateVerticalAnchors())); - break; - default: - break; - } - } else { - qmlInfo(item) << "Can't anchor to an item that isn't a parent or sibling."; - } -} - -void QFxAnchors::connectVAnchors() -{ - Q_D(QFxAnchors); - if (!d->checkVValid()) - return; - - if (d->usedAnchors & HasTopAnchor) { - //Handle stretching connections (if we have multiple horizontal anchors) - QFxAnchorLine *edge = 0; - if (d->usedAnchors & HasBottomAnchor) { - edge = &d->bottom; - connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); - } else if (d->usedAnchors & HasVCenterAnchor) { - edge = &d->vCenter; - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); - } - if (edge) { - //we need to stretch - d->connectVHelper(*edge); - } - - //Handle top - d->connectVHelper(d->top); - connect(this, SIGNAL(topMarginChanged()), this, SLOT(updateVerticalAnchors())); - updateVerticalAnchors(); - } else if (d->usedAnchors & HasBottomAnchor) { - //Handle stretching connections (if we have multiple horizontal anchors) - if (d->usedAnchors & HasVCenterAnchor) { - d->connectVHelper(d->vCenter); - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); - } - - //Handle bottom - d->connectVHelper(d->bottom); - connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); - updateVerticalAnchors(); - } else if (d->usedAnchors & HasVCenterAnchor) { - //Handle vCenter - d->connectVHelper(d->vCenter); - connect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); - updateVerticalAnchors(); - } -} - -void QFxAnchorsPrivate::connectHHelper(const QFxAnchorLine &edge) -{ - //### should we do disconnects first? (will it be called more than once?) - Q_Q(QFxAnchors); - if (edge.item == item->itemParent()) { //child-parent - switch(edge.anchorLine) { - case QFxAnchorLine::Right: - case QFxAnchorLine::HCenter: - QObject::connect(edge.item, SIGNAL(widthChanged()), q, SLOT(updateHorizontalAnchors())); - break; - case QFxAnchorLine::Left: //no connection needed - default: - break; - } - } else if (edge.item->itemParent() == item->itemParent()) { //siblings - switch(edge.anchorLine) { - case QFxAnchorLine::Left: - QObject::connect(edge.item, SIGNAL(leftChanged()), q, SLOT(updateHorizontalAnchors())); - break; - case QFxAnchorLine::Right: - QObject::connect(edge.item, SIGNAL(rightChanged()), q, SLOT(updateHorizontalAnchors())); - break; - case QFxAnchorLine::HCenter: - QObject::connect(edge.item, SIGNAL(hcenterChanged()), q, SLOT(updateHorizontalAnchors())); - break; - default: - break; - } - } else { - qmlInfo(item) << "Can't anchor to an item that isn't a parent or sibling."; - } -} - -void QFxAnchors::connectHAnchors() -{ - Q_D(QFxAnchors); - if (!d->checkHValid()) - return; - - if (d->usedAnchors & HasLeftAnchor) { - //Handle stretching connections (if we have multiple horizontal anchors) - QFxAnchorLine *edge = 0; - if (d->usedAnchors & HasRightAnchor) { - edge = &d->right; - connect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); - } else if (d->usedAnchors & HasHCenterAnchor) { - edge = &d->hCenter; - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); - } - if (edge) { - //we need to stretch - d->connectHHelper(*edge); - } - //Handle left - d->connectHHelper(d->left); - connect(this, SIGNAL(leftMarginChanged()), this, SLOT(updateHorizontalAnchors())); - updateHorizontalAnchors(); - } else if (d->usedAnchors & HasRightAnchor) { - //Handle stretching connections (if we have multiple horizontal anchors) - if (d->usedAnchors & HasHCenterAnchor) { - d->connectHHelper(d->hCenter); - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); - } + d->remDepend(d->centeredIn); + d->centeredIn = c; + d->addDepend(d->centeredIn); - //Handle right - d->connectHHelper(d->right); - connect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); - updateHorizontalAnchors(); - } else if (d->usedAnchors & HasHCenterAnchor) { - //Handle hCenter - d->connectHHelper(d->hCenter); - connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); - updateHorizontalAnchors(); - } + d->centeredInChanged(); } bool QFxAnchorsPrivate::calcStretch(const QFxAnchorLine &edge1, @@ -411,168 +388,124 @@ bool QFxAnchorsPrivate::calcStretch(const QFxAnchorLine &edge1, return invalid; } -void QFxAnchors::updateVerticalAnchors() +void QFxAnchorsPrivate::updateVerticalAnchors() { - Q_D(QFxAnchors); - if (!d->updatingVerticalAnchor) { - d->updatingVerticalAnchor = true; - if (d->usedAnchors & HasTopAnchor) { + if (fill || centeredIn || !isItemComplete()) + return; + + if (!updatingVerticalAnchor) { + updatingVerticalAnchor = true; + if (usedAnchors & QFxAnchors::HasTopAnchor) { //Handle stretching bool invalid = true; int height = 0; - if (d->usedAnchors & HasBottomAnchor) { - invalid = d->calcStretch(d->top, d->bottom, d->topMargin, -d->bottomMargin, QFxAnchorLine::Top, height); - } else if (d->usedAnchors & HasVCenterAnchor) { - invalid = d->calcStretch(d->top, d->vCenter, d->topMargin, d->vCenterOffset, QFxAnchorLine::Top, height); + if (usedAnchors & QFxAnchors::HasBottomAnchor) { + invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QFxAnchorLine::Top, height); + } else if (usedAnchors & QFxAnchors::HasVCenterAnchor) { + invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QFxAnchorLine::Top, height); height *= 2; } if (!invalid) - d->item->setHeight(height); + setItemHeight(height); //Handle top - if (d->top.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->top.item, d->top.anchorLine) + d->topMargin); - } else if (d->top.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->top.item, d->top.anchorLine) + d->topMargin); + if (top.item == item->itemParent()) { + setItemY(adjustedPosition(top.item, top.anchorLine) + topMargin); + } else if (top.item->itemParent() == item->itemParent()) { + setItemY(position(top.item, top.anchorLine) + topMargin); } - } else if (d->usedAnchors & HasBottomAnchor) { + } else if (usedAnchors & QFxAnchors::HasBottomAnchor) { //Handle stretching (top + bottom case is handled above) - if (d->usedAnchors & HasVCenterAnchor) { + if (usedAnchors & QFxAnchors::HasVCenterAnchor) { int height = 0; - bool invalid = d->calcStretch(d->vCenter, d->bottom, d->vCenterOffset, -d->bottomMargin, + bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin, QFxAnchorLine::Top, height); if (!invalid) - d->item->setHeight(height*2); + setItemHeight(height*2); } //Handle bottom - if (d->bottom.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); - } else if (d->bottom.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin); + if (bottom.item == item->itemParent()) { + setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - item->height() - bottomMargin); + } else if (bottom.item->itemParent() == item->itemParent()) { + setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin); } - } else if (d->usedAnchors & HasVCenterAnchor) { + } else if (usedAnchors & QFxAnchors::HasVCenterAnchor) { //(stetching handled above) //Handle vCenter - if (d->vCenter.item == d->item->itemParent()) { - d->item->setY(adjustedPosition(d->vCenter.item, d->vCenter.anchorLine) - - d->item->height()/2 + d->vCenterOffset); - } else if (d->vCenter.item->itemParent() == d->item->itemParent()) { - d->item->setY(position(d->vCenter.item, d->vCenter.anchorLine) - d->item->height()/2 + d->vCenterOffset); + if (vCenter.item == item->itemParent()) { + setItemY(adjustedPosition(vCenter.item, vCenter.anchorLine) + - item->height()/2 + vCenterOffset); + } else if (vCenter.item->itemParent() == item->itemParent()) { + setItemY(position(vCenter.item, vCenter.anchorLine) - item->height()/2 + vCenterOffset); } } - d->updatingVerticalAnchor = false; + updatingVerticalAnchor = false; } else { - qmlInfo(d->item) << "Anchor loop detected on vertical anchor."; + // ### Make this certain :) + qmlInfo(item) << "Possible anchor loop detected on vertical anchor."; } } -void QFxAnchors::updateHorizontalAnchors() +void QFxAnchorsPrivate::updateHorizontalAnchors() { - Q_D(QFxAnchors); - if (!d->updatingHorizontalAnchor) { - d->updatingHorizontalAnchor = true; + if (fill || centeredIn || !isItemComplete()) + return; - //alternate implementation (needs performance testing) - /*switch(d->usedAnchors & QFxAnchors::Horizontal_Mask) { - case 0x03: //(HasLeftAnchor | HasRightAnchor) - { - int width = 0; - if (!d->calcStretch(d->left, d->right, d->leftMargin, -d->rightMargin, QFxAnchorLine::Left, width)) - d->item->setWidth(width); - //fall though - } - case 0x11: //(HasLeftAnchor | HasHCenterAnchor) - { - if (d->usedAnchors & HasHCenterAnchor) { - int width = 0; - if (!d->calcStretch(d->left, d->hCenter, d->leftMargin, d->hCenterOffset, QFxAnchorLine::Left, width)) - d->item->setWidth(width*2); - } - //fall though - } - case HasLeftAnchor: - if (d->left.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->left.item, d->left.anchorLine) + d->leftMargin); - } else if (d->left.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin); - } - break; - case 0x12: //(HasRightAnchor | HasHCenterAnchor) - { - int width = 0; - if (!d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin, QFxAnchorLine::Left, width)) - d->item->setWidth(width*2); - //fall though - } - case HasRightAnchor: - if (d->right.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); - } else if (d->right.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); - } - break; - case HasHCenterAnchor: - if (d->hCenter.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); - } else if (d->hCenter.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); - } - break; - default: - break; - }*/ + if (!updatingHorizontalAnchor) { + updatingHorizontalAnchor = true; - if (d->usedAnchors & HasLeftAnchor) { + if (usedAnchors & QFxAnchors::HasLeftAnchor) { //Handle stretching bool invalid = true; int width = 0; - if (d->usedAnchors & HasRightAnchor) { - invalid = d->calcStretch(d->left, d->right, d->leftMargin, -d->rightMargin, QFxAnchorLine::Left, width); - } else if (d->usedAnchors & HasHCenterAnchor) { - invalid = d->calcStretch(d->left, d->hCenter, d->leftMargin, d->hCenterOffset, QFxAnchorLine::Left, width); + if (usedAnchors & QFxAnchors::HasRightAnchor) { + invalid = calcStretch(left, right, leftMargin, -rightMargin, QFxAnchorLine::Left, width); + } else if (usedAnchors & QFxAnchors::HasHCenterAnchor) { + invalid = calcStretch(left, hCenter, leftMargin, hCenterOffset, QFxAnchorLine::Left, width); width *= 2; } if (!invalid) - d->item->setWidth(width); + setItemWidth(width); //Handle left - if (d->left.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->left.item, d->left.anchorLine) + d->leftMargin); - } else if (d->left.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin); + if (left.item == item->itemParent()) { + setItemX(adjustedPosition(left.item, left.anchorLine) + leftMargin); + } else if (left.item->itemParent() == item->itemParent()) { + setItemX(position(left.item, left.anchorLine) + leftMargin); } - } else if (d->usedAnchors & HasRightAnchor) { + } else if (usedAnchors & QFxAnchors::HasRightAnchor) { //Handle stretching (left + right case is handled in updateLeftAnchor) - if (d->usedAnchors & HasHCenterAnchor) { + if (usedAnchors & QFxAnchors::HasHCenterAnchor) { int width = 0; - bool invalid = d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin, + bool invalid = calcStretch(hCenter, right, hCenterOffset, -rightMargin, QFxAnchorLine::Left, width); if (!invalid) - d->item->setWidth(width*2); + setItemWidth(width*2); } //Handle right - if (d->right.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); - } else if (d->right.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin); + if (right.item == item->itemParent()) { + setItemX(adjustedPosition(right.item, right.anchorLine) - item->width() - rightMargin); + } else if (right.item->itemParent() == item->itemParent()) { + setItemX(position(right.item, right.anchorLine) - item->width() - rightMargin); } - } else if (d->usedAnchors & HasHCenterAnchor) { + } else if (usedAnchors & QFxAnchors::HasHCenterAnchor) { //Handle hCenter - if (d->hCenter.item == d->item->itemParent()) { - d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); - } else if (d->hCenter.item->itemParent() == d->item->itemParent()) { - d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset); + if (hCenter.item == item->itemParent()) { + setItemX(adjustedPosition(hCenter.item, hCenter.anchorLine) - item->width()/2 + hCenterOffset); + } else if (hCenter.item->itemParent() == item->itemParent()) { + setItemX(position(hCenter.item, hCenter.anchorLine) - item->width()/2 + hCenterOffset); } } - d->updatingHorizontalAnchor = false; + updatingHorizontalAnchor = false; } else { - qmlInfo(d->item) << "Anchor loop detected on horizontal anchor."; + // ### Make this certain :) + qmlInfo(item) << "Possible anchor loop detected on horizontal anchor."; } } @@ -588,29 +521,22 @@ void QFxAnchors::setTop(const QFxAnchorLine &edge) if (!d->checkVAnchorValid(edge)) return; - d->usedAnchors |= HasTopAnchor; + if (edge.item) + d->usedAnchors |= HasTopAnchor; + else + d->usedAnchors &= ~HasTopAnchor; d->checkVValid(); + d->remDepend(d->top.item); d->top = edge; + d->addDepend(d->top.item); + d->updateVerticalAnchors(); } void QFxAnchors::resetTop() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasTopAnchor; - - //clear binding - QmlMetaProperty prop(this, "top"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(topMarginChanged()), this, SLOT(updateVerticalAnchors())); - disconnect(d->top.item, 0, this, 0); - - updateVerticalAnchors(); + setTop(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::bottom() const @@ -625,29 +551,22 @@ void QFxAnchors::setBottom(const QFxAnchorLine &edge) if (!d->checkVAnchorValid(edge)) return; - d->usedAnchors |= HasBottomAnchor; + if (edge.item) + d->usedAnchors |= HasBottomAnchor; + else + d->usedAnchors &= ~HasBottomAnchor; d->checkVValid(); + d->remDepend(d->bottom.item); d->bottom = edge; + d->addDepend(d->bottom.item); + d->updateVerticalAnchors(); } void QFxAnchors::resetBottom() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasBottomAnchor; - - //clear binding - QmlMetaProperty prop(this, "bottom"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(bottomMarginChanged()), this, SLOT(updateVerticalAnchors())); - disconnect(d->bottom.item, 0, this, 0); - - updateVerticalAnchors(); + setBottom(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::verticalCenter() const @@ -662,29 +581,22 @@ void QFxAnchors::setVerticalCenter(const QFxAnchorLine &edge) if (!d->checkVAnchorValid(edge)) return; - d->usedAnchors |= HasVCenterAnchor; + if (edge.item) + d->usedAnchors |= HasVCenterAnchor; + else + d->usedAnchors &= ~HasVCenterAnchor; d->checkVValid(); + d->remDepend(d->vCenter.item); d->vCenter = edge; + d->addDepend(d->vCenter.item); + d->updateVerticalAnchors(); } void QFxAnchors::resetVerticalCenter() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasVCenterAnchor; - - //clear binding - QmlMetaProperty prop(this, "verticalCenter"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(verticalCenterOffsetChanged()), this, SLOT(updateVerticalAnchors())); - disconnect(d->vCenter.item, 0, this, 0); - - updateVerticalAnchors(); + setVerticalCenter(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::left() const @@ -699,29 +611,22 @@ void QFxAnchors::setLeft(const QFxAnchorLine &edge) if (!d->checkHAnchorValid(edge)) return; - d->usedAnchors |= HasLeftAnchor; + if (edge.item) + d->usedAnchors |= HasLeftAnchor; + else + d->usedAnchors &= ~HasLeftAnchor; d->checkHValid(); + d->remDepend(d->left.item); d->left = edge; + d->addDepend(d->left.item); + d->updateHorizontalAnchors(); } void QFxAnchors::resetLeft() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasLeftAnchor; - - //clear binding - QmlMetaProperty prop(this, "left"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(leftMarginChanged()), this, SLOT(updateHorizontalAnchors())); - disconnect(d->left.item, 0, this, 0); - - updateHorizontalAnchors(); + setLeft(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::right() const @@ -736,29 +641,23 @@ void QFxAnchors::setRight(const QFxAnchorLine &edge) if (!d->checkHAnchorValid(edge)) return; - d->usedAnchors |= HasRightAnchor; + if (edge.item) + d->usedAnchors |= HasRightAnchor; + else + d->usedAnchors &= ~HasRightAnchor; d->checkHValid(); + d->remDepend(d->right.item); d->right = edge; + d->addDepend(d->right.item); + + d->updateHorizontalAnchors(); } void QFxAnchors::resetRight() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasRightAnchor; - - //clear binding - QmlMetaProperty prop(this, "right"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(rightMarginChanged()), this, SLOT(updateHorizontalAnchors())); - disconnect(d->right.item, 0, this, 0); - - updateHorizontalAnchors(); + setRight(QFxAnchorLine()); } QFxAnchorLine QFxAnchors::horizontalCenter() const @@ -773,29 +672,22 @@ void QFxAnchors::setHorizontalCenter(const QFxAnchorLine &edge) if (!d->checkHAnchorValid(edge)) return; - d->usedAnchors |= HasHCenterAnchor; + if (edge.item) + d->usedAnchors |= HasHCenterAnchor; + else + d->usedAnchors &= ~HasHCenterAnchor; d->checkHValid(); + d->remDepend(d->hCenter.item); d->hCenter = edge; + d->addDepend(d->hCenter.item); + d->updateHorizontalAnchors(); } void QFxAnchors::resetHorizontalCenter() { - Q_D(QFxAnchors); - - //update flags - d->usedAnchors &= ~HasHCenterAnchor; - - //clear binding - QmlMetaProperty prop(this, "horizontalCenter"); - prop.binding()->clearExpression(); - - //disconnect signal/slot connections as needed - disconnect(this, SIGNAL(horizontalCenterOffsetChanged()), this, SLOT(updateHorizontalAnchors())); - disconnect(d->hCenter.item, 0, this, 0); - - updateHorizontalAnchors(); + setHorizontalCenter(QFxAnchorLine()); } int QFxAnchors::leftMargin() const @@ -888,50 +780,6 @@ void QFxAnchors::setVerticalCenterOffset(int offset) emit verticalCenterOffsetChanged(); } -#if 0 -/*! - \property QFxAnchors::baseline - \brief what the baseline of the item should be anchored to (aligned with). - - The baseline of a Text item is the imaginary line on which the text sits. Controls containing - text usually set their baseline to the baseline of their text. - - For non-text items, a default baseline offset of two-thirds of the item's height is used - to determine the baseline. -*/ -int QFxAnchors::baseline() const -{ - return d->item->baseline(); -} - -void QFxAnchors::setBaseline(int baseline) -{ - d->usedAnchors |= HasBaselineAnchor; - - if (d->usedAnchors & HasTopAnchor && d->usedAnchors & HasBottomAnchor) { - qmlInfo(d->item) << "Can't specify top, bottom, and baseline anchors"; - return; - } - - if (d->usedAnchors & HasTopAnchor) { - int hoffset = baseline - d->item->baseline(); - d->item->setHeight(d->item->height() + hoffset); - } else { - if (d->usedAnchors & HasBottomAnchor) { - int hoffset = d->item->baseline() - baseline; - d->item->setHeight(d->item->height() + hoffset); - } - - int boffset = d->item->baseline() - d->item->top(); - QFxItem *parentItem = d->item->itemParent(); - if (parentItem) - d->item->setY(baseline - boffset - parentItem->top()); - else - d->item->setY(baseline - boffset); - } -} -#endif - QFxAnchors::UsedAnchors QFxAnchors::usedAnchors() const { Q_D(const QFxAnchors); diff --git a/src/declarative/fx/qfxanchors.h b/src/declarative/fx/qfxanchors.h index 5a8cc1a..9d776ab 100644 --- a/src/declarative/fx/qfxanchors.h +++ b/src/declarative/fx/qfxanchors.h @@ -42,9 +42,9 @@ #ifndef QFXANCHORS_H #define QFXANCHORS_H -#include <qfxglobal.h> -#include <QObject> -#include <qml.h> +#include <QtCore/QObject> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER @@ -80,6 +80,7 @@ public: Q_DECLARE_METATYPE(QFxAnchorLine); +class QFxAnchorsPrivate; class Q_DECLARATIVE_EXPORT QFxAnchors : public QObject { Q_OBJECT @@ -101,6 +102,7 @@ class Q_DECLARATIVE_EXPORT QFxAnchors : public QObject public: QFxAnchors(QObject *parent=0); + virtual ~QFxAnchors(); enum UsedAnchor { HasLeftAnchor = 0x01, @@ -167,9 +169,6 @@ public: void setItem(QFxItem *item); - void connectHAnchors(); - void connectVAnchors(); - Q_SIGNALS: void leftMarginChanged(); void rightMarginChanged(); @@ -178,13 +177,8 @@ Q_SIGNALS: void verticalCenterOffsetChanged(); void horizontalCenterOffsetChanged(); -private Q_SLOTS: - void fillChanged(); - void updateHorizontalAnchors(); - void updateVerticalAnchors(); - private: - //### should item be a friend? (and make some of the public methods private or protected) + friend class QFxItem; Q_DISABLE_COPY(QFxAnchors) Q_DECLARE_PRIVATE(QFxAnchors) }; diff --git a/src/declarative/fx/qfxanchors_p.h b/src/declarative/fx/qfxanchors_p.h index 82c2086..b90380a 100644 --- a/src/declarative/fx/qfxanchors_p.h +++ b/src/declarative/fx/qfxanchors_p.h @@ -63,9 +63,10 @@ class QFxAnchorsPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QFxAnchors) public: QFxAnchorsPrivate() - : item(0), usedAnchors(0), fill(0), centeredIn(0), leftMargin(0), rightMargin(0), - topMargin(0), bottomMargin(0), vCenterOffset(0), hCenterOffset(0), - updatingHorizontalAnchor(false), updatingVerticalAnchor(false) + : updatingMe(false), updatingHorizontalAnchor(false), + updatingVerticalAnchor(false), item(0), usedAnchors(0), fill(0), + centeredIn(0), leftMargin(0), rightMargin(0), topMargin(0), + bottomMargin(0), vCenterOffset(0), hCenterOffset(0) { } @@ -73,14 +74,37 @@ public: { } + void clearItem(QFxItem *); + + void addDepend(QFxItem *); + void remDepend(QFxItem *); + bool isItemComplete() const; + + bool updatingMe:1; + bool updatingHorizontalAnchor:1; + bool updatingVerticalAnchor:1; + + void setItemHeight(qreal); + void setItemWidth(qreal); + void setItemX(qreal); + void setItemY(qreal); + void setItemPos(const QPointF &); + + void updateOnComplete(); + void updateMe(); + void update(QFxItem *, const QRectF &, const QRectF &); + bool checkHValid() const; bool checkVValid() const; bool checkHAnchorValid(QFxAnchorLine anchor) const; bool checkVAnchorValid(QFxAnchorLine anchor) const; - void connectHHelper(const QFxAnchorLine &anchorLine); - void connectVHelper(const QFxAnchorLine &anchorLine); bool calcStretch(const QFxAnchorLine &edge1, const QFxAnchorLine &edge2, int offset1, int offset2, QFxAnchorLine::AnchorLine line, int &stretch); + void updateHorizontalAnchors(); + void updateVerticalAnchors(); + void fillChanged(); + void centeredInChanged(); + QFxItem *item; QFxAnchors::UsedAnchors usedAnchors; @@ -101,8 +125,6 @@ public: int vCenterOffset; int hCenterOffset; - bool updatingHorizontalAnchor; - bool updatingVerticalAnchor; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxanimatedimageitem.h b/src/declarative/fx/qfxanimatedimageitem.h index 121fe62..a332c8b 100644 --- a/src/declarative/fx/qfxanimatedimageitem.h +++ b/src/declarative/fx/qfxanimatedimageitem.h @@ -42,7 +42,7 @@ #ifndef QFXANIMATEDIMAGEITEM_H #define QFXANIMATEDIMAGEITEM_H -#include <qfximage.h> +#include <QtDeclarative/qfximage.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxblendedimage.h b/src/declarative/fx/qfxblendedimage.h index 5cc0238..2fdf15b 100644 --- a/src/declarative/fx/qfxblendedimage.h +++ b/src/declarative/fx/qfxblendedimage.h @@ -42,7 +42,7 @@ #ifndef QFXBLENDEDIMAGE_H #define QFXBLENDEDIMAGE_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> #if defined(QFX_RENDER_OPENGL2) #include <gltexture.h> #endif @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QFxBlendedImage : public QFxItem +class Q_DECLARATIVE_EXPORT QFxBlendedImage : public QFxItem { Q_OBJECT diff --git a/src/declarative/fx/qfxblurfilter.h b/src/declarative/fx/qfxblurfilter.h index 7a2b5b9..576debf 100644 --- a/src/declarative/fx/qfxblurfilter.h +++ b/src/declarative/fx/qfxblurfilter.h @@ -42,8 +42,8 @@ #ifndef QFXBLURFILTER_H #define QFXBLURFILTER_H -#include <qsimplecanvasfilter.h> -#include <qml.h> +#include <QtDeclarative/qsimplecanvasfilter.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxcomponentinstance.h b/src/declarative/fx/qfxcomponentinstance.h index 64af355..9f84043 100644 --- a/src/declarative/fx/qfxcomponentinstance.h +++ b/src/declarative/fx/qfxcomponentinstance.h @@ -42,7 +42,7 @@ #ifndef QFXCOMPONENTINSTANCE_H #define QFXCOMPONENTINSTANCE_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxcontentwrapper.h b/src/declarative/fx/qfxcontentwrapper.h index 5d5a7e1..0b7253e 100644 --- a/src/declarative/fx/qfxcontentwrapper.h +++ b/src/declarative/fx/qfxcontentwrapper.h @@ -42,7 +42,7 @@ #ifndef QFXCONTENTWRAPPER_H #define QFXCONTENTWRAPPER_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxevents_p.h b/src/declarative/fx/qfxevents_p.h index 30717ef..bcd9f2d 100644 --- a/src/declarative/fx/qfxevents_p.h +++ b/src/declarative/fx/qfxevents_p.h @@ -42,8 +42,8 @@ #ifndef QFXEVENTS_P_H #define QFXEVENTS_P_H -#include <qfxglobal.h> -#include <qml.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> #include <QtCore/qobject.h> #include <QtGui/qevent.h> diff --git a/src/declarative/fx/qfxflickable.h b/src/declarative/fx/qfxflickable.h index c5a0593..3857017 100644 --- a/src/declarative/fx/qfxflickable.h +++ b/src/declarative/fx/qfxflickable.h @@ -42,7 +42,7 @@ #ifndef QFXFLICKABLE_H #define QFXFLICKABLE_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxflipable.cpp b/src/declarative/fx/qfxflipable.cpp index 24ae428..edcc7cb 100644 --- a/src/declarative/fx/qfxflipable.cpp +++ b/src/declarative/fx/qfxflipable.cpp @@ -169,7 +169,6 @@ void QFxFlipable::setBack(QFxItem *back) children()->append(d->back); if (Front == d->current) d->back->setOpacity(0.); - d->setBackTransform(); } /*! @@ -203,8 +202,6 @@ void QFxFlipablePrivate::_q_updateAxis() axisRotation.axis()->setEndX(axis->endX()); axisRotation.axis()->setEndY(axis->endY()); axisRotation.axis()->setEndZ(axis->endZ()); - - setBackTransform(); } void QFxFlipablePrivate::setBackTransform() @@ -273,8 +270,10 @@ void QFxFlipable::setRotation(qreal angle) d->current = newSide; if (d->front) d->front->setOpacity((d->current==Front)?1.:0.); - if (d->back) + if (d->back) { + d->setBackTransform(); d->back->setOpacity((d->current==Back)?1.:0.); + } emit sideChanged(); } } diff --git a/src/declarative/fx/qfxflipable.h b/src/declarative/fx/qfxflipable.h index ef1832e..62b62a5 100644 --- a/src/declarative/fx/qfxflipable.h +++ b/src/declarative/fx/qfxflipable.h @@ -42,12 +42,12 @@ #ifndef QFXFLIPABLE_H #define QFXFLIPABLE_H -#include <QObject> -#include <QTransform> +#include <QtCore/QObject> +#include <QtGui/QTransform> #if defined(QFX_RENDER_OPENGL) #include <QtGui/qmatrix4x4.h> #endif -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxfocuspanel.h b/src/declarative/fx/qfxfocuspanel.h index 38f7a15..cec12a1 100644 --- a/src/declarative/fx/qfxfocuspanel.h +++ b/src/declarative/fx/qfxfocuspanel.h @@ -42,7 +42,7 @@ #ifndef QFXFOCUSPANEL_H #define QFXFOCUSPANEL_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxfocusrealm.h b/src/declarative/fx/qfxfocusrealm.h index 6c35405..fdf1525 100644 --- a/src/declarative/fx/qfxfocusrealm.h +++ b/src/declarative/fx/qfxfocusrealm.h @@ -42,7 +42,7 @@ #ifndef QFXFOCUSREALM_H #define QFXFOCUSREALM_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxgridview.h b/src/declarative/fx/qfxgridview.h index 90bf1ce..99c7cff 100644 --- a/src/declarative/fx/qfxgridview.h +++ b/src/declarative/fx/qfxgridview.h @@ -42,7 +42,7 @@ #ifndef QFXGRIDVIEW_H #define QFXGRIDVIEW_H -#include <qfxflickable.h> +#include <QtDeclarative/qfxflickable.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxhighlightfilter.h b/src/declarative/fx/qfxhighlightfilter.h index 218f4e1..92a3dc7 100644 --- a/src/declarative/fx/qfxhighlightfilter.h +++ b/src/declarative/fx/qfxhighlightfilter.h @@ -42,8 +42,8 @@ #ifndef QFXHIGHLIGHTFILTER_H #define QFXHIGHLIGHTFILTER_H -#include <qsimplecanvasfilter.h> -#include <qml.h> +#include <QtDeclarative/qsimplecanvasfilter.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp index 9d7a36a..4197a80 100644 --- a/src/declarative/fx/qfximage.cpp +++ b/src/declarative/fx/qfximage.cpp @@ -361,49 +361,57 @@ void QFxImage::paintContents(QPainter &p) p.drawImage(0, 0, pix); } } else { - const int sgl = d->_scaleGrid->left(); - const int sgr = d->_scaleGrid->right(); - const int sgt = d->_scaleGrid->top(); - const int sgb = d->_scaleGrid->bottom(); - const int xSide = qMin(sgl + sgr, int(width())); - const int ySide = qMin(sgt + sgb, int(height())); + int sgl = d->_scaleGrid->left(); + int sgr = d->_scaleGrid->right(); + int sgt = d->_scaleGrid->top(); + int sgb = d->_scaleGrid->bottom(); + + int w = width(); + int h = height(); + if (sgt + sgb > h) + sgt = sgb = h/2; + if (sgl + sgr > w) + sgl = sgr = w/2; + + const int xSide = sgl + sgr; + const int ySide = sgt + sgb; // Upper left if (sgt && sgl) p.drawImage(QRect(0, 0, sgl, sgt), pix, QRect(0, 0, sgl, sgt)); // Upper middle if (pix.width() - xSide && sgt) - p.drawImage(QRect(sgl, 0, width() - xSide, sgt), pix, + p.drawImage(QRect(sgl, 0, w - xSide, sgt), pix, QRect(sgl, 0, pix.width() - xSide, sgt)); // Upper right if (sgt && pix.width() - sgr) - p.drawImage(QPoint(width()-sgr, 0), pix, + p.drawImage(QPoint(w-sgr, 0), pix, QRect(pix.width()-sgr, 0, sgr, sgt)); // Middle left if (sgl && pix.height() - ySide) - p.drawImage(QRect(0, sgt, sgl, height() - ySide), pix, + p.drawImage(QRect(0, sgt, sgl, h - ySide), pix, QRect(0, sgt, sgl, pix.height() - ySide)); // Middle if (pix.width() - xSide && pix.height() - ySide) - p.drawImage(QRect(sgl, sgt, width() - xSide, height() - ySide), + p.drawImage(QRect(sgl, sgt, w - xSide, h - ySide), pix, QRect(sgl, sgt, pix.width() - xSide, pix.height() - ySide)); // Middle right if (sgr && pix.height() - ySide) - p.drawImage(QRect(width()-sgr, sgt, sgr, height() - ySide), pix, + p.drawImage(QRect(w-sgr, sgt, sgr, h - ySide), pix, QRect(pix.width()-sgr, sgt, sgr, pix.height() - ySide)); // Lower left if (sgl && sgr) - p.drawImage(QPoint(0, height() - sgb), pix, + p.drawImage(QPoint(0, h - sgb), pix, QRect(0, pix.height() - sgb, sgl, sgb)); // Lower Middle if (pix.width() - xSide && sgb) - p.drawImage(QRect(sgl, height() - sgb, width() - xSide, sgb), pix, + p.drawImage(QRect(sgl, h - sgb, w - xSide, sgb), pix, QRect(sgl, pix.height() - sgb, pix.width() - xSide, sgb)); // Lower Right if (sgr && sgb) - p.drawImage(QPoint(width()-sgr, height() - sgb), pix, + p.drawImage(QPoint(w-sgr, h - sgb), pix, QRect(pix.width()-sgr, pix.height() - sgb, sgr, sgb)); } diff --git a/src/declarative/fx/qfximage.h b/src/declarative/fx/qfximage.h index dc13a97..1436551 100644 --- a/src/declarative/fx/qfximage.h +++ b/src/declarative/fx/qfximage.h @@ -42,7 +42,7 @@ #ifndef QFXIMAGE_H #define QFXIMAGE_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> #include <QtNetwork/qnetworkreply.h> diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index b737615..3cbcd6a 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -52,6 +52,7 @@ #include "qmlengine.h" #include "qmlstate.h" #include "qlistmodelinterface.h" +#include "qfxanchors_p.h" #include "qfxtransform.h" #include "qfxscalegrid.h" @@ -434,6 +435,14 @@ void QFxItem::doUpdate() QFxItem::~QFxItem() { Q_D(QFxItem); + for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) { + QFxAnchors *anchor = d->dependantAnchors.at(ii); + anchor->d_func()->clearItem(this); + } + for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) { + QFxAnchors *anchor = d->dependantAnchors.at(ii); + anchor->d_func()->updateOnComplete(); + } delete d->_anchorLines; d->_anchorLines = 0; } @@ -1062,85 +1071,30 @@ void QFxItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { Q_D(QFxItem); - if (newGeometry.width() != oldGeometry.width()) { - int xoffset = oldGeometry.width() - newGeometry.width(); - d->handleWidthChange(xoffset); - } - if (newGeometry.height() != oldGeometry.height()) { - int yoffset = oldGeometry.height() - newGeometry.height(); - d->handleHeightChange(yoffset); - } + if (d->_anchors) + d->_anchors->d_func()->updateMe(); - if (newGeometry.x() != oldGeometry.x()) { - emit leftChanged(); - emit hcenterChanged(); - emit rightChanged(); + if (newGeometry.size() != oldGeometry.size()) { + if (rotation() && transformOrigin() != QFxItem::TopLeft) + setRotation(rotation()); + if (scale() && transformOrigin() != QFxItem::TopLeft) + setScale(scale()); } - if (newGeometry.y() != oldGeometry.y()) { + if (newGeometry.x() != oldGeometry.x()) + emit leftChanged(); + if (newGeometry.width() != oldGeometry.width()) + emit widthChanged(); + if (newGeometry.y() != oldGeometry.y()) emit topChanged(); - emit vcenterChanged(); - emit bottomChanged(); - } -} - -void QFxItemPrivate::handleWidthChange(int xoffset) -{ - Q_Q(QFxItem); - if (!_anchors) { - emit q->hcenterChanged(); - emit q->rightChanged(); - } else { - QFxAnchors::UsedAnchors used = anchors()->usedAnchors(); - if (used & QFxAnchors::HasHCenterAnchor) { - q->setX(q->x() + xoffset/2); - emit q->rightChanged(); - } else if ((used & QFxAnchors::HasRightAnchor) && !(used & QFxAnchors::HasLeftAnchor)) { - q->setX(q->x() + xoffset); - emit q->hcenterChanged(); - } else { - emit q->hcenterChanged(); - emit q->rightChanged(); - } - } - if (q->rotation() && q->transformOrigin() != QFxItem::TopLeft) - q->setRotation(q->rotation()); - if (q->scale() && q->transformOrigin() != QFxItem::TopLeft) - q->setScale(q->scale()); - emit q->widthChanged(); -} + if (newGeometry.height() != oldGeometry.height()) + emit heightChanged(); -void QFxItemPrivate::handleHeightChange(int yoffset) -{ - Q_Q(QFxItem); - if (!_anchors) { - emit q->vcenterChanged(); - emit q->bottomChanged(); - emit q->baselineChanged(); - } else { - QFxAnchors::UsedAnchors used = anchors()->usedAnchors(); - if (used & QFxAnchors::HasBaselineAnchor) { - q->setY(q->y() + yoffset - q->baselineOffset()); - emit q->bottomChanged(); - emit q->vcenterChanged(); - } else if (used & QFxAnchors::HasVCenterAnchor) { - q->setY(q->y() + yoffset/2); - emit q->bottomChanged(); - } else if ((used & QFxAnchors::HasBottomAnchor) && !(used & QFxAnchors::HasTopAnchor)) { - q->setY(q->y() + yoffset); - emit q->vcenterChanged(); - } else { - emit q->vcenterChanged(); - emit q->bottomChanged(); - emit q->baselineChanged(); - } + for(int ii = 0; ii < d->dependantAnchors.count(); ++ii) { + QFxAnchors *anchor = d->dependantAnchors.at(ii); + anchor->d_func()->update(this, newGeometry, oldGeometry); } - if (q->rotation() && q->transformOrigin() != QFxItem::TopLeft) - q->setRotation(q->rotation()); - if (q->scale() && q->transformOrigin() != QFxItem::TopLeft) - q->setScale(q->scale()); - emit q->heightChanged(); } /*! @@ -1483,7 +1437,6 @@ void QFxItem::setBaselineOffset(int offset) d->_baselineOffset = offset; emit baselineOffsetChanged(); - emit baselineChanged(); } /*! @@ -2075,10 +2028,8 @@ void QFxItem::componentComplete() d->_componentComplete = true; if (d->_stateGroup) d->_stateGroup->componentComplete(); - if (d->_anchors) { - d->anchors()->connectHAnchors(); - d->anchors()->connectVAnchors(); - } + if (d->_anchors) + d->anchors()->d_func()->updateOnComplete(); if (!d->_transform.isEmpty()) updateTransform(); } diff --git a/src/declarative/fx/qfxitem.h b/src/declarative/fx/qfxitem.h index 549c9c2..d34a9fb 100644 --- a/src/declarative/fx/qfxitem.h +++ b/src/declarative/fx/qfxitem.h @@ -42,9 +42,9 @@ #ifndef QFXITEM_H #define QFXITEM_H -#include <QObject> +#include <QtCore/QObject> #include <QtScript/qscriptvalue.h> -#include <QList> +#include <QtCore/QList> #include <QtDeclarative/qfxanchors.h> #include <QtDeclarative/qfxglobal.h> #include <QtDeclarative/qml.h> @@ -213,14 +213,9 @@ public Q_SLOTS: Q_SIGNALS: void leftChanged(); - void rightChanged(); void widthChanged(); void heightChanged(); void topChanged(); - void bottomChanged(); - void hcenterChanged(); - void vcenterChanged(); - void baselineChanged(); void baselineOffsetChanged(); void stateChanged(const QString &); void focusChanged(); diff --git a/src/declarative/fx/qfxitem_p.h b/src/declarative/fx/qfxitem_p.h index f2da3ba..85ce171 100644 --- a/src/declarative/fx/qfxitem_p.h +++ b/src/declarative/fx/qfxitem_p.h @@ -53,11 +53,11 @@ // We mean it. // -#include "qfxitem.h" +#include <QtDeclarative/qfxitem.h> #include <private/qsimplecanvasitem_p.h> #include <private/qmlnullablevalue_p.h> -#include <qml.h> -#include <qmlcontext.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlcontext.h> #include <QtCore/qlist.h> QT_BEGIN_NAMESPACE @@ -129,6 +129,7 @@ public: } return _anchors; } + QList<QFxAnchors *> dependantAnchors; QFxAnchors *_anchors; QFxContents *_contents; QFxItem *qmlItem; @@ -171,9 +172,6 @@ public: QmlStateGroup *states(); QmlStateGroup *_stateGroup; - - void handleWidthChange(int xoffset); - void handleHeightChange(int xoffset); }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxkeyactions.h b/src/declarative/fx/qfxkeyactions.h index 7ad323a..a5aec2e 100644 --- a/src/declarative/fx/qfxkeyactions.h +++ b/src/declarative/fx/qfxkeyactions.h @@ -42,10 +42,10 @@ #ifndef QFXKEYACTIONS_H #define QFXKEYACTIONS_H -#include <qfxglobal.h> -#include <QObject> -#include <qml.h> -#include <qfxitem.h> +#include <QtCore/QObject> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxkeyproxy.h b/src/declarative/fx/qfxkeyproxy.h index ae5fce4..6cf0c0d 100644 --- a/src/declarative/fx/qfxkeyproxy.h +++ b/src/declarative/fx/qfxkeyproxy.h @@ -42,7 +42,7 @@ #ifndef QFXKEYPROXY_H #define QFXKEYPROXY_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxlayouts.h b/src/declarative/fx/qfxlayouts.h index acfc0c4..35e41d8 100644 --- a/src/declarative/fx/qfxlayouts.h +++ b/src/declarative/fx/qfxlayouts.h @@ -42,10 +42,10 @@ #ifndef QFXLAYOUTS_H #define QFXLAYOUTS_H -#include <qfxitem.h> -#include <QObject> -#include <QString> -#include <qmlstate.h> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtDeclarative/qfxitem.h> +#include <QtDeclarative/qmlstate.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxlayouts_p.h b/src/declarative/fx/qfxlayouts_p.h index 859482f..77b0ea1 100644 --- a/src/declarative/fx/qfxlayouts_p.h +++ b/src/declarative/fx/qfxlayouts_p.h @@ -53,11 +53,11 @@ // We mean it. // -#include "qfxlayouts.h" -#include "qfxitem_p.h" -#include <QObject> -#include <QString> -#include <qmlstate.h> +#include <private/qfxitem_p.h> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtDeclarative/qfxlayouts.h> +#include <QtDeclarative/qmlstate.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/fx/qfxlistview.h b/src/declarative/fx/qfxlistview.h index 42f7773..87a851b 100644 --- a/src/declarative/fx/qfxlistview.h +++ b/src/declarative/fx/qfxlistview.h @@ -42,7 +42,7 @@ #ifndef QFXLISTVIEW_H #define QFXLISTVIEW_H -#include <qfxflickable.h> +#include <QtDeclarative/qfxflickable.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxmouseregion.h b/src/declarative/fx/qfxmouseregion.h index 2ba4a50..1d1ec93 100644 --- a/src/declarative/fx/qfxmouseregion.h +++ b/src/declarative/fx/qfxmouseregion.h @@ -42,7 +42,7 @@ #ifndef QFXMOUSEREGION_H #define QFXMOUSEREGION_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxpainteditem.h b/src/declarative/fx/qfxpainteditem.h index 015a035..6cd21e6 100644 --- a/src/declarative/fx/qfxpainteditem.h +++ b/src/declarative/fx/qfxpainteditem.h @@ -42,8 +42,8 @@ #ifndef QFXIMAGEITEM_H #define QFXIMAGEITEM_H -#include <qfxglobal.h> -#include <qfxitem.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxpainteditem_p.h b/src/declarative/fx/qfxpainteditem_p.h index b0432ac..5d5da6b 100644 --- a/src/declarative/fx/qfxpainteditem_p.h +++ b/src/declarative/fx/qfxpainteditem_p.h @@ -53,8 +53,8 @@ // We mean it. // -#include "qfxitem_p.h" -#include <qsimplecanvas.h> +#include <private/qfxitem_p.h> +#include <QtDeclarative/qsimplecanvas.h> #if defined(QFX_RENDER_OPENGL) #include "gltexture.h" diff --git a/src/declarative/fx/qfxparticles.cpp b/src/declarative/fx/qfxparticles.cpp index 1aaf256..67c1208 100644 --- a/src/declarative/fx/qfxparticles.cpp +++ b/src/declarative/fx/qfxparticles.cpp @@ -340,6 +340,32 @@ void QFxParticleMotionWander::destroy(QFxParticle &p) } //--------------------------------------------------------------------------- +class QFxParticlesPainter : public QFxItem +{ +public: + QFxParticlesPainter(QFxParticlesPrivate *p, QFxItem* parent) + : QFxItem(parent), d(p) + { + setOptions(HasContents); + maxX = minX = maxY = minY = 0; + } + +#if defined(QFX_RENDER_QPAINTER) + void paintContents(QPainter &p); +#elif defined(QFX_RENDER_OPENGL2) + void paintGLContents(GLPainter &); +#endif + + void updateSize(); + + qreal maxX; + qreal minX; + qreal maxY; + qreal minY; + QFxParticlesPrivate* d; +}; + +//--------------------------------------------------------------------------- class QFxParticlesPrivate : public QFxItemPrivate { Q_DECLARE_PUBLIC(QFxParticles) @@ -359,7 +385,12 @@ public: { } - void init() {} + void init() + { + Q_Q(QFxParticles); + paintItem = new QFxParticlesPainter(this, q); + } + void tick(int time); void createParticle(int time); void updateOpacity(QFxParticle &p, int age); @@ -383,6 +414,7 @@ public: int streamDelay; bool emitting; QFxParticleMotion *motion; + QFxParticlesPainter *paintItem; QList<QFxParticle> particles; QTickAnimationProxy<QFxParticlesPrivate, &QFxParticlesPrivate::tick> clock; @@ -1040,28 +1072,76 @@ QString QFxParticles::propertyInfo() const return d->url.toString(); } +void QFxParticlesPainter::updateSize(){ + setX(-500); + setY(-500); + setWidth(1000); + setHeight(1000); + return ; + const int parentX = parent()->x(); + const int parentY = parent()->y(); + //Have to use statistical approach to needed size as arbitrary particle + //motions make it impossible to calculate. + //max/min vars stored to give a never shrinking rect + for (int i = 0; i < d->particles.count(); ++i) { + const QFxParticle &particle = d->particles.at(i); + if(particle.x > maxX) + maxX = particle.x; + if(particle.x < minX) + minX = particle.x; + if(particle.y > maxY) + maxY = particle.y; + if(particle.y < minY) + minY = particle.y; + } + + int myWidth = (int)(maxX-minX+0.5)+d->image.width(); + int myX = (int)(minX - parentX); + int myHeight = (int)(maxY-minY+0.5)+d->image.height(); + int myY = (int)(minY - parentY); + setWidth(myWidth); + setHeight(myHeight); + setX(myX); + setY(myY); +} + #if defined(QFX_RENDER_QPAINTER) void QFxParticles::paintContents(QPainter &p) { - Q_D(QFxParticles); + Q_UNUSED(p); + //painting is done by the ParticlesPainter, so it can have the right size +} + +void QFxParticlesPainter::paintContents(QPainter &p) +{ if (d->image.isNull()) return; - const int myX = x(); - const int myY = y(); + updateSize(); + const int myX = x() + parent()->x(); + const int myY = y() + parent()->y(); + for (int i = 0; i < d->particles.count(); ++i) { const QFxParticle &particle = d->particles.at(i); p.setOpacity(particle.opacity); - p.drawImage(particle.x-myX, particle.y-myY, d->image); + p.drawImage(particle.x - myX, particle.y - myY, d->image); } + update();//Should I need this? (GV does) } #elif defined(QFX_RENDER_OPENGL2) -void QFxParticles::paintGLContents(GLPainter &p) +void QFxParticles::paintGLContents(GLPainter &) { - Q_D(QFxParticles); + //painting is done by the ParticlesPainter, so it can have the right size +} + +void QFxParticlesPainter::paintGLContents(GLPainter &p) +{ + if (d->image.isNull()) return; + updateSize(); + if (d->texDirty && !d->image.isNull()) { d->tex.setImage(d->image); d->tex.setHorizontalWrap(GLTexture::Repeat); @@ -1075,8 +1155,8 @@ void QFxParticles::paintGLContents(GLPainter &p) glBindTexture(GL_TEXTURE_2D, d->tex.texture()); - const int myX = (int)x(); - const int myY = (int)y(); + const int myX = (int)(x() + parent()->x()); + const int myY = (int)(y() + parent()->y()); float widthV = d->image.width(); float heightV = d->image.height(); for (int i = 0; i < d->particles.count(); ++i) { diff --git a/src/declarative/fx/qfxparticles.h b/src/declarative/fx/qfxparticles.h index 0696e60..31a00fb 100644 --- a/src/declarative/fx/qfxparticles.h +++ b/src/declarative/fx/qfxparticles.h @@ -42,7 +42,7 @@ #ifndef QFXPARTICLES_H #define QFXPARTICLES_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> #if defined(QFX_RENDER_OPENGL) #include "gltexture.h" @@ -56,7 +56,7 @@ QT_MODULE(Declarative) class QFxParticle; class QFxParticles; -class QFxParticleMotion : public QObject +class Q_DECLARATIVE_EXPORT QFxParticleMotion : public QObject { Q_OBJECT public: @@ -68,7 +68,7 @@ public: }; QML_DECLARE_TYPE(QFxParticleMotion); -class QFxParticleMotionLinear : public QFxParticleMotion +class Q_DECLARATIVE_EXPORT QFxParticleMotionLinear : public QFxParticleMotion { Q_OBJECT public: @@ -79,7 +79,7 @@ public: }; QML_DECLARE_TYPE(QFxParticleMotionLinear); -class QFxParticleMotionGravity : public QFxParticleMotion +class Q_DECLARATIVE_EXPORT QFxParticleMotionGravity : public QFxParticleMotion { Q_OBJECT @@ -108,7 +108,7 @@ private: }; QML_DECLARE_TYPE(QFxParticleMotionGravity); -class QFxParticleMotionWander : public QFxParticleMotion +class Q_DECLARATIVE_EXPORT QFxParticleMotionWander : public QFxParticleMotion { Q_OBJECT public: diff --git a/src/declarative/fx/qfxpath.h b/src/declarative/fx/qfxpath.h index c594793..10cf252 100644 --- a/src/declarative/fx/qfxpath.h +++ b/src/declarative/fx/qfxpath.h @@ -42,10 +42,10 @@ #ifndef QFXPATH_H #define QFXPATH_H -#include <QObject> -#include <QPainterPath> -#include <qml.h> -#include <qfxitem.h> +#include <QtCore/QObject> +#include <QtGui/QPainterPath> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxpathview.h b/src/declarative/fx/qfxpathview.h index 04804b7..33db566 100644 --- a/src/declarative/fx/qfxpathview.h +++ b/src/declarative/fx/qfxpathview.h @@ -42,8 +42,8 @@ #ifndef QFXPATHVIEW_H #define QFXPATHVIEW_H -#include <qfxitem.h> -#include <qfxpath.h> +#include <QtDeclarative/qfxitem.h> +#include <QtDeclarative/qfxpath.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxpixmap.h b/src/declarative/fx/qfxpixmap.h index 297dba7..fd56ee4 100644 --- a/src/declarative/fx/qfxpixmap.h +++ b/src/declarative/fx/qfxpixmap.h @@ -42,10 +42,10 @@ #ifndef QFXPIXMAP_H #define QFXPIXMAP_H -#include <QString> -#include <qsimplecanvas.h> -#include <qfxglobal.h> -#include <QPixmap> +#include <QtCore/QString> +#include <QtGui/QPixmap> +#include <QtDeclarative/qsimplecanvas.h> +#include <QtDeclarative/qfxglobal.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxrect.cpp b/src/declarative/fx/qfxrect.cpp index dafd8a2..f1cbb58 100644 --- a/src/declarative/fx/qfxrect.cpp +++ b/src/declarative/fx/qfxrect.cpp @@ -52,6 +52,11 @@ QML_DEFINE_TYPE(QFxPen,Pen); \ingroup group_utility \brief The QFxPen class provides a pen used for drawing rect borders on a QFxView. + By default, the pen is invalid and nothing is drawn. You must either set a color (then the default + width is 0) or a width (then the default color is black). + + A width of 0 is a single-pixel line on the border of the item being painted. + Example: \qml Rect { pen.width: 2; pen.color: "red" ... } @@ -61,8 +66,9 @@ QML_DEFINE_TYPE(QFxPen,Pen); /*! \property QFxPen::width \brief the width of the pen. - The default width is 1. If the width is less than 1 the pen is considered invalid - and won't be used. + A width of 0 is a single-pixel line on the border of the item being painted. + + If the width is less than 0 the pen is considered invalid and won't be used. */ /*! @@ -86,8 +92,28 @@ QML_DEFINE_TYPE(QFxPen,Pen); void QFxPen::setColor(const QColor &c) { _color = c; - emit updated(); _valid = _color.alpha() ? true : false; + emit updated(); +} + +/*! + \property QFxPen::width + \brief the width of the pen. + + \qml + // rect with green border using hexidecimal notation + Rect { pen.width: 4 } + \endqml + + A width of 0 creates a thin line. For no line, use a negative width or a transparent color. + + Odd pen widths generally lead to half-pixel painting. +*/ +void QFxPen::setWidth(int w) +{ + _width = w; + _valid = (_width < 0) ? false : true; + emit updated(); } @@ -167,6 +193,8 @@ void QFxRect::doUpdate() Q_D(QFxRect); d->_rectTexture.clear(); #endif + const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0; + setPaintMargin((pw+1)/2); update(); } @@ -372,14 +400,19 @@ void QFxRect::generateRoundedRect() { Q_D(QFxRect); if (d->_rectImage.isNull()) { - d->_rectImage = QImage(d->_radius*2 + 1, d->_radius*2 + 1, QImage::Format_ARGB32_Premultiplied); + const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0; + d->_rectImage = QImage(d->_radius*2 + 1 + pw*2, d->_radius*2 + 1 + pw*2, QImage::Format_ARGB32_Premultiplied); d->_rectImage.fill(0); QPainter p(&(d->_rectImage)); - QPen pn(QColor(pen()->color()), pen()->width()); p.setRenderHint(QPainter::Antialiasing); - p.setPen(pn); + if (d->_pen && d->_pen->isValid()) { + QPen pn(QColor(pen()->color()), pen()->width()); + p.setPen(pn); + } else { + p.setPen(Qt::NoPen); + } p.setBrush(d->_color); - p.drawRoundedRect(0, 0, d->_rectImage.width(), d->_rectImage.height(), d->_radius, d->_radius); + p.drawRoundedRect((pw+1)/2, (pw+1)/2, d->_rectImage.width()-(pw+1)/2*2, d->_rectImage.height()-(pw+1)/2*2, d->_radius, d->_radius); } } @@ -387,14 +420,19 @@ void QFxRect::generateBorderedRect() { Q_D(QFxRect); if (d->_rectImage.isNull()) { - d->_rectImage = QImage(d->pen()->width()*2 + 1, d->pen()->width()*2 + 1, QImage::Format_ARGB32_Premultiplied); + const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0; + d->_rectImage = QImage(d->pen()->width()*2 + 1 + pw*2, d->pen()->width()*2 + 1 + pw*2, QImage::Format_ARGB32_Premultiplied); d->_rectImage.fill(0); QPainter p(&(d->_rectImage)); - QPen pn(QColor(pen()->color()), pen()->width()); p.setRenderHint(QPainter::Antialiasing); - p.setPen(pn); + if (d->_pen && d->_pen->isValid()) { + QPen pn(QColor(pen()->color()), pen()->width()); + p.setPen(pn); + } else { + p.setPen(Qt::NoPen); + } p.setBrush(d->_color); - p.drawRect(0, 0, d->_rectImage.width(), d->_rectImage.height()); + p.drawRect(qreal(pw+1)/2, qreal(pw+1)/2, d->_rectImage.width()-(pw+1)/2*2, d->_rectImage.height()-(pw+1)/2*2); } } #elif defined(QFX_RENDER_OPENGL) @@ -402,14 +440,19 @@ void QFxRect::generateRoundedRect() { Q_D(QFxRect); if (d->_rectTexture.isNull()) { - QImage roundRect(int(d->_radius*2 + 1), int(d->_radius*2 + 1), QImage::Format_ARGB32); + const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0; + QImage roundRect(d->_radius*2 + 4 + pw*2, d->_radius*2 + 4 + pw*2, QImage::Format_ARGB32_Premultiplied); roundRect.fill(0); QPainter p(&roundRect); - QPen pn(QColor(pen()->color()), pen()->width()); p.setRenderHint(QPainter::Antialiasing); - p.setPen(pn); + if (d->_pen && d->_pen->isValid()) { + QPen pn(QColor(pen()->color()), pen()->width()); + p.setPen(pn); + } else { + p.setPen(Qt::NoPen); + } p.setBrush(d->_color); - p.drawRoundedRect(0, 0, roundRect.width(), roundRect.height(), d->_radius, d->_radius); + p.drawRoundedRect((pw+1)/2, (pw+1)/2, roundRect.width()-(pw+1)/2*2, roundRect.height()-(pw+1)/2*2, d->_radius, d->_radius); d->_rectTexture.setImage(roundRect); } } @@ -418,14 +461,19 @@ void QFxRect::generateBorderedRect() { Q_D(QFxRect); if (d->_rectTexture.isNull()) { - QImage borderedRect(d->pen()->width()*2 + 1, d->pen()->width()*2 + 1, QImage::Format_ARGB32_Premultiplied); + const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0; + QImage borderedRect(pw*2 + 4, pw*2 + 4, QImage::Format_ARGB32_Premultiplied); borderedRect.fill(0); QPainter p(&(borderedRect)); - QPen pn(QColor(pen()->color()), pen()->width()); p.setRenderHint(QPainter::Antialiasing); - p.setPen(pn); + if (d->_pen && d->_pen->isValid()) { + QPen pn(QColor(pen()->color()), pen()->width()); + p.setPen(pn); + } else { + p.setPen(Qt::NoPen); + } p.setBrush(d->_color); - p.drawRect(0, 0, borderedRect.width(), borderedRect.height()); + p.drawRect(qreal(pw+1)/2, qreal(pw+1)/2, borderedRect.width()-(pw+1)/2*2, borderedRect.height()-(pw+1)/2*2); d->_rectTexture.setImage(borderedRect); } } @@ -458,9 +506,13 @@ void QFxRect::drawRect(QPainter &p) // XXX This path is still slower than the image path // Image path won't work for gradients though p.save(); - QPen pn(QColor(pen()->color()), pen()->width()); p.setRenderHint(QPainter::Antialiasing); - p.setPen(pn); + if (d->_pen && d->_pen->isValid()) { + QPen pn(QColor(pen()->color()), pen()->width()); + p.setPen(pn); + } else { + p.setPen(Qt::NoPen); + } if (d->_gradcolor.isValid()){ QLinearGradient grad(0, 0, 0, height()); grad.setColorAt(0, d->_color); @@ -476,55 +528,72 @@ void QFxRect::drawRect(QPainter &p) p.restore(); } else { int offset = 0; + const int pw = d->_pen && d->_pen->isValid() ? (d->_pen->width()+1)/2*2 : 0; + if (d->_radius > 0) { generateRoundedRect(); //### implicit conversion to int - offset = d->_radius; + offset = int(d->_radius+0.5+pw); } else { generateBorderedRect(); - offset = d->pen()->width(); + offset = pw; } //basically same code as QFxImage uses to paint sci images - int xSide = qMin(offset * 2, int(width())); - int ySide = qMin(offset * 2, int(height()));; + int w = width()+pw; + int h = height()+pw; + int xOffset = offset; + int xSide = xOffset * 2; + bool xMiddles=true; + if (xSide > w) { + xMiddles=false; + xOffset = w/2 + 1; + xSide = xOffset * 2; + } + int yOffset = offset; + int ySide = yOffset * 2; + bool yMiddles=true; + if (ySide > h) { + yMiddles = false; + yOffset = h/2 + 1; + ySide = yOffset * 2; + } // Upper left - p.drawImage(QRect(0, 0, offset, offset), d->_rectImage, QRect(0, 0, offset, offset)); + p.drawImage(QRect(-pw/2, -pw/2, xOffset, yOffset), d->_rectImage, QRect(0, 0, xOffset, yOffset)); // Upper middle - if (d->_rectImage.width() - xSide) - p.drawImage(QRect(offset, 0, width() - xSide, offset), d->_rectImage, - QRect(offset, 0, d->_rectImage.width() - xSide, offset)); + if (xMiddles) + p.drawImage(QRect(xOffset-pw/2, -pw/2, width() - xSide + pw, yOffset), d->_rectImage, + QRect(d->_rectImage.width()/2, 0, 1, yOffset)); // Upper right - if (d->_rectImage.width() - offset) { - p.drawImage(QPoint(width()-offset, 0), d->_rectImage, - QRect(d->_rectImage.width()-offset, 0, offset, offset)); - } + p.drawImage(QPoint(width()-xOffset+pw/2, -pw/2), d->_rectImage, + QRect(d->_rectImage.width()-xOffset, 0, xOffset, yOffset)); // Middle left - if (d->_rectImage.height() - ySide) - p.drawImage(QRect(0, offset, offset, height() - ySide), d->_rectImage, - QRect(0, offset, offset, d->_rectImage.height() - ySide)); + if (yMiddles) + p.drawImage(QRect(-pw/2, yOffset-pw/2, xOffset, height() - ySide + pw), d->_rectImage, + QRect(0, d->_rectImage.height()/2, xOffset, 1)); // Middle - if (d->_rectImage.width() - xSide && d->_rectImage.height() - ySide) - p.drawImage(QRect(offset, offset, width() - xSide, height() - ySide), d->_rectImage, - QRect(offset, offset, d->_rectImage.width() - xSide, d->_rectImage.height() - ySide)); - // Midlle right - if (d->_rectImage.height() - ySide) - p.drawImage(QRect(width()-offset, offset, offset, height() - ySide), d->_rectImage, - QRect(d->_rectImage.width()-offset, offset, offset, d->_rectImage.height() - ySide)); + if (xMiddles && yMiddles) + // XXX paint errors in animation example + //p.fillRect(xOffset-pw/2, yOffset-pw/2, width() - xSide + pw, height() - ySide + pw, d->getColor()); + p.drawImage(QRect(xOffset-pw/2, yOffset-pw/2, width() - xSide + pw, height() - ySide + pw), d->_rectImage, + QRect(d->_rectImage.width()/2, d->_rectImage.height()/2, 1, 1)); + // Middle right + if (yMiddles) + p.drawImage(QRect(width()-xOffset+pw/2, yOffset-pw/2, xOffset, height() - ySide + pw), d->_rectImage, + QRect(d->_rectImage.width()-xOffset, d->_rectImage.height()/2, xOffset, 1)); // Lower left - p.drawImage(QPoint(0, height() - offset), d->_rectImage, QRect(0, d->_rectImage.height() - offset, offset, offset)); + p.drawImage(QPoint(-pw/2, height() - yOffset + pw/2), d->_rectImage, QRect(0, d->_rectImage.height() - yOffset, xOffset, yOffset)); // Lower Middle - if (d->_rectImage.width() - xSide) - p.drawImage(QRect(offset, height() - offset, width() - xSide, offset), d->_rectImage, - QRect(offset, d->_rectImage.height() - offset, d->_rectImage.width() - xSide, offset)); + if (xMiddles) + p.drawImage(QRect(xOffset-pw/2, height() - yOffset +pw/2, width() - xSide + pw, yOffset), d->_rectImage, + QRect(d->_rectImage.width()/2, d->_rectImage.height() - yOffset, 1, yOffset)); // Lower Right - if (d->_rectImage.width() - offset) - p.drawImage(QPoint(width()-offset, height() - offset), d->_rectImage, - QRect(d->_rectImage.width()-offset, d->_rectImage.height() - offset, offset, offset)); + p.drawImage(QPoint(width()-xOffset+pw/2, height() - yOffset+pw/2), d->_rectImage, + QRect(d->_rectImage.width()-xOffset, d->_rectImage.height() - yOffset, xOffset, yOffset)); } } #endif @@ -586,53 +655,60 @@ void QFxRect::paintGLContents(GLPainter &p) } } else { qreal offset = 0; + qreal pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0.0; + if (d->_radius > 0) { generateRoundedRect(); - offset = d->_radius; + offset = d->_radius + pw+1.5; } else { generateBorderedRect(); - offset = d->pen()->width(); + offset = pw+1.5; } QGLShaderProgram *shader = p.useTextureShader(); - float imgWidth = d->_rectTexture.width(); - float imgHeight = d->_rectTexture.height(); - if (!imgWidth || !imgHeight) + float texWidth = d->_rectTexture.width(); + float texHeight = d->_rectTexture.height(); + if (!texWidth || !texHeight) return; - float widthV = width(); - float heightV = height(); + float widthV = qreal(width())+pw/2; + float heightV = qreal(height())+pw/2; - float texleft = 0; - float texright = 1; - float textop = 1; - float texbottom = 0; - float imgleft = 0; - float imgright = widthV; - float imgtop = 0; - float imgbottom = heightV; + float xOffset = offset; + bool xMiddles = true; + if (xOffset*2 > width()+pw) { + xMiddles = false; + xOffset = (width()+pw)/2; + } + float yOffset = offset; + bool yMiddles = true; + if (yOffset*2 > height()+pw) { + yMiddles = false; + yOffset = (height()+pw)/2; + } - texleft = float(offset) / imgWidth; - imgleft = offset; - texright = 1. - float(offset) / imgWidth; - imgright = widthV - offset; - textop = 1. - float(offset) / imgHeight; - imgtop = offset; - texbottom = float(offset) / imgHeight; - imgbottom = heightV - offset; + float texleft = xOffset / texWidth; + float imgleft = xOffset-pw/2; + float texright = (texWidth-xOffset) / texWidth; + float imgright = widthV - xOffset; + + float textop = yOffset / texHeight; + float imgtop = yOffset-pw/2; + float texbottom = (texHeight-yOffset) / texHeight; + float imgbottom = heightV - yOffset; //Bug 231768: Inappropriate interpolation was occuring on 3x3 textures if (offset==1) texleft=texright=textop=texbottom=0.5; - float vert1[] = { 0, 0, - 0, imgtop, - imgleft, 0, + float vert1[] = { -pw/2, -pw/2, + -pw/2, imgtop, + imgleft, -pw/2, imgleft, imgtop, - imgright, 0, + imgright, -pw/2, imgright, imgtop, - widthV, 0, + widthV, -pw/2, widthV, imgtop }; float tex1[] = { 0, 0, 0, textop, @@ -642,8 +718,8 @@ void QFxRect::paintGLContents(GLPainter &p) texright, textop, 1, 0, 1, textop }; - float vert2[] = { 0, imgtop, - 0, imgbottom, + float vert2[] = { -pw/2, imgtop, + -pw/2, imgbottom, imgleft, imgtop, imgleft, imgbottom, imgright, imgtop, @@ -658,31 +734,33 @@ void QFxRect::paintGLContents(GLPainter &p) texright, texbottom, 1, textop, 1, texbottom }; - float vert3[] = { 0, imgbottom, - 0, heightV, - imgleft, imgbottom, + float vert3[] = { -pw/2, heightV, + -pw/2, imgbottom, imgleft, heightV, - imgright, imgbottom, + imgleft, imgbottom, imgright, heightV, - widthV, imgbottom, - widthV, heightV }; - float tex3[] = { 0, texbottom, - 0, 0, + imgright, imgbottom, + widthV, heightV, + widthV, imgbottom }; + float tex3[] = { 0, 1, + 0, texbottom, + texleft, 1, texleft, texbottom, - texleft, 0, + texright, 1, texright, texbottom, - texright, 0, - 1, texbottom, - 1, 0 }; + 1, 1, + 1, texbottom }; glBindTexture(GL_TEXTURE_2D, d->_rectTexture.texture()); shader->setAttributeArray(SingleTextureShader::Vertices, vert1, 2); shader->setAttributeArray(SingleTextureShader::TextureCoords, tex1, 2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 8); - shader->setAttributeArray(SingleTextureShader::Vertices, vert2, 2); - shader->setAttributeArray(SingleTextureShader::TextureCoords, tex2, 2); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 8); + if (yMiddles) { + shader->setAttributeArray(SingleTextureShader::Vertices, vert2, 2); + shader->setAttributeArray(SingleTextureShader::TextureCoords, tex2, 2); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 8); + } shader->setAttributeArray(SingleTextureShader::Vertices, vert3, 2); shader->setAttributeArray(SingleTextureShader::TextureCoords, tex3, 2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 8); @@ -761,9 +839,9 @@ void QFxRect::paintGLContents(GLPainter &p) glColor4f(1, 1, 1, p.activeOpacity); } - float imgWidth = d->_rectTexture.width(); - float imgHeight = d->_rectTexture.height(); - if (!imgWidth || !imgHeight) + float texWidth = d->_rectTexture.width(); + float texHeight = d->_rectTexture.height(); + if (!texWidth || !texHeight) return; float widthV = width(); @@ -778,13 +856,13 @@ void QFxRect::paintGLContents(GLPainter &p) float imgtop = 0; float imgbottom = heightV; - texleft = float(offset) / imgWidth; + texleft = float(offset) / texWidth; imgleft = offset; - texright = 1. - float(offset) / imgWidth; + texright = 1. - float(offset) / texWidth; imgright = widthV - offset; - textop = 1. - float(offset) / imgHeight; + textop = 1. - float(offset) / texHeight; imgtop = offset; - texbottom = float(offset) / imgHeight; + texbottom = float(offset) / texHeight; imgbottom = heightV - offset; float vert1[] = { 0, 0, diff --git a/src/declarative/fx/qfxrect.h b/src/declarative/fx/qfxrect.h index 42e7b2f..420ec44 100644 --- a/src/declarative/fx/qfxrect.h +++ b/src/declarative/fx/qfxrect.h @@ -42,7 +42,7 @@ #ifndef QFXRECT_H #define QFXRECT_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER @@ -58,11 +58,11 @@ class Q_DECLARATIVE_EXPORT QFxPen : public QObject Q_PROPERTY(QColor color READ color WRITE setColor) public: QFxPen(QObject *parent=0) - : QObject(parent), _width(1), _color("#000000"), _valid(false) + : QObject(parent), _width(0), _color("#000000"), _valid(false) {} int width() const { return _width; } - void setWidth(int w) { _width = w; emit updated(); _valid = (_width < 1) ? false : true; } + void setWidth(int w); QColor color() const { return _color; } void setColor(const QColor &c); diff --git a/src/declarative/fx/qfxreflectionfilter.h b/src/declarative/fx/qfxreflectionfilter.h index b0cc7b2..383e12f 100644 --- a/src/declarative/fx/qfxreflectionfilter.h +++ b/src/declarative/fx/qfxreflectionfilter.h @@ -42,8 +42,8 @@ #ifndef QFXREFLECTIONFILTER_H #define QFXREFLECTIONFILTER_H -#include <qsimplecanvasfilter.h> -#include <qml.h> +#include <QtDeclarative/qsimplecanvasfilter.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxrepeater.h b/src/declarative/fx/qfxrepeater.h index 8efd281..362242b 100644 --- a/src/declarative/fx/qfxrepeater.h +++ b/src/declarative/fx/qfxrepeater.h @@ -42,7 +42,7 @@ #ifndef QFXREPEATER_H #define QFXREPEATER_H -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxscalegrid.h b/src/declarative/fx/qfxscalegrid.h index 9010ce7..d0f735f 100644 --- a/src/declarative/fx/qfxscalegrid.h +++ b/src/declarative/fx/qfxscalegrid.h @@ -42,13 +42,13 @@ #ifndef QFXSCALEGRID_H #define QFXSCALEGRID_H -#include <qfxglobal.h> -#include <QImage> -#include <QString> -#include <QObject> -#include <qsimplecanvas.h> -#include <qfxpixmap.h> -#include <qml.h> +#include <QtCore/QString> +#include <QtCore/QObject> +#include <QtGui/QImage> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qsimplecanvas.h> +#include <QtDeclarative/qfxpixmap.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxshadowfilter.h b/src/declarative/fx/qfxshadowfilter.h index 9ba3b7b..fc54e01 100644 --- a/src/declarative/fx/qfxshadowfilter.h +++ b/src/declarative/fx/qfxshadowfilter.h @@ -42,8 +42,8 @@ #ifndef QFXSHADOWFILTER_H #define QFXSHADOWFILTER_H -#include <qsimplecanvasfilter.h> -#include <qml.h> +#include <QtDeclarative/qsimplecanvasfilter.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxtext.cpp b/src/declarative/fx/qfxtext.cpp index a43219d..e84255d 100644 --- a/src/declarative/fx/qfxtext.cpp +++ b/src/declarative/fx/qfxtext.cpp @@ -458,10 +458,11 @@ void QFxTextPrivate::updateSize() singleline = !tmp.contains(QChar::LineSeparator); if (singleline && elideMode != Qt::ElideNone && q->widthValid()) tmp = fm.elidedText(tmp,elideMode,q->width()); // XXX still worth layout...? - QTextLayout layout; + layout.clearLayout(); layout.setFont(f); layout.setText(tmp); size = setupTextLayout(&layout); + cachedLayoutSize = size; } if (richText) { singleline = false; // richtext can't elide or be optimized for single-line case @@ -608,18 +609,11 @@ QImage QFxTextPrivate::wrappedTextImage(bool drawStyle) //do layout Q_Q(const QFxText); QFont f; if (_font) f = _font->font(); - QString tmp = text; - if (singleline && elideMode != Qt::ElideNone && q->widthValid()) { - QFontMetrics fm(f); - tmp = fm.elidedText(tmp,elideMode,q->width()); // XXX still worth layout...? - } - tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); - QTextLayout textLayout(tmp, f); - QSize size = setupTextLayout(&textLayout); + QSize size = cachedLayoutSize; int x = 0; - for (int i = 0; i < textLayout.lineCount(); ++i) { - QTextLine line = textLayout.lineAt(i); + for (int i = 0; i < layout.lineCount(); ++i) { + QTextLine line = layout.lineAt(i); if (hAlign == QFxText::AlignLeft) { x = 0; } else if (hAlign == QFxText::AlignRight) { @@ -640,7 +634,7 @@ QImage QFxTextPrivate::wrappedTextImage(bool drawStyle) else p.setPen(color); p.setFont(f); - textLayout.draw(&p, QPointF(0, 0)); + layout.draw(&p, QPointF(0, 0)); return img; } @@ -749,7 +743,16 @@ void QFxText::paintContents(QPainter &p) break; } + bool needClip = !clip() && (d->imgCache.width() > width() || + d->imgCache.height() > height()); + + if (needClip) { + p.save(); + p.setClipRect(boundingRect()); + } p.drawImage(x, y, d->imgCache); + if (needClip) + p.restore(); } #elif defined(QFX_RENDER_OPENGL2) diff --git a/src/declarative/fx/qfxtext.h b/src/declarative/fx/qfxtext.h index 0de884b..ee9082b 100644 --- a/src/declarative/fx/qfxtext.h +++ b/src/declarative/fx/qfxtext.h @@ -42,8 +42,8 @@ #ifndef QFXTEXT_H #define QFXTEXT_H -#include <qfxitem.h> -#include <qmlfont.h> +#include <QtDeclarative/qfxitem.h> +#include <QtDeclarative/qmlfont.h> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxtext_p.h b/src/declarative/fx/qfxtext_p.h index 4296891..8bb3142 100644 --- a/src/declarative/fx/qfxtext_p.h +++ b/src/declarative/fx/qfxtext_p.h @@ -56,6 +56,7 @@ #include "qfxitem.h" #include "qfxitem_p.h" #include "qml.h" +#include <QtGui/qtextlayout.h> #if defined(QFX_RENDER_OPENGL) #include "gltexture.h" @@ -72,7 +73,9 @@ class QFxTextPrivate : public QFxItemPrivate Q_DECLARE_PUBLIC(QFxText) public: QFxTextPrivate() - : _font(0), color((QRgb)0), style(QFxText::Normal), imgDirty(true), hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), elideMode(Qt::ElideNone), dirty(false), wrap(false), richText(false), singleline(false), control(0), doc(0) + : _font(0), color((QRgb)0), style(QFxText::Normal), imgDirty(true), + hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), elideMode(Qt::ElideNone), + dirty(false), wrap(false), richText(false), singleline(false), control(0), doc(0) { } @@ -126,6 +129,8 @@ public: bool singleline; QTextControl *control; QTextDocument *doc; + QTextLayout layout; + QSize cachedLayoutSize; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 35b1173..8667c9e 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -662,7 +662,6 @@ void QFxTextEdit::keyReleaseEvent(QKeyEvent *event) */ void QFxTextEdit::focusChanged(bool hasFocus) { - Q_D(QFxTextEdit); setCursorVisible(hasFocus); } @@ -675,29 +674,6 @@ void QFxTextEdit::selectAll() d->control->selectAll(); } -static QMouseEvent *sceneMouseEventToMouseEvent(QGraphicsSceneMouseEvent *e) -{ - QEvent::Type t; - switch(e->type()) { - default: - case QEvent::GraphicsSceneMousePress: - t = QEvent::MouseButtonPress; - break; - case QEvent::GraphicsSceneMouseRelease: - t = QEvent::MouseButtonRelease; - break; - case QEvent::GraphicsSceneMouseMove: - t = QEvent::MouseMove; - break; - case QGraphicsSceneEvent::GraphicsSceneMouseDoubleClick: - t = QEvent::MouseButtonDblClick; - break; - } - - QMouseEvent *me = new QMouseEvent(t, e->pos().toPoint(), e->button(), e->buttons(), 0); - return me; -} - /*! \overload Handles the given mouse \a event. @@ -707,10 +683,7 @@ void QFxTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) Q_D(QFxTextEdit); if (d->focusOnPress) setFocus(true); - QMouseEvent *me = sceneMouseEventToMouseEvent(event); - d->control->processEvent(me, QPointF(0, 0)); - event->setAccepted(me->isAccepted()); - delete me; + d->control->processEvent(event, QPointF(0, 0)); if (!event->isAccepted()) QFxPaintedItem::mousePressEvent(event); } @@ -722,10 +695,7 @@ Handles the given mouse \a event. void QFxTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_D(QFxTextEdit); - QMouseEvent *me = sceneMouseEventToMouseEvent(event); - d->control->processEvent(me, QPointF(0, 0)); - event->setAccepted(me->isAccepted()); - delete me; + d->control->processEvent(event, QPointF(0, 0)); if (!event->isAccepted()) QFxPaintedItem::mousePressEvent(event); } @@ -737,10 +707,7 @@ Handles the given mouse \a event. void QFxTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { Q_D(QFxTextEdit); - QMouseEvent *me = sceneMouseEventToMouseEvent(event); - d->control->processEvent(me, QPointF(0, 0)); - event->setAccepted(me->isAccepted()); - delete me; + d->control->processEvent(event, QPointF(0, 0)); if (!event->isAccepted()) QFxPaintedItem::mousePressEvent(event); } diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h index 0aaa17b..f702101 100644 --- a/src/declarative/fx/qfxtextedit.h +++ b/src/declarative/fx/qfxtextedit.h @@ -42,8 +42,8 @@ #ifndef QFXTEXTEDIT_H #define QFXTEXTEDIT_H -#include <qfxtext.h> -#include <qfxpainteditem.h> +#include <QtDeclarative/qfxtext.h> +#include <QtDeclarative/qfxpainteditem.h> #include <QtGui/qtextdocument.h> #include <QtGui/qtextoption.h> diff --git a/src/declarative/fx/qfxtransform.cpp b/src/declarative/fx/qfxtransform.cpp index 7b76367..d99af27 100644 --- a/src/declarative/fx/qfxtransform.cpp +++ b/src/declarative/fx/qfxtransform.cpp @@ -179,6 +179,20 @@ void QFxAxis::setEndZ(qreal z) emit updated(); } +/*! + \qmlclass Rotation + \brief A Rotation object provides a way to rotate an Item around a point. + + The following example rotates a Rect around its interior point 25, 25: + \qml + Rect { + width: 100; height: 100 + color: "blue" + transform: Rotation { originX: 25; originY: 25; angle: 45} + } + \endqml +*/ + QFxRotation::QFxRotation(QObject *parent) : QFxTransform(parent), _originX(0), _originY(0), _angle(0), _dirty(true) { @@ -188,6 +202,12 @@ QFxRotation::~QFxRotation() { } +/*! + \qmlproperty real Rotation::originX + \qmlproperty real Rotation::originY + + The point to rotate around. +*/ qreal QFxRotation::originX() const { return _originX; @@ -210,6 +230,11 @@ void QFxRotation::setOriginY(qreal oy) update(); } +/*! + \qmlproperty real Rotation::angle + + The angle, in degrees, to rotate. +*/ qreal QFxRotation::angle() const { return _angle; @@ -217,8 +242,11 @@ qreal QFxRotation::angle() const void QFxRotation::setAngle(qreal angle) { + if (_angle == angle) + return; _angle = angle; update(); + emit angleChanged(); } bool QFxRotation::isIdentity() const @@ -244,7 +272,9 @@ QMatrix4x4 QFxRotation::transform() const if (_dirty) { _transform = QMatrix4x4(); _dirty = false; - _transform.rotate(_angle, _originX, _originY); + _transform.translate(_originX, _originY); + _transform.rotate(_angle, 0, 0, 1); + _transform.translate(-_originX, -_originY); } return _transform; } diff --git a/src/declarative/fx/qfxtransform.h b/src/declarative/fx/qfxtransform.h index a3a1a83..31374df 100644 --- a/src/declarative/fx/qfxtransform.h +++ b/src/declarative/fx/qfxtransform.h @@ -42,12 +42,12 @@ #ifndef QFXTRANSFORM_H #define QFXTRANSFORM_H -#include <QObject> -#include <QTransform> +#include <QtCore/QObject> +#include <QtGui/QTransform> #if defined(QFX_RENDER_OPENGL) #include <QtGui/qmatrix4x4.h> #endif -#include <qfxitem.h> +#include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER @@ -115,7 +115,7 @@ class Q_DECLARATIVE_EXPORT QFxRotation : public QFxTransform Q_PROPERTY(qreal originX READ originX WRITE setOriginX) Q_PROPERTY(qreal originY READ originY WRITE setOriginY) - Q_PROPERTY(qreal angle READ angle WRITE setAngle) + Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged()) public: QFxRotation(QObject *parent=0); ~QFxRotation(); @@ -132,6 +132,9 @@ public: virtual bool isIdentity() const; virtual QSimpleCanvas::Matrix transform() const; +Q_SIGNALS: + void angleChanged(); + private Q_SLOTS: void update(); private: diff --git a/src/declarative/fx/qfxvisualitemmodel.h b/src/declarative/fx/qfxvisualitemmodel.h index 7156d70..622065c 100644 --- a/src/declarative/fx/qfxvisualitemmodel.h +++ b/src/declarative/fx/qfxvisualitemmodel.h @@ -44,7 +44,7 @@ #include <QtCore/qobject.h> #include <QtCore/qabstractitemmodel.h> -#include <qml.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER @@ -62,7 +62,7 @@ class QFxItem; class QmlComponent; class QmlPackage; class QFxVisualItemModelPrivate; -class QFxVisualItemModel : public QObject +class Q_DECLARATIVE_EXPORT QFxVisualItemModel : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QFxVisualItemModel) diff --git a/src/declarative/fx/qfxwebview.h b/src/declarative/fx/qfxwebview.h index afd5b0f..6a3dad5 100644 --- a/src/declarative/fx/qfxwebview.h +++ b/src/declarative/fx/qfxwebview.h @@ -42,12 +42,12 @@ #ifndef QFXWEBVIEW_H #define QFXWEBVIEW_H -#include <QAction> -#include <QUrl> -#include <qfxglobal.h> -#include <qfxpainteditem.h> +#include <QtGui/QAction> +#include <QtCore/QUrl> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qfxpainteditem.h> #include <QtNetwork/qnetworkaccessmanager.h> -#include <QWebPage> +#include <QtWebKit/QWebPage> QT_BEGIN_HEADER diff --git a/src/declarative/fx/qfxwidgetcontainer.h b/src/declarative/fx/qfxwidgetcontainer.h index 65e4352..3b1f016 100644 --- a/src/declarative/fx/qfxwidgetcontainer.h +++ b/src/declarative/fx/qfxwidgetcontainer.h @@ -48,6 +48,8 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +QT_MODULE(Declarative) + class QGraphicsWidget; class Q_DECLARATIVE_EXPORT QFxWidgetContainer : public QFxItem diff --git a/src/declarative/opengl/glheaders.h b/src/declarative/opengl/glheaders.h index f0f6a55..fd1da18 100644 --- a/src/declarative/opengl/glheaders.h +++ b/src/declarative/opengl/glheaders.h @@ -42,7 +42,7 @@ #ifndef _GLHEADERS_H_ #define _GLHEADERS_H_ -#include <qfxglobal.h> +#include <QtDeclarative/qfxglobal.h> #define GL_GLEXT_PROTOTYPES 1 #include <QtOpenGL/qgl.h> diff --git a/src/declarative/opengl/glsave.h b/src/declarative/opengl/glsave.h index cca3d3c..8256162 100644 --- a/src/declarative/opengl/glsave.h +++ b/src/declarative/opengl/glsave.h @@ -42,9 +42,9 @@ #ifndef _GLSAVE_H_ #define _GLSAVE_H_ -#include <qglobal.h> -#include <qfxglobal.h> -#include <QRect> +#include <QtCore/qglobal.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtCore/QRect> #include "glheaders.h" diff --git a/src/declarative/opengl/gltexture.h b/src/declarative/opengl/gltexture.h index f920b60..8704498 100644 --- a/src/declarative/opengl/gltexture.h +++ b/src/declarative/opengl/gltexture.h @@ -42,10 +42,10 @@ #ifndef _GLTEXTURE_H_ #define _GLTEXTURE_H_ -#include <qfxglobal.h> +#include <QtDeclarative/qfxglobal.h> -#include <QRect> -#include <QPoint> +#include <QtCore/QRect> +#include <QtCore/QPoint> #include "glheaders.h" diff --git a/src/declarative/qml/parser/javascript.g b/src/declarative/qml/parser/javascript.g index 48e8244..155630b 100644 --- a/src/declarative/qml/parser/javascript.g +++ b/src/declarative/qml/parser/javascript.g @@ -46,7 +46,7 @@ %decl javascriptparser_p.h %impl javascriptparser.cpp %expect 2 -%expect-rr 1 +%expect-rr 2 %token T_AND "&" T_AND_AND "&&" T_AND_EQ "&=" %token T_BREAK "break" T_CASE "case" T_CATCH "catch" @@ -207,86 +207,71 @@ #include "javascriptgrammar_p.h" #include "javascriptast_p.h" +#include "javascriptengine_p.h" + #include <QtCore/QList> QT_BEGIN_NAMESPACE class QString; -class JavaScriptEnginePrivate; -class JavaScriptNameIdImpl; -class JavaScriptParser: protected $table +namespace JavaScript { + +class Engine; +class NameId; + +class Parser: protected $table { public: union Value { int ival; double dval; - JavaScriptNameIdImpl *sval; - JavaScript::AST::ArgumentList *ArgumentList; - JavaScript::AST::CaseBlock *CaseBlock; - JavaScript::AST::CaseClause *CaseClause; - JavaScript::AST::CaseClauses *CaseClauses; - JavaScript::AST::Catch *Catch; - JavaScript::AST::DefaultClause *DefaultClause; - JavaScript::AST::ElementList *ElementList; - JavaScript::AST::Elision *Elision; - JavaScript::AST::ExpressionNode *Expression; - JavaScript::AST::Finally *Finally; - JavaScript::AST::FormalParameterList *FormalParameterList; - JavaScript::AST::FunctionBody *FunctionBody; - JavaScript::AST::FunctionDeclaration *FunctionDeclaration; - JavaScript::AST::Node *Node; - JavaScript::AST::PropertyName *PropertyName; - JavaScript::AST::PropertyNameAndValueList *PropertyNameAndValueList; - JavaScript::AST::SourceElement *SourceElement; - JavaScript::AST::SourceElements *SourceElements; - JavaScript::AST::Statement *Statement; - JavaScript::AST::StatementList *StatementList; - JavaScript::AST::Block *Block; - JavaScript::AST::VariableDeclaration *VariableDeclaration; - JavaScript::AST::VariableDeclarationList *VariableDeclarationList; - - JavaScript::AST::UiProgram *UiProgram; - JavaScript::AST::UiImportList *UiImportList; - JavaScript::AST::UiImport *UiImport; - JavaScript::AST::UiPublicMember *UiPublicMember; - JavaScript::AST::UiObjectDefinition *UiObjectDefinition; - JavaScript::AST::UiObjectInitializer *UiObjectInitializer; - JavaScript::AST::UiObjectBinding *UiObjectBinding; - JavaScript::AST::UiScriptBinding *UiScriptBinding; - JavaScript::AST::UiArrayBinding *UiArrayBinding; - JavaScript::AST::UiObjectMember *UiObjectMember; - JavaScript::AST::UiObjectMemberList *UiObjectMemberList; - JavaScript::AST::UiQualifiedId *UiQualifiedId; - }; - - struct DiagnosticMessage { - enum Kind { Warning, Error }; - - DiagnosticMessage() - : kind(Error) {} - - DiagnosticMessage(Kind kind, const JavaScript::AST::SourceLocation &loc, const QString &message) - : kind(kind), loc(loc), message(message) {} - - bool isWarning() const - { return kind == Warning; } - - bool isError() const - { return kind == Error; } - - Kind kind; - JavaScript::AST::SourceLocation loc; - QString message; + NameId *sval; + AST::ArgumentList *ArgumentList; + AST::CaseBlock *CaseBlock; + AST::CaseClause *CaseClause; + AST::CaseClauses *CaseClauses; + AST::Catch *Catch; + AST::DefaultClause *DefaultClause; + AST::ElementList *ElementList; + AST::Elision *Elision; + AST::ExpressionNode *Expression; + AST::Finally *Finally; + AST::FormalParameterList *FormalParameterList; + AST::FunctionBody *FunctionBody; + AST::FunctionDeclaration *FunctionDeclaration; + AST::Node *Node; + AST::PropertyName *PropertyName; + AST::PropertyNameAndValueList *PropertyNameAndValueList; + AST::SourceElement *SourceElement; + AST::SourceElements *SourceElements; + AST::Statement *Statement; + AST::StatementList *StatementList; + AST::Block *Block; + AST::VariableDeclaration *VariableDeclaration; + AST::VariableDeclarationList *VariableDeclarationList; + + AST::UiProgram *UiProgram; + AST::UiImportList *UiImportList; + AST::UiImport *UiImport; + AST::UiPublicMember *UiPublicMember; + AST::UiObjectDefinition *UiObjectDefinition; + AST::UiObjectInitializer *UiObjectInitializer; + AST::UiObjectBinding *UiObjectBinding; + AST::UiScriptBinding *UiScriptBinding; + AST::UiArrayBinding *UiArrayBinding; + AST::UiObjectMember *UiObjectMember; + AST::UiObjectMemberList *UiObjectMemberList; + AST::UiQualifiedId *UiQualifiedId; }; public: - JavaScriptParser(); - ~JavaScriptParser(); + Parser(Engine *engine); + ~Parser(); - bool parse(JavaScriptEnginePrivate *driver); + bool parse(); - JavaScript::AST::UiProgram *ast() + AST::UiProgram *ast() { return program; } QList<DiagnosticMessage> diagnosticMessages() const @@ -317,17 +302,20 @@ protected: inline Value &sym(int index) { return sym_stack [tos + index - 1]; } - inline JavaScript::AST::SourceLocation &loc(int index) + inline AST::SourceLocation &loc(int index) { return location_stack [tos + index - 1]; } + AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); + protected: + Engine *driver; int tos; int stack_size; Value *sym_stack; int *state_stack; - JavaScript::AST::SourceLocation *location_stack; + AST::SourceLocation *location_stack; - JavaScript::AST::UiProgram *program; + AST::UiProgram *program; // error recovery enum { TOKEN_BUFFER_SIZE = 3 }; @@ -335,12 +323,12 @@ protected: struct SavedToken { int token; double dval; - JavaScript::AST::SourceLocation loc; + AST::SourceLocation loc; }; double yylval; - JavaScript::AST::SourceLocation yylloc; - JavaScript::AST::SourceLocation yyprevlloc; + AST::SourceLocation yylloc; + AST::SourceLocation yyprevlloc; SavedToken token_buffer[TOKEN_BUFFER_SIZE]; SavedToken *first_token; @@ -349,12 +337,16 @@ protected: QList<DiagnosticMessage> diagnostic_messages; }; +} // end of namespace JavaScript + + :/ /. #include "javascriptparser_p.h" +#include <QVarLengthArray> // // This file is automatically generated from javascript.g. @@ -365,7 +357,7 @@ using namespace JavaScript; QT_BEGIN_NAMESPACE -void JavaScriptParser::reallocateStack() +void Parser::reallocateStack() { if (! stack_size) stack_size = 128; @@ -377,7 +369,7 @@ void JavaScriptParser::reallocateStack() location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation))); } -inline static bool automatic(JavaScriptEnginePrivate *driver, int token) +inline static bool automatic(Engine *driver, int token) { return token == $table::T_RBRACE || token == 0 @@ -385,7 +377,8 @@ inline static bool automatic(JavaScriptEnginePrivate *driver, int token) } -JavaScriptParser::JavaScriptParser(): +Parser::Parser(Engine *engine): + driver(engine), tos(0), stack_size(0), sym_stack(0), @@ -396,7 +389,7 @@ JavaScriptParser::JavaScriptParser(): { } -JavaScriptParser::~JavaScriptParser() +Parser::~Parser() { if (stack_size) { qFree(sym_stack); @@ -415,7 +408,35 @@ static inline AST::SourceLocation location(Lexer *lexer) return loc; } -bool JavaScriptParser::parse(JavaScriptEnginePrivate *driver) +AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) +{ + QVarLengthArray<NameId *, 4> nameIds; + QVarLengthArray<AST::SourceLocation, 4> locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) { + AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name); + q->identifierToken = idExpr->identifierToken; + + AST::UiQualifiedId *currentId = q; + for (int i = nameIds.size() - 1; i != -1; --i) { + currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]); + currentId->identifierToken = locations[i]; + } + + return currentId->finish(); + } + + return 0; +} + +bool Parser::parse() { Lexer *lexer = driver->lexer(); bool hadErrors = false; @@ -475,7 +496,7 @@ UiProgram: UiImportListOpt UiRootMember ; case $rule_number: { program = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, sym(2).UiObjectMemberList->finish()); - sym(1).UiProgram = program; + sym(1).UiProgram = program; } break; ./ @@ -580,23 +601,11 @@ case $rule_number: { } break; ./ -UiObjectMember: UiQualifiedId T_COLON T_IDENTIFIER UiObjectInitializer ; +UiObjectDefinition: UiQualifiedId UiObjectInitializer ; /. case $rule_number: { - AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), sym(1).UiQualifiedId->finish(), - sym(3).sval, sym(4).UiObjectInitializer); - node->colonToken = loc(2); - node->identifierToken = loc(3); - sym(1).Node = node; -} break; -./ - -UiObjectDefinition: T_IDENTIFIER UiObjectInitializer ; -/. -case $rule_number: { - AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).sval, + AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(2).UiObjectInitializer); - node->identifierToken = loc(1); sym(1).Node = node; } break; ./ @@ -634,11 +643,46 @@ case $rule_number: { } break; ./ -UiObjectMember: UiQualifiedId T_COLON UiMultilineStringStatement ; -/. case $rule_number: ./ -UiObjectMember: UiQualifiedId T_COLON Statement ; + +UiObjectMember: UiQualifiedId T_COLON Expression UiObjectInitializer ; /. case $rule_number: { + if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(3).Expression)) { + AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + sym(1).UiQualifiedId->finish(), qualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + sym(1).Node = node; + } else { + sym(1).Node = 0; + + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(2), + QLatin1String("Expected a type name after token `:'"))); + + return false; // ### recover + } +} break; +./ + +UiObjectMember: UiQualifiedId T_COLON Block ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON EmptyStatement ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON ExpressionStatement ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON DebuggerStatement ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON UiMultilineStringStatement ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON IfStatement ; --- ### do we really want if statement in a binding? +/.case $rule_number:./ + +/. +{ AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(3).Statement); node->colonToken = loc(2); @@ -648,7 +692,7 @@ case $rule_number: { UiPropertyType: T_VAR ; /. -case $rule_number: +case $rule_number: ./ UiPropertyType: T_RESERVED_WORD ; /. @@ -663,7 +707,7 @@ UiPropertyType: T_IDENTIFIER ; UiObjectMember: T_SIGNAL T_IDENTIFIER ; /. case $rule_number: { - AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (JavaScriptNameIdImpl *)0, sym(2).sval); + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); node->typeToken = loc(2); @@ -779,25 +823,6 @@ case $rule_number: { } ./ -UiQualifiedId: JsIdentifier ; -/. -case $rule_number: { - AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).sval); - node->identifierToken = loc(1); - sym(1).Node = node; -} break; -./ - -UiQualifiedId: UiQualifiedId T_DOT JsIdentifier ; -/. -case $rule_number: { - AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).UiQualifiedId, sym(3).sval); - node->identifierToken = loc(3); - sym(1).Node = node; -} break; -./ - - -------------------------------------------------------------------------------------------------------- -- Expressions -------------------------------------------------------------------------------------------------------- @@ -899,10 +924,20 @@ case $rule_number: { } break; ./ -PrimaryExpression: T_LBRACKET ElisionOpt T_RBRACKET ; +PrimaryExpression: T_LBRACKET T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->rbracketToken = loc(2); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET Elision T_RBRACKET ; /. case $rule_number: { - AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision); + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; @@ -919,10 +954,23 @@ case $rule_number: { } break; ./ -PrimaryExpression: T_LBRACKET ElementList T_COMMA ElisionOpt T_RBRACKET ; +PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ; /. case $rule_number: { - AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), sym(4).Elision); + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + sym(4).Elision->finish()); node->lbracketToken = loc(1); node->commaToken = loc(3); node->rbracketToken = loc(5); @@ -973,51 +1021,73 @@ case $rule_number: { } break; ./ -ElementList: ElisionOpt AssignmentExpression ; +UiQualifiedId: JsIdentifier ; +/. +case $rule_number: { + AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +UiQualifiedId: UiQualifiedId T_DOT JsIdentifier ; /. case $rule_number: { - sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision, sym(2).Expression); + AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).UiQualifiedId, sym(3).sval); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; +./ + +ElementList: AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); } break; ./ -ElementList: ElementList T_COMMA ElisionOpt AssignmentExpression ; +ElementList: Elision AssignmentExpression ; /. case $rule_number: { - AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision, sym(4).Expression); - node->commaToken = loc(2); - sym(1).Node = node; + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); } break; ./ -Elision: T_COMMA ; +ElementList: ElementList T_COMMA AssignmentExpression ; /. case $rule_number: { - AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); - node->commaToken = loc(1); + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, + (AST::Elision *) 0, sym(3).Expression); + node->commaToken = loc(2); sym(1).Node = node; } break; ./ -Elision: Elision T_COMMA ; +ElementList: ElementList T_COMMA Elision AssignmentExpression ; /. case $rule_number: { - AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(), + sym(4).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; ./ -ElisionOpt: %prec SHIFT_THERE ; +Elision: T_COMMA ; /. case $rule_number: { - sym(1).Node = 0; + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); + node->commaToken = loc(1); + sym(1).Node = node; } break; ./ -ElisionOpt: Elision ; +Elision: Elision T_COMMA ; /. case $rule_number: { - sym(1).Elision = sym(1).Elision->finish (); + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); + node->commaToken = loc(2); + sym(1).Node = node; } break; ./ @@ -1038,7 +1108,7 @@ case $rule_number: { sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); node->commaToken = loc(2); node->colonToken = loc(4); - sym(1).Node = node; + sym(1).Node = node; } break; ./ @@ -1047,7 +1117,7 @@ PropertyName: T_IDENTIFIER %prec REDUCE_HERE ; case $rule_number: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; ./ @@ -1059,7 +1129,7 @@ PropertyName: T_PROPERTY ; case $rule_number: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; ./ @@ -1068,7 +1138,7 @@ PropertyName: T_STRING_LITERAL ; case $rule_number: { AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; ./ @@ -1077,7 +1147,7 @@ PropertyName: T_NUMERIC_LITERAL ; case $rule_number: { AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; ./ @@ -1086,7 +1156,7 @@ PropertyName: ReservedIdentifier ; case $rule_number: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; ./ diff --git a/src/declarative/qml/parser/javascriptast.cpp b/src/declarative/qml/parser/javascriptast.cpp index 8a10650..083dd28 100644 --- a/src/declarative/qml/parser/javascriptast.cpp +++ b/src/declarative/qml/parser/javascriptast.cpp @@ -813,6 +813,7 @@ void UiPublicMember::accept0(Visitor *visitor) void UiObjectDefinition::accept0(Visitor *visitor) { if (visitor->visit(this)) { + acceptChild(qualifiedTypeNameId, visitor); acceptChild(initializer, visitor); } @@ -833,6 +834,7 @@ void UiObjectBinding::accept0(Visitor *visitor) { if (visitor->visit(this)) { acceptChild(qualifiedId, visitor); + acceptChild(qualifiedTypeNameId, visitor); acceptChild(initializer, visitor); } diff --git a/src/declarative/qml/parser/javascriptast_p.h b/src/declarative/qml/parser/javascriptast_p.h index cd47e42..134f3cc 100644 --- a/src/declarative/qml/parser/javascriptast_p.h +++ b/src/declarative/qml/parser/javascriptast_p.h @@ -53,18 +53,15 @@ // We mean it. // -#include <QtCore/QString> - - - #include "javascriptastvisitor_p.h" +#include <QtCore/QString> QT_BEGIN_NAMESPACE #define JAVASCRIPT_DECLARE_AST_NODE(name) \ enum { K = Kind_##name }; -class JavaScriptNameIdImpl; +class NameId; namespace QSOperator // ### rename { @@ -120,27 +117,6 @@ _T1 cast(_T2 *ast) return 0; } -class SourceLocation -{ -public: - SourceLocation(quint32 offset = 0, quint32 length = 0) - : offset(offset), length(length), - startLine(0), startColumn(0) - { } - - bool isValid() const { return length != 0; } - - quint32 begin() const { return offset; } - quint32 end() const { return offset + length; } - -// attributes - // ### encode - quint32 offset; - quint32 length; - quint32 startLine; - quint32 startColumn; -}; - class Node { public: @@ -339,7 +315,7 @@ class IdentifierExpression: public ExpressionNode public: JAVASCRIPT_DECLARE_AST_NODE(IdentifierExpression) - IdentifierExpression(JavaScriptNameIdImpl *n): + IdentifierExpression(NameId *n): name (n) { kind = K; } virtual ~IdentifierExpression() {} @@ -353,7 +329,7 @@ public: { return identifierToken; } // attributes - JavaScriptNameIdImpl *name; + NameId *name; SourceLocation identifierToken; }; @@ -444,7 +420,7 @@ class StringLiteral: public ExpressionNode public: JAVASCRIPT_DECLARE_AST_NODE(StringLiteral) - StringLiteral(JavaScriptNameIdImpl *v): + StringLiteral(NameId *v): value (v) { kind = K; } virtual ~StringLiteral() {} @@ -458,7 +434,7 @@ public: { return literalToken; } // attributes: - JavaScriptNameIdImpl *value; + NameId *value; SourceLocation literalToken; }; @@ -467,7 +443,7 @@ class RegExpLiteral: public ExpressionNode public: JAVASCRIPT_DECLARE_AST_NODE(RegExpLiteral) - RegExpLiteral(JavaScriptNameIdImpl *p, int f): + RegExpLiteral(NameId *p, int f): pattern (p), flags (f) { kind = K; } virtual ~RegExpLiteral() {} @@ -481,7 +457,7 @@ public: { return literalToken; } // attributes: - JavaScriptNameIdImpl *pattern; + NameId *pattern; int flags; SourceLocation literalToken; }; @@ -667,7 +643,7 @@ class IdentifierPropertyName: public PropertyName public: JAVASCRIPT_DECLARE_AST_NODE(IdentifierPropertyName) - IdentifierPropertyName(JavaScriptNameIdImpl *n): + IdentifierPropertyName(NameId *n): id (n) { kind = K; } virtual ~IdentifierPropertyName() {} @@ -675,7 +651,7 @@ public: virtual void accept0(Visitor *visitor); // attributes - JavaScriptNameIdImpl *id; + NameId *id; }; class StringLiteralPropertyName: public PropertyName @@ -683,14 +659,14 @@ class StringLiteralPropertyName: public PropertyName public: JAVASCRIPT_DECLARE_AST_NODE(StringLiteralPropertyName) - StringLiteralPropertyName(JavaScriptNameIdImpl *n): + StringLiteralPropertyName(NameId *n): id (n) { kind = K; } virtual ~StringLiteralPropertyName() {} virtual void accept0(Visitor *visitor); // attributes - JavaScriptNameIdImpl *id; + NameId *id; }; class NumericLiteralPropertyName: public PropertyName @@ -739,7 +715,7 @@ class FieldMemberExpression: public ExpressionNode public: JAVASCRIPT_DECLARE_AST_NODE(FieldMemberExpression) - FieldMemberExpression(ExpressionNode *b, JavaScriptNameIdImpl *n): + FieldMemberExpression(ExpressionNode *b, NameId *n): base (b), name (n) { kind = K; } @@ -755,7 +731,7 @@ public: // attributes ExpressionNode *base; - JavaScriptNameIdImpl *name; + NameId *name; SourceLocation dotToken; SourceLocation identifierToken; }; @@ -1288,7 +1264,7 @@ class VariableDeclaration: public Node public: JAVASCRIPT_DECLARE_AST_NODE(VariableDeclaration) - VariableDeclaration(JavaScriptNameIdImpl *n, ExpressionNode *e): + VariableDeclaration(NameId *n, ExpressionNode *e): name (n), expression (e), readOnly(false) { kind = K; } @@ -1297,7 +1273,7 @@ public: virtual void accept0(Visitor *visitor); // attributes - JavaScriptNameIdImpl *name; + NameId *name; ExpressionNode *expression; bool readOnly; SourceLocation identifierToken; @@ -1602,7 +1578,7 @@ class ContinueStatement: public Statement public: JAVASCRIPT_DECLARE_AST_NODE(ContinueStatement) - ContinueStatement(JavaScriptNameIdImpl *l = 0): + ContinueStatement(NameId *l = 0): label (l) { kind = K; } virtual ~ContinueStatement() {} @@ -1616,7 +1592,7 @@ public: { return semicolonToken; } // attributes - JavaScriptNameIdImpl *label; + NameId *label; SourceLocation continueToken; SourceLocation identifierToken; SourceLocation semicolonToken; @@ -1627,7 +1603,7 @@ class BreakStatement: public Statement public: JAVASCRIPT_DECLARE_AST_NODE(BreakStatement) - BreakStatement(JavaScriptNameIdImpl *l = 0): + BreakStatement(NameId *l = 0): label (l) { kind = K; } virtual ~BreakStatement() {} @@ -1641,7 +1617,7 @@ public: { return semicolonToken; } // attributes - JavaScriptNameIdImpl *label; + NameId *label; SourceLocation breakToken; SourceLocation identifierToken; SourceLocation semicolonToken; @@ -1823,7 +1799,7 @@ class LabelledStatement: public Statement public: JAVASCRIPT_DECLARE_AST_NODE(LabelledStatement) - LabelledStatement(JavaScriptNameIdImpl *l, Statement *stmt): + LabelledStatement(NameId *l, Statement *stmt): label (l), statement (stmt) { kind = K; } @@ -1838,7 +1814,7 @@ public: { return statement->lastSourceLocation(); } // attributes - JavaScriptNameIdImpl *label; + NameId *label; Statement *statement; SourceLocation identifierToken; SourceLocation colonToken; @@ -1873,7 +1849,7 @@ class Catch: public Node public: JAVASCRIPT_DECLARE_AST_NODE(Catch) - Catch(JavaScriptNameIdImpl *n, Block *stmt): + Catch(NameId *n, Block *stmt): name (n), statement (stmt) { kind = K; } @@ -1882,7 +1858,7 @@ public: virtual void accept0(Visitor *visitor); // attributes - JavaScriptNameIdImpl *name; + NameId *name; Block *statement; SourceLocation catchToken; SourceLocation lparenToken; @@ -1954,7 +1930,7 @@ class FunctionExpression: public ExpressionNode public: JAVASCRIPT_DECLARE_AST_NODE(FunctionExpression) - FunctionExpression(JavaScriptNameIdImpl *n, FormalParameterList *f, FunctionBody *b): + FunctionExpression(NameId *n, FormalParameterList *f, FunctionBody *b): name (n), formals (f), body (b) { kind = K; } @@ -1969,7 +1945,7 @@ public: { return rbraceToken; } // attributes - JavaScriptNameIdImpl *name; + NameId *name; FormalParameterList *formals; FunctionBody *body; SourceLocation functionToken; @@ -1985,7 +1961,7 @@ class FunctionDeclaration: public FunctionExpression public: JAVASCRIPT_DECLARE_AST_NODE(FunctionDeclaration) - FunctionDeclaration(JavaScriptNameIdImpl *n, FormalParameterList *f, FunctionBody *b): + FunctionDeclaration(NameId *n, FormalParameterList *f, FunctionBody *b): FunctionExpression(n, f, b) { kind = K; } @@ -1999,11 +1975,11 @@ class FormalParameterList: public Node public: JAVASCRIPT_DECLARE_AST_NODE(FormalParameterList) - FormalParameterList(JavaScriptNameIdImpl *n): + FormalParameterList(NameId *n): name (n), next (this) { kind = K; } - FormalParameterList(FormalParameterList *previous, JavaScriptNameIdImpl *n): + FormalParameterList(FormalParameterList *previous, NameId *n): name (n) { kind = K; @@ -2023,7 +1999,7 @@ public: } // attributes - JavaScriptNameIdImpl *name; + NameId *name; FormalParameterList *next; SourceLocation commaToken; SourceLocation identifierToken; @@ -2185,11 +2161,11 @@ class UiQualifiedId: public Node public: JAVASCRIPT_DECLARE_AST_NODE(UiQualifiedId) - UiQualifiedId(JavaScriptNameIdImpl *name) + UiQualifiedId(NameId *name) : next(this), name(name) { kind = K; } - UiQualifiedId(UiQualifiedId *previous, JavaScriptNameIdImpl *name) + UiQualifiedId(UiQualifiedId *previous, NameId *name) : name(name) { kind = K; @@ -2210,7 +2186,7 @@ public: // attributes UiQualifiedId *next; - JavaScriptNameIdImpl *name; + NameId *name; SourceLocation identifierToken; }; @@ -2219,14 +2195,14 @@ class UiImport: public Node public: JAVASCRIPT_DECLARE_AST_NODE(UiImport) - UiImport(JavaScriptNameIdImpl *fileName) + UiImport(NameId *fileName) : fileName(fileName) { kind = K; } virtual void accept0(Visitor *visitor); // attributes - JavaScriptNameIdImpl *fileName; + NameId *fileName; SourceLocation importToken; SourceLocation fileNameToken; SourceLocation semicolonToken; @@ -2324,13 +2300,13 @@ class UiPublicMember: public UiObjectMember public: JAVASCRIPT_DECLARE_AST_NODE(UiPublicMember) - UiPublicMember(JavaScriptNameIdImpl *memberType, - JavaScriptNameIdImpl *name) + UiPublicMember(NameId *memberType, + NameId *name) : type(Property), memberType(memberType), name(name), expression(0), isDefaultMember(false) { kind = K; } - UiPublicMember(JavaScriptNameIdImpl *memberType, - JavaScriptNameIdImpl *name, + UiPublicMember(NameId *memberType, + NameId *name, ExpressionNode *expression) : type(Property), memberType(memberType), name(name), expression(expression), isDefaultMember(false) { kind = K; } @@ -2352,8 +2328,8 @@ public: // attributes enum { Signal, Property } type; - JavaScriptNameIdImpl *memberType; - JavaScriptNameIdImpl *name; + NameId *memberType; + NameId *name; ExpressionNode *expression; bool isDefaultMember; SourceLocation defaultToken; @@ -2369,28 +2345,22 @@ class UiObjectDefinition: public UiObjectMember public: JAVASCRIPT_DECLARE_AST_NODE(UiObjectDefinition) - UiObjectDefinition(JavaScriptNameIdImpl *name, + UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId, UiObjectInitializer *initializer) - : name(name), initializer(initializer) + : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer) { kind = K; } virtual SourceLocation firstSourceLocation() const - { return identifierToken; } + { return qualifiedTypeNameId->identifierToken; } virtual SourceLocation lastSourceLocation() const - { - if (initializer) - return initializer->rbraceToken; - - return identifierToken; - } + { return initializer->rbraceToken; } virtual void accept0(Visitor *visitor); // attributes - JavaScriptNameIdImpl *name; + UiQualifiedId *qualifiedTypeNameId; UiObjectInitializer *initializer; - SourceLocation identifierToken; }; class UiSourceElement: public UiObjectMember @@ -2435,10 +2405,10 @@ public: JAVASCRIPT_DECLARE_AST_NODE(UiObjectBinding) UiObjectBinding(UiQualifiedId *qualifiedId, - JavaScriptNameIdImpl *name, + UiQualifiedId *qualifiedTypeNameId, UiObjectInitializer *initializer) : qualifiedId(qualifiedId), - name(name), + qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer) { kind = K; } @@ -2452,10 +2422,9 @@ public: // attributes UiQualifiedId *qualifiedId; - JavaScriptNameIdImpl *name; + UiQualifiedId *qualifiedTypeNameId; UiObjectInitializer *initializer; SourceLocation colonToken; - SourceLocation identifierToken; }; class UiScriptBinding: public UiObjectMember diff --git a/src/declarative/qml/parser/javascriptastfwd_p.h b/src/declarative/qml/parser/javascriptastfwd_p.h index 858e393..822a2d7 100644 --- a/src/declarative/qml/parser/javascriptastfwd_p.h +++ b/src/declarative/qml/parser/javascriptastfwd_p.h @@ -59,7 +59,26 @@ QT_BEGIN_NAMESPACE namespace JavaScript { namespace AST { -class SourceLocation; +class SourceLocation +{ +public: + SourceLocation(quint32 offset = 0, quint32 length = 0) + : offset(offset), length(length), + startLine(0), startColumn(0) + { } + + bool isValid() const { return length != 0; } + + quint32 begin() const { return offset; } + quint32 end() const { return offset + length; } + +// attributes + // ### encode + quint32 offset; + quint32 length; + quint32 startLine; + quint32 startColumn; +}; class Visitor; class Node; diff --git a/src/declarative/qml/parser/javascriptengine_p.cpp b/src/declarative/qml/parser/javascriptengine_p.cpp index ca15b75..d893a90 100644 --- a/src/declarative/qml/parser/javascriptengine_p.cpp +++ b/src/declarative/qml/parser/javascriptengine_p.cpp @@ -29,7 +29,6 @@ #include "javascriptengine_p.h" #include "javascriptnodepool_p.h" -#include "javascriptvalue.h" #include <qnumeric.h> #include <QHash> @@ -37,7 +36,10 @@ QT_BEGIN_NAMESPACE namespace JavaScript { -QString numberToString(qjsreal value) +uint qHash(const JavaScript::NameId &id) +{ return qHash(id.asString()); } + +QString numberToString(double value) { return QString::number(value); } int Ecma::RegExp::flagFromChar(const QChar &ch) @@ -67,9 +69,10 @@ QString Ecma::RegExp::flagsToString(int flags) return result; } -NodePool::NodePool(const QString &fileName, JavaScriptEnginePrivate *engine) +NodePool::NodePool(const QString &fileName, Engine *engine) : m_fileName(fileName), m_engine(engine) { + m_engine->setNodePool(this); } NodePool::~NodePool() @@ -93,12 +96,12 @@ static int toDigit(char c) return -1; } -qjsreal integerFromString(const char *buf, int size, int radix) +double integerFromString(const char *buf, int size, int radix) { if (size == 0) return qSNaN(); - qjsreal sign = 1.0; + double sign = 1.0; int i = 0; if (buf[0] == '+') { ++i; @@ -130,7 +133,7 @@ qjsreal integerFromString(const char *buf, int size, int radix) if ((d == -1) || (d >= radix)) break; } - qjsreal result; + double result; if (j == i) { if (!qstrcmp(buf, "Infinity")) result = qInf(); @@ -138,7 +141,7 @@ qjsreal integerFromString(const char *buf, int size, int radix) result = qSNaN(); } else { result = 0; - qjsreal multiplier = 1; + double multiplier = 1; for (--i ; i >= j; --i, multiplier *= radix) result += toDigit(buf[i]) * multiplier; } @@ -146,12 +149,43 @@ qjsreal integerFromString(const char *buf, int size, int radix) return result; } -qjsreal integerFromString(const QString &str, int radix) +double integerFromString(const QString &str, int radix) { QByteArray ba = str.trimmed().toUtf8(); return integerFromString(ba.constData(), ba.size(), radix); } + +Engine::Engine() + : _lexer(0), _nodePool(0) +{ } + +Engine::~Engine() +{ } + +QSet<NameId> Engine::literals() const +{ return _literals; } + +NameId *Engine::intern(const QChar *u, int s) +{ return const_cast<NameId *>(&*_literals.insert(NameId(u, s))); } + +QString Engine::toString(NameId *id) +{ return id->asString(); } + +Lexer *Engine::lexer() const +{ return _lexer; } + +void Engine::setLexer(Lexer *lexer) +{ _lexer = lexer; } + +NodePool *Engine::nodePool() const +{ return _nodePool; } + +void Engine::setNodePool(NodePool *nodePool) +{ _nodePool = nodePool; } + + + } // end of namespace JavaScript QT_END_NAMESPACE diff --git a/src/declarative/qml/parser/javascriptengine_p.h b/src/declarative/qml/parser/javascriptengine_p.h index 1e6e568..3bd924a 100644 --- a/src/declarative/qml/parser/javascriptengine_p.h +++ b/src/declarative/qml/parser/javascriptengine_p.h @@ -30,23 +30,50 @@ #ifndef JAVASCRIPTENGINE_P_H #define JAVASCRIPTENGINE_P_H -#include "javascriptvalue.h" #include <QString> #include <QSet> +#include "javascriptastfwd_p.h" + QT_BEGIN_NAMESPACE namespace JavaScript { +class NameId +{ + QString _text; -class Node; -class Lexer; -class NodePool; +public: + NameId(const QChar *u, int s) + : _text(u, s) + { } -namespace AST { + const QString asString() const + { return _text; } -class Node; + bool operator == (const NameId &other) const + { return _text == other._text; } -} // end of namespace AST + bool operator != (const NameId &other) const + { return _text != other._text; } + + bool operator < (const NameId &other) const + { return _text < other._text; } +}; + +uint qHash(const JavaScript::NameId &id); + +} // end of namespace JavaScript + +#if defined(Q_CC_MSVC) && _MSC_VER <= 1300 +//this ensures that code outside JavaScript can use the hash function +//it also a workaround for some compilers +inline uint qHash(const JavaScript::NameId &nameId) { return JavaScript::qHash(nameId); } +#endif + +namespace JavaScript { + +class Lexer; +class NodePool; namespace Ecma { @@ -66,79 +93,53 @@ public: } // end of namespace Ecma -} // end of namespace JavaScript - - - -class JavaScriptNameIdImpl +class DiagnosticMessage { - QString _text; - public: - JavaScriptNameIdImpl(const QChar *u, int s) - : _text(u, s) - { } + enum Kind { Warning, Error }; - const QString asString() const - { return _text; } + DiagnosticMessage() + : kind(Error) {} - bool operator == (const JavaScriptNameIdImpl &other) const - { return _text == other._text; } + DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message) + : kind(kind), loc(loc), message(message) {} - bool operator != (const JavaScriptNameIdImpl &other) const - { return _text != other._text; } + bool isWarning() const + { return kind == Warning; } - bool operator < (const JavaScriptNameIdImpl &other) const - { return _text < other._text; } -}; + bool isError() const + { return kind == Error; } -inline uint qHash(const JavaScriptNameIdImpl &id) -{ return qHash(id.asString()); } + Kind kind; + AST::SourceLocation loc; + QString message; +}; -class JavaScriptEnginePrivate +class Engine { - JavaScript::Lexer *_lexer; - JavaScript::NodePool *_nodePool; - JavaScript::AST::Node *_ast; - QSet<JavaScriptNameIdImpl> _literals; + Lexer *_lexer; + NodePool *_nodePool; + QSet<NameId> _literals; public: - JavaScriptEnginePrivate() - : _lexer(0), _nodePool(0), _ast(0) - { } - - QSet<JavaScriptNameIdImpl> literals() const - { return _literals; } + Engine(); + ~Engine(); - JavaScriptNameIdImpl *intern(const QChar *u, int s) - { return const_cast<JavaScriptNameIdImpl *>(&*_literals.insert(JavaScriptNameIdImpl(u, s))); } + QSet<NameId> literals() const; - static QString toString(JavaScriptNameIdImpl *id) - { return id->asString(); } + NameId *intern(const QChar *u, int s); - JavaScript::Lexer *lexer() const - { return _lexer; } + static QString toString(NameId *id); - void setLexer(JavaScript::Lexer *lexer) - { _lexer = lexer; } + Lexer *lexer() const; + void setLexer(Lexer *lexer); - JavaScript::NodePool *nodePool() const - { return _nodePool; } - - void setNodePool(JavaScript::NodePool *nodePool) - { _nodePool = nodePool; } - - JavaScript::AST::Node *ast() const - { return _ast; } - - JavaScript::AST::Node *changeAbstractSyntaxTree(JavaScript::AST::Node *node) - { - JavaScript::AST::Node *previousAST = _ast; - _ast = node; - return previousAST; - } + NodePool *nodePool() const; + void setNodePool(NodePool *nodePool); }; +} // end of namespace JavaScript + QT_END_NAMESPACE #endif // JAVASCRIPTENGINE_P_H diff --git a/src/declarative/qml/parser/javascriptgrammar.cpp b/src/declarative/qml/parser/javascriptgrammar.cpp index abe3f1c..a879bfe 100644 --- a/src/declarative/qml/parser/javascriptgrammar.cpp +++ b/src/declarative/qml/parser/javascriptgrammar.cpp @@ -56,527 +56,585 @@ const char *const JavaScriptGrammar::spell [] = { const int JavaScriptGrammar::lhs [] = { 91, 92, 92, 95, 95, 96, 96, 94, 93, 98, - 98, 100, 100, 101, 101, 99, 97, 99, 99, 103, - 104, 104, 99, 99, 106, 106, 106, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, 102, 102, - 110, 110, 110, 102, 102, 111, 111, 111, 111, 111, - 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, - 113, 113, 117, 117, 112, 112, 115, 115, 118, 118, - 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 120, 120, 121, 121, 121, - 121, 121, 124, 124, 125, 125, 125, 125, 123, 123, - 126, 126, 127, 127, 128, 128, 128, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 130, 130, 130, - 130, 131, 131, 131, 132, 132, 132, 132, 133, 133, - 133, 133, 133, 133, 133, 134, 134, 134, 134, 134, - 134, 135, 135, 135, 135, 135, 136, 136, 136, 136, - 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, + 98, 100, 100, 101, 101, 97, 99, 99, 103, 104, + 104, 99, 99, 99, 99, 99, 99, 99, 111, 111, + 111, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 102, 102, 114, 114, 114, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, + 115, 115, 115, 115, 102, 102, 117, 117, 117, 117, + 116, 116, 119, 119, 121, 121, 121, 121, 121, 121, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 123, 123, 124, 124, 124, 124, 124, 127, 127, + 128, 128, 128, 128, 126, 126, 129, 129, 130, 130, + 131, 131, 131, 132, 132, 132, 132, 132, 132, 132, + 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, + 135, 135, 135, 135, 136, 136, 136, 136, 136, 136, + 136, 137, 137, 137, 137, 137, 137, 138, 138, 138, + 138, 138, 139, 139, 139, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143, 144, 144, 145, 145, 146, - 146, 147, 147, 148, 148, 116, 116, 149, 149, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 107, 107, 151, 151, 152, 152, 153, 153, 105, - 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 154, 169, 169, 168, 168, 109, - 109, 170, 170, 171, 171, 173, 173, 172, 174, 177, - 175, 175, 178, 176, 176, 155, 156, 156, 157, 157, - 158, 158, 158, 158, 158, 158, 158, 159, 159, 159, - 159, 160, 160, 160, 160, 161, 161, 162, 164, 179, - 179, 182, 182, 180, 180, 183, 181, 163, 163, 163, - 165, 165, 166, 166, 166, 184, 185, 167, 167, 108, - 122, 189, 189, 186, 186, 187, 187, 190, 191, 191, - 192, 192, 188, 188, 114, 114, 193}; + 146, 147, 147, 148, 148, 149, 149, 150, 150, 151, + 151, 120, 120, 152, 152, 153, 153, 153, 153, 153, + 153, 153, 153, 153, 153, 153, 153, 105, 105, 154, + 154, 155, 155, 156, 156, 157, 157, 157, 157, 157, + 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, + 106, 168, 168, 167, 167, 113, 113, 169, 169, 170, + 170, 172, 172, 171, 173, 176, 174, 174, 177, 175, + 175, 107, 108, 108, 110, 110, 158, 158, 158, 158, + 158, 158, 158, 159, 159, 159, 159, 160, 160, 160, + 160, 161, 161, 162, 164, 178, 178, 181, 181, 179, + 179, 182, 180, 163, 163, 163, 165, 165, 166, 166, + 166, 183, 184, 109, 109, 112, 125, 188, 188, 185, + 185, 186, 186, 189, 190, 190, 191, 191, 187, 187, + 118, 118, 192}; const int JavaScriptGrammar:: rhs[] = { 2, 1, 1, 1, 2, 3, 3, 0, 1, 1, - 2, 1, 3, 2, 3, 4, 2, 1, 5, 1, - 2, 2, 3, 3, 1, 1, 1, 2, 4, 4, - 5, 5, 6, 6, 7, 7, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 3, 5, 3, 4, 3, - 2, 4, 1, 2, 0, 1, 3, 5, 1, 1, + 2, 1, 3, 2, 3, 2, 1, 5, 1, 2, + 2, 4, 3, 3, 3, 3, 3, 3, 1, 1, + 1, 2, 4, 4, 5, 5, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, + 5, 3, 4, 3, 1, 3, 1, 2, 3, 4, + 1, 2, 3, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, - 3, 5, 1, 2, 4, 4, 4, 3, 0, 1, - 1, 3, 1, 1, 1, 2, 2, 1, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 1, 3, 3, - 3, 1, 3, 3, 1, 3, 3, 3, 1, 3, - 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, - 3, 1, 3, 3, 3, 3, 1, 3, 3, 3, - 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, - 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, - 3, 1, 5, 1, 5, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 0, 1, 1, 3, 0, 1, 1, + 1, 1, 1, 1, 1, 4, 3, 5, 1, 2, + 4, 4, 4, 3, 0, 1, 1, 3, 1, 1, + 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 3, 3, 3, 1, 3, 3, + 1, 3, 3, 3, 1, 3, 3, 3, 3, 3, + 3, 1, 3, 3, 3, 3, 3, 1, 3, 3, + 3, 3, 1, 3, 3, 3, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 3, 1, 5, 1, + 5, 1, 3, 1, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, + 1, 1, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 1, 2, 0, 1, 3, - 3, 1, 1, 1, 3, 1, 3, 2, 2, 2, - 0, 1, 2, 0, 1, 1, 2, 2, 7, 5, - 7, 7, 5, 9, 10, 7, 8, 2, 2, 3, - 3, 2, 2, 3, 3, 3, 3, 5, 5, 3, - 5, 1, 2, 0, 1, 4, 3, 3, 3, 3, - 3, 3, 3, 3, 4, 5, 2, 2, 2, 8, - 8, 1, 3, 0, 1, 0, 1, 1, 1, 2, - 1, 1, 0, 1, 0, 1, 2}; + 3, 1, 2, 0, 1, 3, 3, 1, 1, 1, + 3, 1, 3, 2, 2, 2, 0, 1, 2, 0, + 1, 1, 2, 2, 7, 5, 7, 7, 5, 9, + 10, 7, 8, 2, 2, 3, 3, 2, 2, 3, + 3, 3, 3, 5, 5, 3, 5, 1, 2, 0, + 1, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 5, 2, 2, 2, 8, 8, 1, 3, 0, + 1, 0, 1, 1, 1, 2, 1, 1, 0, 1, + 0, 1, 2}; const int JavaScriptGrammar::action_default [] = { 8, 2, 0, 4, 3, 0, 0, 0, 6, 7, - 5, 0, 9, 1, 0, 17, 37, 44, 242, 0, - 0, 41, 42, 14, 39, 40, 43, 243, 18, 10, - 0, 0, 0, 38, 0, 27, 26, 25, 0, 0, - 31, 0, 32, 145, 212, 176, 184, 180, 124, 196, - 172, 0, 109, 47, 125, 188, 192, 113, 142, 123, - 128, 108, 162, 149, 0, 53, 54, 50, 313, 41, - 315, 65, 0, 0, 0, 0, 0, 48, 51, 0, - 0, 42, 43, 52, 46, 0, 49, 0, 0, 138, - 0, 0, 125, 144, 127, 126, 0, 0, 0, 140, - 141, 139, 143, 0, 173, 0, 0, 0, 0, 163, - 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, - 147, 148, 146, 151, 155, 154, 152, 150, 165, 164, - 166, 0, 181, 0, 177, 0, 0, 119, 106, 118, - 107, 75, 76, 77, 102, 78, 103, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 104, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 105, 0, 0, 117, 213, 120, 0, 121, 0, - 122, 116, 35, 36, 0, 209, 202, 200, 207, 208, - 206, 205, 211, 204, 203, 201, 210, 197, 0, 185, - 0, 0, 189, 0, 0, 193, 0, 0, 119, 111, - 0, 110, 0, 115, 129, 0, 314, 304, 305, 0, - 302, 0, 303, 0, 306, 220, 227, 226, 234, 222, - 0, 223, 307, 0, 312, 224, 225, 230, 228, 309, - 308, 311, 231, 0, 0, 0, 0, 0, 313, 41, - 0, 315, 42, 214, 256, 43, 0, 0, 0, 0, - 0, 232, 233, 221, 229, 257, 258, 301, 310, 0, - 272, 273, 274, 275, 0, 268, 269, 270, 271, 298, - 299, 0, 0, 0, 0, 0, 261, 262, 218, 216, - 178, 186, 182, 198, 174, 219, 0, 125, 190, 194, - 167, 156, 0, 0, 175, 0, 0, 0, 0, 168, - 0, 0, 0, 0, 0, 160, 158, 161, 159, 157, - 170, 169, 171, 0, 183, 0, 179, 0, 217, 125, - 0, 199, 214, 215, 0, 214, 0, 0, 264, 0, - 0, 0, 266, 0, 187, 0, 0, 191, 0, 0, - 195, 254, 0, 246, 255, 249, 0, 253, 0, 214, - 247, 0, 214, 0, 0, 265, 0, 0, 0, 267, - 314, 304, 0, 0, 306, 0, 300, 0, 290, 0, - 0, 0, 260, 0, 259, 0, 316, 0, 74, 236, - 239, 0, 75, 242, 78, 103, 80, 81, 50, 85, - 86, 41, 87, 90, 48, 51, 42, 214, 43, 52, - 93, 46, 95, 49, 97, 98, 243, 100, 101, 105, - 0, 67, 0, 0, 69, 73, 71, 59, 70, 72, - 0, 68, 58, 237, 235, 113, 114, 119, 0, 112, - 0, 289, 0, 276, 277, 0, 288, 0, 0, 0, - 279, 284, 282, 285, 0, 0, 283, 284, 0, 280, - 0, 281, 238, 287, 0, 238, 286, 0, 291, 292, - 0, 238, 293, 294, 0, 0, 295, 0, 0, 0, - 296, 297, 131, 130, 0, 0, 0, 263, 0, 0, - 0, 278, 0, 66, 0, 63, 65, 56, 0, 62, - 57, 64, 61, 55, 0, 60, 135, 133, 137, 134, - 132, 136, 0, 0, 0, 29, 0, 30, 0, 33, - 34, 28, 15, 11, 0, 0, 24, 41, 65, 20, - 0, 23, 16, 0, 12, 0, 19, 13, 21, 22, - 45, 251, 244, 0, 252, 248, 0, 250, 240, 0, - 241, 245, 317}; + 5, 65, 45, 46, 43, 44, 47, 9, 0, 1, + 0, 0, 16, 66, 41, 248, 0, 0, 46, 14, + 47, 249, 17, 10, 0, 0, 0, 42, 0, 31, + 30, 29, 0, 0, 35, 0, 36, 151, 218, 182, + 190, 186, 130, 202, 178, 0, 115, 49, 131, 194, + 198, 119, 148, 129, 134, 114, 168, 155, 0, 55, + 56, 52, 319, 321, 0, 0, 0, 0, 0, 0, + 50, 53, 0, 0, 54, 48, 0, 51, 0, 0, + 144, 0, 0, 131, 150, 133, 132, 0, 0, 0, + 146, 147, 145, 149, 0, 179, 0, 0, 0, 0, + 169, 0, 0, 0, 0, 0, 0, 159, 0, 0, + 0, 153, 154, 152, 157, 161, 160, 158, 156, 171, + 170, 172, 0, 187, 0, 183, 0, 0, 125, 112, + 124, 113, 81, 82, 83, 108, 84, 109, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 110, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 111, 0, 0, 123, 219, 126, 0, 127, + 0, 128, 122, 39, 40, 0, 215, 208, 206, 213, + 214, 212, 211, 217, 210, 209, 207, 216, 203, 0, + 191, 0, 0, 195, 0, 0, 199, 0, 0, 125, + 117, 0, 116, 0, 121, 135, 0, 320, 310, 311, + 0, 308, 0, 309, 0, 312, 226, 233, 232, 240, + 228, 0, 229, 313, 0, 318, 230, 231, 236, 234, + 315, 314, 317, 237, 0, 0, 0, 0, 0, 319, + 45, 0, 321, 46, 220, 262, 47, 0, 0, 0, + 0, 0, 238, 239, 227, 235, 263, 264, 307, 316, + 0, 278, 279, 280, 281, 0, 274, 275, 276, 277, + 304, 305, 0, 0, 0, 0, 0, 267, 268, 224, + 222, 184, 192, 188, 204, 180, 225, 0, 131, 196, + 200, 173, 162, 0, 0, 181, 0, 0, 0, 0, + 174, 0, 0, 0, 0, 0, 166, 164, 167, 165, + 163, 176, 175, 177, 0, 189, 0, 185, 0, 223, + 131, 0, 205, 220, 221, 0, 220, 0, 0, 270, + 0, 0, 0, 272, 0, 193, 0, 0, 197, 0, + 0, 201, 260, 0, 252, 261, 255, 0, 259, 0, + 220, 253, 0, 220, 0, 0, 271, 0, 0, 0, + 273, 320, 310, 0, 0, 312, 0, 306, 0, 296, + 0, 0, 0, 266, 0, 265, 0, 322, 0, 80, + 242, 245, 0, 81, 248, 84, 109, 86, 87, 52, + 91, 92, 45, 93, 96, 50, 53, 46, 220, 47, + 54, 99, 48, 101, 51, 103, 104, 249, 106, 107, + 111, 0, 73, 0, 0, 75, 79, 77, 63, 76, + 78, 0, 74, 62, 243, 241, 119, 120, 125, 0, + 118, 0, 295, 0, 282, 283, 0, 294, 0, 0, + 0, 285, 290, 288, 291, 0, 0, 289, 290, 0, + 286, 0, 287, 244, 293, 0, 244, 292, 0, 297, + 298, 0, 244, 299, 300, 0, 0, 301, 0, 0, + 0, 302, 303, 137, 136, 0, 0, 0, 269, 0, + 0, 0, 284, 67, 0, 0, 71, 57, 0, 59, + 69, 0, 60, 70, 72, 61, 68, 58, 0, 64, + 141, 139, 143, 140, 138, 142, 0, 0, 0, 33, + 0, 34, 0, 37, 38, 32, 15, 11, 0, 23, + 26, 24, 0, 25, 28, 244, 0, 19, 0, 27, + 22, 81, 248, 84, 109, 86, 87, 52, 91, 92, + 45, 93, 96, 50, 53, 46, 220, 47, 54, 99, + 48, 101, 51, 103, 104, 249, 106, 107, 111, 49, + 0, 12, 0, 18, 13, 20, 21, 257, 250, 0, + 258, 254, 0, 256, 246, 0, 247, 251, 323}; const int JavaScriptGrammar::goto_default [] = { - 6, 5, 13, 1, 4, 3, 28, 30, 29, 533, - 15, 31, 530, 531, 389, 513, 230, 234, 263, 53, - 61, 494, 492, 387, 386, 44, 493, 385, 388, 139, - 57, 52, 177, 59, 48, 176, 54, 60, 89, 58, - 43, 63, 62, 300, 50, 294, 45, 290, 47, 292, - 46, 291, 55, 298, 56, 299, 49, 293, 289, 330, - 442, 295, 296, 225, 229, 231, 235, 236, 227, 226, - 238, 264, 237, 242, 261, 262, 228, 391, 390, 32, - 543, 542, 352, 353, 545, 355, 544, 354, 450, 454, - 457, 453, 452, 472, 473, 219, 233, 215, 218, 232, - 240, 239, 0}; + 6, 5, 19, 1, 4, 3, 32, 34, 33, 570, + 22, 18, 538, 539, 231, 226, 230, 232, 229, 236, + 517, 235, 264, 57, 65, 495, 494, 388, 387, 48, + 386, 389, 140, 61, 56, 178, 63, 52, 177, 58, + 64, 90, 62, 47, 67, 66, 301, 54, 295, 49, + 291, 51, 293, 50, 292, 59, 299, 60, 300, 53, + 294, 290, 331, 443, 296, 297, 390, 237, 228, 227, + 239, 265, 238, 243, 262, 263, 392, 391, 36, 579, + 578, 353, 354, 581, 356, 580, 355, 451, 455, 458, + 454, 453, 473, 474, 220, 234, 216, 219, 233, 241, + 240, 0}; const int JavaScriptGrammar::action_index [] = { - -23, -91, 10, -91, -19, 50, 77, 56, -91, -91, - -91, 67, -91, -91, 383, -91, -91, -91, -91, -4, - 213, 20, 186, -91, -91, -91, -18, -91, -91, -91, - 370, 129, 203, -91, 204, -91, -91, -91, -17, 192, - -91, 693, -91, 87, -91, 42, 9, -20, 191, -91, - 310, 140, -91, -91, 534, 17, 114, 160, 125, -91, - -91, -91, 344, 162, 693, -91, -91, -91, 157, -91, - 1191, 34, 693, 693, 693, 613, 693, -91, -91, 693, - 693, -91, -91, -91, -91, 693, -91, 693, 693, -91, - 693, 693, 119, 227, -91, -91, 693, 693, 693, -91, - -91, -91, 193, 693, 310, 693, 693, 693, 693, 446, - 693, 693, 693, 693, 693, 693, 237, 693, 693, 693, - 88, 106, 107, 237, 237, 166, 237, 237, 354, 372, - 334, 693, -11, 693, 19, 1104, 693, 693, -91, -91, + 8, -91, 14, -91, -15, 296, 67, 94, -91, -91, + -91, -91, -91, -91, -91, -91, -91, -91, 109, -91, + 184, 408, -91, -91, -91, -91, 45, 125, 170, -91, + 46, -91, -91, -91, 429, 171, 130, -91, 120, -91, + -91, -91, -19, 169, -91, 733, -91, 72, -91, 22, + -26, -59, 173, -91, 278, 174, -91, -91, 574, 51, + 112, 183, 177, -91, -91, -91, 412, 214, 733, -91, + -91, -91, 161, 1566, 980, 733, 733, 733, 653, 733, + -91, -91, 733, 733, -91, -91, 733, -91, 733, 733, + -91, 733, 733, 98, 235, -91, -91, 733, 733, 733, + -91, -91, -91, 230, 733, 276, 733, 733, 733, 733, + 396, 733, 733, 733, 733, 733, 733, 288, 733, 733, + 733, 88, 87, 74, 288, 288, 288, 218, 221, 486, + 372, 362, 733, 4, 733, 76, 1479, 733, 733, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, - -91, -91, 98, 693, -91, -91, 0, -43, -91, 693, - -91, -91, -91, -91, 693, -91, -91, -91, -91, -91, - -91, -91, -91, -91, -91, -91, -91, -91, 693, 6, - 693, 693, -2, 82, 693, -91, 1104, 693, 693, -91, - 96, -91, 8, -91, -91, 61, -91, 147, 80, 33, - -91, 154, -91, 63, 1452, -91, -91, -91, -91, -91, - 169, -91, -91, 23, -91, -91, -91, -91, -91, -91, - 1452, -91, -91, 285, 287, 68, 1365, 55, 112, 79, - 46, 1626, 66, 693, -91, 65, 47, 693, 52, 58, - 59, -91, -91, -91, -91, -91, -91, -91, -91, 64, - -91, -91, -91, -91, 73, -91, -91, -91, -91, -91, - -91, -5, 45, 693, 137, 81, -91, -91, 1017, -91, - 69, 28, 14, -91, 240, 76, 53, 476, 171, 120, - 308, 237, 180, 693, 264, 693, 693, 693, 693, 298, - 693, 693, 693, 693, 693, 230, 237, 237, 237, 237, - 288, 268, 378, 693, -68, 693, 12, 693, -91, 445, - 693, -91, 693, 7, -47, 693, -44, 1365, -91, 693, - 100, 1365, -91, 693, -25, 693, 693, 22, 15, 693, - -91, -8, 108, -13, -91, -91, 693, -91, 178, 693, - -91, -60, 693, -58, 1365, -91, 693, 99, 1365, -91, - -33, 199, -53, -27, 1452, -26, -91, 1365, -91, 693, - 95, 1365, 32, 1365, -91, 43, 41, 4, -91, -91, - 1365, 5, 232, 54, 275, 70, 693, 1365, 49, 27, - 252, 48, 30, 613, 40, 39, -91, 777, -91, 25, - -1, 26, 693, 24, -3, 693, 21, 693, 1, 2, - 693, -91, 1278, 37, -91, -91, -91, -91, -91, -91, - 693, -91, -91, -91, -91, 156, -91, 693, -21, -91, - 1365, -91, 60, -91, -91, 1365, -91, 693, 102, 3, - -91, 29, -91, 35, 101, 693, -91, 36, 38, -91, - -30, -91, 1365, -91, 94, 1365, -91, 176, -91, -91, - 143, 1365, 44, -91, 16, -6, -91, 207, -9, -29, - -91, -91, -91, -91, 693, 90, 1365, -91, 693, 91, - 1365, -91, 111, 13, 857, -91, 18, -91, 937, -91, - -91, -91, -91, -91, 105, -91, -91, -91, -91, -91, - -91, -91, -33, -24, 215, -91, 693, -91, 187, -91, - -91, -91, -91, -91, 1539, 174, -91, 133, 104, -91, - 62, -91, -91, 97, -91, 51, -91, -91, -91, -91, - -91, 57, -91, 173, -91, -91, 693, -91, -91, 151, - -91, -91, -91, + -91, -91, -91, 102, 733, -91, -91, 60, 3, -91, + 733, -91, -91, -91, -91, 733, -91, -91, -91, -91, + -91, -91, -91, -91, -91, -91, -91, -91, -91, 733, + -6, 733, 733, 30, 32, 733, -91, 1479, 733, 733, + -91, 107, -91, -14, -91, -91, 69, -91, 191, 49, + 18, -91, 233, -91, 47, 1827, -91, -91, -91, -91, + -91, 204, -91, -91, 39, -91, -91, -91, -91, -91, + -91, 1827, -91, -91, 322, 281, 103, 1740, 50, 203, + 77, 40, 2001, 53, 733, -91, 52, 29, 733, 25, + 28, 35, -91, -91, -91, -91, -91, -91, -91, -91, + 113, -91, -91, -91, -91, 106, -91, -91, -91, -91, + -91, -91, 15, 68, 733, 135, 119, -91, -91, 897, + -91, 82, 58, 17, -91, 261, 84, 42, 494, 91, + 79, 304, 288, 208, 733, 245, 733, 733, 733, 733, + 418, 733, 733, 733, 733, 733, 288, 288, 288, 288, + 288, 343, 336, 279, 733, -57, 733, 19, 733, -91, + 574, 733, -91, 733, -7, -30, 733, -60, 1740, -91, + 733, 111, 1740, -91, 733, 2, 733, 733, 43, 37, + 733, -91, 34, 118, 23, -91, -91, 733, -91, 238, + 733, -91, -5, 733, -17, 1740, -91, 733, 133, 1740, + -91, -9, 194, -32, -8, 1827, -25, -91, 1740, -91, + 733, 100, 1740, 21, 1740, -91, 31, 26, -20, -91, + -91, 1740, -38, 283, 41, 291, 85, 733, 1740, -1, + -34, 252, 54, -27, 653, 9, 5, -91, 817, -91, + 6, -21, 7, 733, 11, -28, 733, 1, 733, -33, + -10, 733, -91, 1653, 33, -91, -91, -91, -91, -91, + -91, 733, -91, -91, -91, -91, 172, -91, 733, -24, + -91, 1740, -91, 73, -91, -91, 1740, -91, 733, 93, + 0, -91, 24, -91, 36, 122, 733, -91, 44, 48, + -91, -3, -91, 1740, -91, 110, 1740, -91, 192, -91, + -91, 124, 1740, 27, -91, -12, -29, -91, 155, -53, + -22, -91, -91, -91, -91, 733, 123, 1740, -91, 733, + 92, 1740, -91, -91, 105, 1229, -91, -91, 1146, -91, + -91, 1063, -91, -91, -91, -91, -91, -91, 90, -91, + -91, -91, -91, -91, -91, -91, 71, 70, 222, -91, + 733, -91, 164, -91, -91, -91, -91, -91, 1392, -91, + -91, -91, 268, -91, -91, 1914, 1312, -91, 75, -91, + -91, 350, 55, 303, 108, 733, 1740, 59, 38, 242, + 62, 40, 527, 63, 81, -91, 817, -91, 138, 29, + 65, 733, 78, 56, 733, 80, 733, 61, 66, 57, + 101, -91, 347, -91, -91, -91, -91, 64, -91, 140, + -91, -91, 733, -91, -91, 144, -91, -91, -91, - -103, -103, -103, -103, 15, 16, -103, -103, -103, -103, - -103, -103, -103, -103, 208, -103, -103, -103, -103, -103, - -1, -103, -103, -103, -103, -103, -103, -103, -103, -103, - 237, -103, 26, -103, 31, -103, -103, -103, -103, -103, - -103, 28, -103, -103, -103, -103, -103, -103, -103, -103, - -103, -103, -103, -103, -46, -103, -103, -103, -103, -103, - -103, -103, -103, -103, 98, -103, -103, -103, 7, -103, - -103, -103, -10, 118, 111, 67, 112, -103, -103, 119, - 123, -103, -103, -103, -103, 124, -103, 115, 97, -103, - 32, 106, -103, -103, -103, -103, 128, 171, 101, -103, - -103, -103, -103, 156, -103, 157, 159, 81, 131, -103, - 127, 136, 145, 139, 102, 91, -103, 59, 50, 72, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - -103, 70, -103, 80, -103, 85, 61, 51, -103, -103, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - -103, -103, -103, 54, -103, -103, -103, -103, -103, -24, - -103, -103, -103, -103, -23, -103, -103, -103, -103, -103, - -103, -103, -103, -103, -103, -103, -103, -103, 134, -103, - 138, 17, -103, -103, 23, -103, 255, -4, 73, -103, - -103, -103, -103, -103, -103, -103, -103, 11, -103, -103, - -103, 8, -103, -103, 9, -103, -103, -103, -103, -103, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - 77, -103, -103, 10, 2, -103, 5, -103, -3, -103, - -103, -103, -103, 19, -103, -103, -103, 27, -31, -103, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - -103, -103, -103, -5, -103, -103, -103, -103, 105, -103, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - -103, -103, 34, 205, -103, 193, 169, 181, 201, -103, - 147, 66, 78, 79, 89, -103, -103, -103, -103, -103, - -103, -103, -103, 202, -103, 192, -103, 212, -103, -103, - 182, -103, 68, -103, -103, 62, -103, 56, -103, 33, - -103, 55, -103, 170, -103, 161, 162, -103, -103, 172, - -103, -103, -103, -103, -103, -103, 211, -103, 69, 71, - -103, -103, 64, -103, 60, -103, 41, -103, 42, -103, - -103, 74, -103, -103, 75, -103, -103, 38, -103, 35, - -103, 36, -103, 44, -103, -103, -103, -103, -103, -103, - 52, -103, 45, -103, 43, -103, 65, 46, -103, -103, - 40, -103, -103, 146, -103, -103, -103, 49, -103, -103, - -103, -103, 47, -103, -22, 149, -103, 153, -103, -103, - 30, -103, 48, -103, -103, -103, -103, -103, -103, -103, - 29, -103, -103, -103, -103, -103, -103, 133, -103, -103, - 53, -103, -103, -103, -103, 58, -103, 57, -103, -103, - -103, -103, -103, -56, -103, -6, -103, -82, -103, -103, - -103, -103, -77, -103, -103, -68, -103, -103, -103, -103, - -103, -103, -90, -103, -103, -58, -103, -11, -103, -60, - -103, -103, -103, -103, 21, -103, 25, -103, 22, -103, - 20, -103, -103, -103, 6, -103, 12, -103, 3, -103, - -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - -103, -103, -103, -103, -103, -103, 24, -103, -103, -103, - -103, -103, -103, -103, 1, -2, -103, 4, 104, -103, - -103, -103, -103, -103, -103, 18, -103, -103, -103, -103, - -103, -103, -103, -103, -103, -103, 0, -103, -103, 63, - -103, -103, -103}; + -102, -102, -102, -102, 19, 103, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -4, 249, -102, -102, -102, -102, -102, -7, -102, -102, + -102, -102, -102, -102, 257, -102, -13, -102, -11, -102, + -102, -102, -102, -102, -102, -3, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -44, -102, + -102, -102, -102, -102, -102, -102, -102, -102, 141, -102, + -102, -102, -8, -102, 0, 16, 116, 122, 129, 119, + -102, -102, 90, 64, -102, -102, 94, -102, 91, 86, + -102, 71, 79, -102, -102, -102, -102, 159, 81, 76, + -102, -102, -102, -102, 98, -102, 67, 63, 47, 163, + -102, 160, 115, 104, 105, 127, 133, -102, 151, 144, + 130, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, 145, -102, 152, -102, 162, 31, 21, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, 23, -102, -102, -102, -102, -102, + 29, -102, -102, -102, -102, 34, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, 89, + -102, 68, 36, -102, -102, 42, -102, 235, 46, 49, + -102, -102, -102, -102, -102, -102, -102, -102, 33, -102, + -102, -102, 26, -102, -102, -18, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, 53, -102, -102, 8, 20, -102, -5, -102, 32, + -102, -102, -102, -102, 39, -102, -102, -102, 37, 73, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, 40, -102, -102, -102, -102, 97, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, 41, 213, -102, 186, 199, 203, 209, + -102, 50, 51, 38, 57, 60, -102, -102, -102, -102, + -102, -102, -102, -102, 212, -102, 174, -102, 166, -102, + -102, 168, -102, 125, -102, -102, 61, -102, 1, -102, + 45, -102, -9, -102, 172, -102, 184, 176, -102, -102, + 170, -102, -102, -102, -102, -102, -102, 215, -102, 124, + 132, -102, -102, 178, -102, -29, -102, 25, -102, 2, + -102, -102, 62, -102, -102, 102, -102, -102, -28, -102, + 22, -102, -31, -102, -33, -102, -102, -102, -102, -102, + -102, -34, -102, 17, -102, 18, -102, 111, -20, -102, + -102, 24, -102, -102, 153, -102, -102, -102, 30, -102, + -102, -102, -102, 28, -102, 73, 140, -102, 205, -102, + -102, 5, -102, 44, -102, -102, -102, -102, -102, -102, + -102, 43, -102, -102, -102, -102, -102, -102, 135, -102, + -102, 7, -102, -102, -102, -102, 4, -102, 55, -102, + -102, -102, -102, -102, -25, -102, 48, -102, 9, -102, + -102, -102, -102, -69, -102, -102, -70, -102, -102, -102, + -102, -102, -102, -92, -102, -102, -12, -102, -10, -102, + -1, -102, -102, -102, -102, 11, -102, -40, -102, 14, + -102, -39, -102, -102, -102, -17, -102, -102, 54, -102, + -102, -24, -102, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, + 3, -102, -102, -102, -102, -102, -102, -102, 267, -102, + -102, -102, 12, -102, -102, -102, 301, -102, -102, -102, + -102, -19, -102, -15, -102, 59, -64, -102, -102, -2, + -102, -102, 142, -102, -102, -102, -14, -102, -102, -102, + -102, 6, -102, 73, 52, -102, 75, -102, -102, -102, + -102, -102, 128, -102, -102, -102, -102, -102, -102, -102, + -102, -102, -6, -102, -102, 58, -102, -102, -102}; const int JavaScriptGrammar::action_info [] = { - 198, 362, 364, 371, 471, 514, 374, 373, 179, 356, - 325, 521, 39, 303, 335, 173, 337, 181, 366, 198, - 103, 501, 349, 323, 343, 461, 495, 471, -99, 376, - 471, -96, -72, -94, 455, 447, 451, 484, 488, 439, - 455, 455, 495, 103, 430, 462, -73, -91, 383, 422, - 420, 479, 477, 14, 131, -69, -83, 131, 133, 432, - 434, -102, 34, 288, 475, 2, 379, 133, 213, 2, - 303, 282, 445, 440, 546, 7, 323, 552, 267, 11, - 11, 283, 379, 447, 327, 471, 377, 0, 221, 204, - 0, 288, 325, 223, 484, 488, 224, 217, 173, 173, - 14, 465, 173, 173, 173, 535, 173, 173, 173, 0, - 173, 458, 495, 173, 332, 0, 358, 9, 8, 496, - 0, 444, 443, 539, 538, 273, 272, 90, 90, 280, - 279, 280, 279, 11, 278, 277, 524, 96, 91, 91, - 377, 69, 287, 286, 525, 173, 90, 90, 173, 474, - 486, 490, 211, 536, 174, 381, 459, 91, 91, 368, - 341, 94, 449, 475, 200, 505, 14, 497, 201, 359, - 345, 206, 95, 343, 346, 206, 69, 173, 81, 82, - 69, 549, 97, 69, 173, 0, 69, 117, 98, 118, - 207, 117, 437, 118, 207, 173, 208, 285, 0, 41, - 119, 183, 182, 69, 119, 96, 135, 69, 0, 69, - 0, 0, 0, 81, 82, 35, 0, 81, 82, 0, - 81, 82, 516, 81, 82, 136, 0, 137, 69, 0, - 266, 265, 69, 35, 550, 548, 69, 469, 468, 96, - 81, 82, 69, 0, 81, 82, 81, 82, 520, 519, - 97, 0, 0, 42, 40, 117, 98, 118, 305, 306, - 37, 69, 117, 0, 118, 81, 82, 0, 119, 81, - 82, 36, 0, 81, 82, 119, 517, 515, 37, 81, - 82, 69, 305, 306, 97, 307, 308, 0, -313, 36, - 98, 310, 311, 271, 270, 0, 0, 0, 81, 82, - 312, 0, 0, 313, 69, 314, 0, 0, 0, 307, - 308, 310, 311, 0, 69, 0, 69, 0, 81, 82, - 312, 310, 311, 313, 0, 314, 0, 0, 105, 106, - 312, 310, 311, 313, 0, 314, 276, 275, 0, 0, - 312, 81, 82, 313, 0, 314, 271, 270, 276, 275, - 0, 81, 82, 81, 82, 107, 108, 110, 111, 0, - 0, 0, 0, 0, 0, 112, 113, 110, 111, 114, - 0, 115, 0, 0, 0, 112, 113, 110, 111, 114, - 19, 115, 0, 0, 0, 112, 113, 0, 0, 114, - 0, 115, 20, 19, 0, 110, 111, 0, 0, 21, - 0, 310, 311, 112, 113, 20, 0, 114, 0, 115, - 312, 0, 21, 313, 0, 314, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 522, 0, 0, 0, 25, - 0, 0, 0, 0, 0, 0, 22, 26, 23, 0, - 0, 0, 25, 0, 27, 0, 0, 0, 185, 22, - 26, 0, 0, 18, 0, 24, 0, 27, 186, 0, - 0, 0, 187, 0, 0, 0, 18, 0, 24, 110, - 111, 188, 0, 189, 0, 0, 0, 112, 113, 185, - 0, 114, 0, 115, 190, 0, 191, 94, 0, 186, - 0, 0, 0, 187, 192, 0, 0, 193, 95, 0, - 0, 0, 188, 194, 189, 0, 0, 339, 0, 195, - 0, 0, 0, 0, 0, 190, 0, 191, 94, 0, - 0, 0, 0, 0, 196, 192, 0, 0, 193, 95, - 0, 0, 0, 0, 194, 0, 0, 185, 0, 0, - 195, 0, 0, 0, 0, 0, 0, 186, 0, 0, - 0, 187, 0, 0, 0, 196, 0, 0, 0, 0, - 188, 0, 189, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 190, 0, 191, 94, 0, 0, 0, - 0, 0, 0, 192, 0, 0, 193, 95, 0, 0, - 0, 0, 194, 0, 0, 0, 0, 0, 195, 0, + 338, 174, 289, 485, 472, 472, -89, 480, -105, 380, + 43, 472, -79, -78, -100, 448, -97, 435, -102, 134, + 304, 326, 132, 104, 478, 375, 489, 372, 374, 456, + 377, 336, 199, 452, 423, 433, 440, 384, 421, 205, + 431, 456, 132, 365, 350, 344, 214, 476, -108, 456, + 324, 357, 462, 199, 367, 463, 363, 222, 472, 446, + 441, -75, -108, 182, 485, 448, -89, 588, 180, -75, + -97, 489, -100, 2, 289, 525, 380, 104, 224, 7, + 225, 582, 134, 304, 378, -102, 289, -105, -79, 472, + -65, 283, 328, 344, 268, 326, 2, 485, 174, 518, + 174, 174, 489, 333, 284, 218, 324, 372, 174, 572, + 174, 38, 91, 498, 91, 174, 0, 466, 174, 174, + 0, 0, 0, 92, 20, 92, 359, 91, 91, 346, + 475, 174, 459, 347, 445, 444, 576, 575, 92, 92, + 95, 174, 21, 174, 476, -78, 281, 280, 585, 39, + 509, 96, 491, 450, 12, 9, 8, 573, 175, 12, + 382, 499, 201, 212, 281, 280, 202, 279, 278, 281, + 280, 342, 174, 12, 274, 273, 45, 460, 528, 360, + 288, 287, 174, 487, 12, 0, 20, 207, 136, 97, + 12, 13, 16, 369, 41, 286, 13, 16, 207, 39, + 174, 586, 584, 0, 21, 40, 208, 137, 438, 138, + 13, 16, 174, 12, 0, 0, 0, 208, 0, 209, + 12, 13, 16, 12, 0, 524, 523, 13, 16, 520, + 46, 44, 12, 0, 98, 184, 183, 12, 0, 118, + 99, 119, 97, 118, 41, 119, 118, 97, 119, 0, + 13, 16, 120, 470, 469, 40, 120, 13, 16, 120, + 13, 16, 12, 306, 307, 267, 266, 12, 0, 13, + 16, 12, 0, 0, 13, 16, 174, 0, -319, 306, + 307, 12, 0, 521, 519, 0, 0, 98, -319, 0, + 308, 309, 98, 99, 106, 107, 106, 107, 99, 13, + 16, 21, 311, 312, 13, 16, 308, 309, 13, 16, + 12, 313, 12, 118, 314, 119, 315, 0, 13, 16, + 12, 108, 109, 108, 109, 12, 120, 311, 312, 267, + 266, 0, 12, 0, 0, 0, 313, 0, 0, 314, + 0, 315, 277, 276, 272, 271, 0, 13, 16, 13, + 16, 12, 277, 276, 0, 15, 0, 13, 16, 311, + 312, 0, 13, 16, 277, 276, 311, 312, 313, 13, + 16, 314, 0, 315, 0, 313, 12, 0, 314, 12, + 315, 14, 0, 272, 271, 111, 112, 0, 13, 16, + 0, 0, 0, 113, 114, 111, 112, 115, 0, 116, + 0, 0, 0, 113, 114, 0, 15, 115, 0, 116, + 0, 272, 271, 13, 16, 0, 13, 16, 26, 111, + 112, 0, 0, 0, 0, 0, 0, 113, 114, 0, + 27, 115, 14, 116, 0, 111, 112, 12, 0, 26, + 0, 311, 312, 113, 114, 0, 0, 115, 0, 116, + 313, 27, 0, 314, 0, 315, 0, 0, 12, 0, + 0, 0, 0, 29, 0, 0, 0, 15, 0, 0, + 0, 0, 0, 0, 28, 30, 0, 0, 0, 0, + 0, 0, 31, 0, 526, 0, 0, 0, 15, 0, + 0, 25, 0, 14, 0, 28, 30, 186, 0, 0, + 0, 0, 0, 31, 0, 0, 0, 187, 0, 111, + 112, 188, 25, 0, 14, 0, 0, 113, 114, 0, + 189, 115, 190, 116, 0, 340, 0, 0, 0, 0, + 0, 0, 0, 191, 0, 192, 95, 0, 0, 69, + 70, 0, 0, 193, 0, 0, 194, 96, 0, 72, + 0, 0, 195, 0, 0, 0, 12, 0, 196, 0, + 73, 74, 0, 75, 0, 0, 0, 0, 0, 0, + 78, 0, 0, 197, 81, 0, 0, 186, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 187, 0, 0, + 0, 188, 84, 13, 16, 0, 85, 0, 0, 0, + 189, 0, 190, 0, 0, 0, 0, 80, 87, 71, + 0, 0, 0, 191, 0, 192, 95, 0, 0, 0, + 0, 0, 0, 193, 0, 0, 194, 96, 0, 0, + 0, 0, 195, 0, 0, 0, 0, 0, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 196, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 65, 66, 0, 0, 0, - 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, - 0, 0, 69, 0, 0, 0, 70, 71, 0, 72, - 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, - 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 83, 81, - 82, 0, 84, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 77, 86, 67, 0, 0, 0, 0, - 0, 0, 0, 0, 64, 65, 66, 0, 0, 0, - 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, - 0, 0, 69, 0, 0, 0, 70, 71, 0, 72, - 0, 0, 0, 73, 0, 74, 75, 76, 0, 0, - 78, 0, 0, 0, 79, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 83, 81, - 82, 0, 84, 0, 85, 0, 87, 0, 88, 0, - 0, 0, 0, 77, 86, 67, 0, 0, 0, 0, - 0, 0, 0, 0, -92, 0, 0, 0, 64, 65, - 66, 0, 0, 0, 0, 0, 0, 0, 0, 68, - 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, - 70, 71, 0, 72, 0, 0, 0, 73, 0, 74, - 75, 76, 0, 0, 78, 0, 0, 0, 79, 0, - 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 83, 81, 82, 0, 84, 0, 85, 0, - 87, 0, 88, 0, 0, 0, 0, 77, 86, 67, - 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, - 66, 0, 0, 0, 0, 0, 0, 0, 0, 68, - 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, - 70, 71, 0, 72, 0, 0, 0, 73, 0, 74, - 75, 76, 0, 0, 78, 0, 0, 0, 79, 0, - 80, 0, 0, 503, 0, 0, 0, 0, 0, 0, - 0, 0, 83, 81, 82, 0, 84, 0, 85, 0, - 87, 0, 88, 0, 0, 0, 0, 77, 86, 67, - 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, - 66, 0, 0, 0, 0, 0, 0, 0, 0, 68, - 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, - 70, 71, 0, 72, 0, 0, 0, 73, 0, 74, - 75, 76, 0, 0, 78, 0, 0, 0, 79, 0, - 80, 0, 0, 500, 0, 0, 0, 0, 0, 0, - 0, 0, 83, 81, 82, 0, 84, 0, 85, 0, - 87, 0, 88, 0, 0, 0, 0, 77, 86, 67, - 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, - 66, 0, 0, 0, 0, 0, 0, 0, 0, 68, - 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, - 70, 71, 0, 72, 0, 0, 0, 73, 0, 74, - 75, 76, 0, 0, 78, 0, 0, 0, 79, 0, - 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 83, 81, 82, 0, 84, 0, 85, 0, - 87, 302, 88, 0, 0, 0, 0, 77, 86, 67, - 0, 0, 0, 0, 0, 0, 0, 0, 141, 142, - 143, 0, 0, 145, 147, 148, 0, 0, 149, 0, - 150, 0, 0, 0, 152, 153, 154, 0, 0, 0, - 0, 0, 0, 69, 155, 156, 157, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 158, 0, 0, + 0, 0, 0, 197, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, + 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, + 0, 0, 12, 0, 0, 0, 73, 74, 0, 75, + 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, + 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 84, 13, + 16, 0, 85, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 80, 87, 71, 0, 0, 0, 0, + 0, 0, 0, 0, 68, 69, 70, 0, 0, 0, + 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, + 0, 0, 12, 0, 0, 0, 73, 74, 0, 75, + 0, 0, 0, 76, 0, 77, 78, 79, 0, 0, + 81, 0, 0, 0, 82, 0, 83, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 84, 13, + 16, 0, 85, 0, 86, 0, 88, 0, 89, 0, + 0, 0, 0, 80, 87, 71, 0, 0, 0, 0, + 0, 0, 0, 0, -98, 0, 0, 0, 68, 69, + 70, 0, 0, 0, 0, 0, 0, 0, 0, 72, + 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, + 73, 74, 0, 75, 0, 0, 0, 76, 0, 77, + 78, 79, 0, 0, 81, 0, 0, 0, 82, 0, + 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 84, 13, 16, 0, 85, 0, 86, 0, + 88, 0, 89, 0, 0, 0, 0, 80, 87, 71, + 0, 0, 0, 0, 0, 0, 0, 0, 68, 69, + 70, 0, 0, 0, 0, 0, 0, 0, 0, 72, + 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, + 73, 74, 0, 75, 0, 0, 0, 76, 0, 77, + 78, 79, 0, 0, 81, 0, 0, 0, 82, 0, + 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 84, 13, 16, 0, 85, 0, 86, 0, + 88, 303, 89, 0, 0, 0, 0, 80, 87, 71, + 0, 0, 0, 0, 0, 0, 0, 0, 496, 0, + 0, 68, 69, 70, 0, 0, 0, 0, 0, 0, + 0, 0, 72, 0, 0, 0, 0, 0, 0, 12, + 0, 0, 0, 73, 74, 0, 75, 0, 0, 0, + 76, 0, 77, 78, 79, 0, 0, 81, 0, 0, + 0, 82, 0, 83, 0, 0, 497, 0, 0, 0, + 0, 0, 0, 0, 0, 84, 13, 16, 0, 85, + 0, 86, 0, 88, 0, 89, 0, 0, 0, 0, + 80, 87, 71, 0, 0, 0, 0, 0, 0, 0, + 0, 504, 0, 0, 68, 69, 70, 0, 0, 0, + 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, + 0, 0, 12, 0, 0, 0, 73, 74, 0, 75, + 0, 0, 0, 76, 0, 77, 78, 79, 0, 0, + 81, 0, 0, 0, 82, 0, 83, 0, 0, 505, + 0, 0, 0, 0, 0, 0, 0, 0, 84, 13, + 16, 0, 85, 0, 86, 0, 88, 0, 89, 0, + 0, 0, 0, 80, 87, 71, 0, 0, 0, 0, + 0, 0, 0, 0, 496, 0, 0, 68, 69, 70, + 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, + 0, 0, 0, 0, 0, 12, 0, 0, 0, 73, + 74, 0, 75, 0, 0, 0, 76, 0, 77, 78, + 79, 0, 0, 81, 0, 0, 0, 82, 0, 83, + 0, 0, 502, 0, 0, 0, 0, 0, 0, 0, + 0, 84, 13, 16, 0, 85, 0, 86, 0, 88, + 0, 89, 0, 0, 0, 0, 80, 87, 71, 0, + 0, 0, 0, 0, 0, 0, 0, 504, 0, 0, + 68, 69, 70, 0, 0, 0, 0, 0, 0, 0, + 0, 72, 0, 0, 0, 0, 0, 0, 12, 0, + 0, 0, 73, 74, 0, 75, 0, 0, 0, 76, + 0, 77, 78, 79, 0, 0, 81, 0, 0, 0, + 82, 0, 83, 0, 0, 507, 0, 0, 0, 0, + 0, 0, 0, 0, 84, 13, 16, 0, 85, 0, + 86, 0, 88, 0, 89, 0, 0, 0, 0, 80, + 87, 71, 0, 0, 0, 0, 0, 0, 0, 0, + 496, 0, 0, 68, 69, 70, 0, 0, 0, 0, + 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, + 0, 12, 0, 0, 0, 73, 74, 0, 75, 0, + 0, 0, 76, 0, 77, 78, 79, 0, 0, 81, + 0, 0, 0, 82, 0, 83, 0, 0, 497, 0, + 0, 15, 0, 0, 0, 0, 0, 84, 13, 16, + 0, 85, 0, 86, 0, 88, 0, 89, 0, 0, + 0, 0, 80, 87, 71, 0, 0, 14, 0, 0, + 0, 0, 0, 68, 69, 70, 0, 0, 0, 0, + 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, + 0, 12, 251, 0, 0, 535, 536, 0, 75, 0, + 0, 0, 76, 0, 77, 78, 79, 0, 0, 81, + 0, 0, 0, 82, 0, 83, 0, 0, 0, 0, + 0, 0, 0, 255, 0, 0, 0, 84, 13, 16, + 0, 85, 0, 86, 0, 88, 0, 89, 0, 0, + 0, 0, 80, 87, 71, 0, 246, 0, 537, 0, + 0, 0, 0, 142, 143, 144, 0, 0, 146, 148, + 149, 0, 0, 150, 0, 151, 0, 0, 0, 153, + 154, 155, 0, 0, 0, 0, 0, 0, 12, 156, + 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 159, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, + 0, 0, 0, 0, 0, 13, 16, 163, 164, 165, + 0, 167, 168, 169, 170, 171, 172, 0, 0, 160, + 166, 152, 145, 147, 161, 0, 0, 0, 0, 0, + 142, 143, 144, 0, 0, 146, 148, 149, 0, 0, + 150, 0, 151, 0, 0, 0, 153, 154, 155, 0, + 0, 0, 0, 0, 0, 425, 156, 157, 158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, + 0, 0, 0, 426, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 162, 0, 0, 0, 0, + 0, 430, 427, 429, 163, 164, 165, 0, 167, 168, + 169, 170, 171, 172, 0, 0, 160, 166, 152, 145, + 147, 161, 0, 0, 0, 0, 0, 142, 143, 144, + 0, 0, 146, 148, 149, 0, 0, 150, 0, 151, + 0, 0, 0, 153, 154, 155, 0, 0, 0, 0, + 0, 0, 425, 156, 157, 158, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 159, 0, 0, 0, + 426, 0, 0, 0, 0, 0, 0, 0, 428, 0, + 0, 0, 162, 0, 0, 0, 0, 0, 430, 427, + 429, 163, 164, 165, 0, 167, 168, 169, 170, 171, + 172, 0, 0, 160, 166, 152, 145, 147, 161, 0, + 0, 0, 0, 0, 244, 0, 0, 0, 0, 245, + 0, 68, 69, 70, 247, 0, 0, 0, 0, 0, + 0, 248, 72, 0, 0, 0, 0, 0, 0, 250, + 251, 0, 0, 252, 74, 0, 75, 0, 0, 0, + 76, 0, 77, 78, 79, 0, 0, 81, 0, 0, + 0, 82, 0, 83, 0, 0, 0, 0, 0, 254, + 0, 255, 0, 0, 0, 84, 253, 256, 257, 85, + 258, 86, 259, 88, 31, 89, 260, 261, 0, 0, + 80, 87, 71, 25, 246, 0, 0, 0, 0, 0, + 0, 244, 0, 0, 0, 0, 245, 0, 68, 69, + 70, 247, 0, 0, 0, 0, 0, 0, 248, 249, + 0, 0, 0, 0, 0, 0, 250, 251, 0, 0, + 252, 74, 0, 75, 0, 0, 0, 76, 0, 77, + 78, 79, 0, 0, 81, 0, 0, 0, 82, 0, + 83, 0, 0, 0, 0, 0, 254, 0, 255, 0, + 0, 0, 84, 253, 256, 257, 85, 258, 86, 259, + 88, 31, 89, 260, 261, 0, 0, 80, 87, 71, + 25, 246, 0, 0, 0, 0, 0, 0, 541, 143, + 144, 0, 0, 543, 148, 545, 69, 70, 546, 0, + 151, 0, 0, 0, 153, 548, 549, 0, 0, 0, + 0, 0, 0, 550, 551, 157, 158, 252, 74, 0, + 75, 0, 0, 0, 76, 0, 77, 552, 79, 0, + 0, 554, 0, 0, 0, 82, 0, 83, 0, 0, + 0, 0, 0, 556, 0, 255, 0, 0, 0, 558, + 555, 557, 559, 560, 561, 86, 563, 564, 565, 566, + 567, 568, 0, 0, 553, 562, 547, 542, 544, 161, + 0, 0, 0, 0, 0, 393, 143, 144, 0, 0, + 395, 148, 397, 69, 70, 398, 0, 151, 0, 0, + 0, 153, 400, 401, 0, 0, 0, 0, 0, 0, + 402, 403, 157, 158, 252, 74, 0, 75, 0, 0, + 0, 76, 0, 77, 404, 79, 0, 0, 406, 0, + 0, 0, 82, 0, 83, 0, -244, 0, 0, 0, + 408, 0, 255, 0, 0, 0, 410, 407, 409, 411, + 412, 413, 86, 415, 416, 417, 418, 419, 420, 0, + 0, 405, 414, 399, 394, 396, 161, 0, 0, 0, + 0, 0, + + 334, 477, 282, 482, 270, 503, 467, 464, 275, 42, + 577, 55, 506, 479, 481, 217, 516, 522, 185, 23, + 468, 217, 540, 583, 10, 486, 488, 492, 490, 493, + 508, 270, 434, 385, 422, 383, 381, 366, 379, 368, + 270, 275, 468, 275, 334, 173, 282, 217, 242, 223, + 179, 468, 176, 334, 285, 371, 221, 343, 181, 341, + 211, 282, 465, 198, 352, 204, 457, 339, 370, 449, + 447, 206, 432, 442, 424, 334, 0, 93, 179, 501, + 0, 577, 318, 500, 213, 221, 93, 0, 471, 93, + 93, 93, 130, 483, 316, 317, 93, 461, 93, 93, + 215, 319, 93, 93, 320, 514, 93, 93, 129, 17, + 93, 0, 110, 94, 93, 93, 484, 102, 93, 242, + 93, 103, 101, 203, 337, 93, 11, 484, 93, 93, + 93, 513, 483, 93, 574, 515, 298, 93, 587, 334, + 0, 302, 200, 93, 93, 105, 334, 352, 125, 126, + 93, 11, 215, 269, 93, 93, 373, 510, 93, 124, + 512, 93, 436, 511, 179, 437, 93, 0, 242, 93, + 439, 127, 93, 123, 0, 436, 0, 128, 437, 93, + 93, 483, 215, 93, 93, 139, 436, 122, 335, 437, + 93, 93, 334, 141, 121, 362, 133, 376, 93, 93, + 100, 135, 93, 0, 117, 330, 361, 330, 131, 330, + 302, 93, 302, 93, 302, 330, 302, 0, 302, 0, + 302, 0, 0, 93, 327, 93, 345, 329, 302, 332, + 302, 351, 310, 0, 0, 0, 0, 349, 93, 0, + 348, 364, 93, 302, 93, 321, 484, 302, 93, 322, + 0, 93, 93, 302, 330, 323, 302, 302, 139, 302, + 35, 305, 0, 0, 325, 527, 141, 210, 35, 0, + 24, 37, 11, 0, 0, 0, 358, 0, 24, 37, + 11, 532, 529, 531, 533, 530, 534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, - 81, 82, 162, 163, 164, 0, 166, 167, 168, 169, - 170, 171, 0, 0, 159, 165, 151, 144, 146, 160, - 0, 0, 0, 0, 0, 141, 142, 143, 0, 0, - 145, 147, 148, 0, 0, 149, 0, 150, 0, 0, - 0, 152, 153, 154, 0, 0, 0, 0, 0, 0, - 424, 155, 156, 157, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 158, 0, 0, 0, 425, 0, + 0, 0, 0, 0, 0, 0, 0, 571, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 161, 0, 0, 0, 0, 0, 429, 426, 428, 162, - 163, 164, 0, 166, 167, 168, 169, 170, 171, 0, - 0, 159, 165, 151, 144, 146, 160, 0, 0, 0, - 0, 0, 141, 142, 143, 0, 0, 145, 147, 148, - 0, 0, 149, 0, 150, 0, 0, 0, 152, 153, - 154, 0, 0, 0, 0, 0, 0, 424, 155, 156, - 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 158, 0, 0, 0, 425, 0, 0, 0, 0, - 0, 0, 0, 427, 0, 0, 0, 161, 0, 0, - 0, 0, 0, 429, 426, 428, 162, 163, 164, 0, - 166, 167, 168, 169, 170, 171, 0, 0, 159, 165, - 151, 144, 146, 160, 0, 0, 0, 0, 0, 243, - 0, 0, 0, 0, 244, 0, 64, 65, 66, 246, - 0, 0, 0, 0, 0, 0, 247, 68, 0, 0, - 0, 0, 0, 0, 249, 250, 0, 0, 251, 71, - 0, 72, 0, 0, 0, 73, 0, 74, 75, 76, - 0, 0, 78, 0, 0, 0, 79, 0, 80, 0, - 0, 0, 0, 0, 253, 0, 254, 0, 0, 0, - 83, 252, 255, 256, 84, 257, 85, 258, 87, 27, - 88, 259, 260, 0, 0, 77, 86, 67, 18, 245, - 0, 0, 0, 0, 0, 0, 243, 0, 0, 0, - 0, 244, 0, 64, 65, 66, 246, 0, 0, 0, - 0, 0, 0, 247, 248, 0, 0, 0, 0, 0, - 0, 249, 250, 0, 0, 251, 71, 0, 72, 0, - 0, 0, 73, 0, 74, 75, 76, 0, 0, 78, - 0, 0, 0, 79, 0, 80, 0, 0, 0, 0, - 0, 253, 0, 254, 0, 0, 0, 83, 252, 255, - 256, 84, 257, 85, 258, 87, 27, 88, 259, 260, - 0, 0, 77, 86, 67, 18, 245, 0, 0, 0, - 0, 0, 0, 243, 0, 0, 0, 0, 244, 0, - 64, 65, 66, 246, 0, 0, 0, 0, 0, 0, - 247, 68, 0, 0, 0, 0, 0, 0, 527, 250, - 0, 0, 251, 528, 0, 72, 0, 0, 0, 73, - 0, 74, 75, 76, 0, 0, 78, 0, 0, 0, - 79, 0, 80, 0, 0, 0, 0, 0, 253, 0, - 254, 0, 0, 0, 83, 252, 255, 256, 84, 257, - 85, 258, 87, 27, 88, 259, 260, 0, 0, 77, - 86, 67, 18, 245, 0, 529, 0, 0, 0, 0, - 392, 142, 143, 0, 0, 394, 147, 396, 65, 66, - 397, 0, 150, 0, 0, 0, 152, 399, 400, 0, - 0, 0, 0, 0, 0, 401, 402, 156, 157, 251, - 71, 0, 72, 0, 0, 0, 73, 0, 74, 403, - 76, 0, 0, 405, 0, 0, 0, 79, 0, 80, - 0, -238, 0, 0, 0, 407, 0, 254, 0, 0, - 0, 409, 406, 408, 410, 411, 412, 85, 414, 415, - 416, 417, 418, 419, 0, 0, 404, 413, 398, 393, - 395, 160, 0, 0, 0, 0, 0, - - 463, 180, 197, 480, 476, 481, 504, 460, 478, 466, - 464, 284, 210, 184, 532, 526, 370, 540, 512, 281, - 10, 274, 12, 241, 537, 547, 216, 222, 499, 269, - 220, 502, 470, 498, 491, 333, 456, 485, 489, 487, - 518, 470, 203, 467, 51, 541, 38, 0, 205, 340, - 382, 380, 378, 351, 431, 421, 369, 367, 384, 216, - 281, 0, 274, 467, 269, 333, 433, 441, 92, 342, - 338, 93, 446, 448, 365, 423, 178, 172, 333, 175, - 333, 0, 541, 0, 333, 0, 92, 333, 351, 241, - 121, 241, 0, 220, 0, 92, 0, 435, 178, 120, - 436, 92, 92, 214, 138, 212, 92, 316, 92, 0, - 534, 0, 122, 140, 92, 92, 92, 92, 132, 317, - 318, 0, 336, 129, 363, 92, 134, 92, 334, 0, - 319, 361, 127, 92, 92, 483, 214, 92, 92, 101, - 0, 297, 92, 126, 551, 102, 301, 92, 92, 507, - 508, 92, 360, 482, 92, 92, 506, 509, 178, 92, - 92, 510, 511, 92, 92, 438, 99, 92, 116, 372, - 92, 375, 92, 130, 92, 92, 435, 123, 268, 436, - 125, 92, 0, 92, 199, 92, 124, 482, 315, 92, - 202, 483, 92, 92, 0, 92, 0, 92, 329, 109, - 104, 128, 301, 301, 0, 92, 92, 92, 329, 100, - 301, 301, 320, 301, 347, 0, 0, 92, 329, 0, - 348, 344, 301, 301, 321, 16, 33, 17, 92, 92, - 350, 0, 0, 301, 301, 0, 309, 92, 92, 326, - 331, 92, 301, 301, 322, 523, 301, 329, 329, 0, - 304, 324, 301, 301, 16, 33, 17, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 357, - 328, 0, 0, 0, 138, 0, 0, 0, 0, 0, - 0, 0, 0, 140, 209, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 569, 0, 0, 0, 0, 0, + 493, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; + 0, 0, 0}; const int JavaScriptGrammar::action_check [] = { - 2, 61, 60, 36, 33, 29, 33, 60, 8, 17, - 78, 29, 29, 1, 61, 8, 60, 60, 31, 2, - 1, 8, 7, 48, 2, 55, 8, 33, 7, 55, - 33, 7, 7, 7, 5, 36, 33, 36, 36, 60, - 5, 5, 8, 1, 7, 7, 7, 7, 16, 8, - 7, 60, 36, 33, 48, 7, 7, 48, 78, 55, - 55, 7, 66, 36, 20, 88, 36, 78, 60, 88, - 1, 76, 7, 7, 17, 65, 48, 0, 55, 29, - 29, 36, 36, 36, 8, 33, 7, -1, 8, 7, - -1, 36, 78, 60, 36, 36, 33, 36, 8, 8, - 33, 7, 8, 8, 8, 8, 8, 8, 8, -1, - 8, 10, 8, 8, 61, -1, 8, 61, 62, 8, - -1, 61, 62, 61, 62, 61, 62, 40, 40, 61, - 62, 61, 62, 29, 61, 62, 7, 12, 51, 51, - 7, 29, 61, 62, 15, 8, 40, 40, 8, 6, - 60, 60, 56, 56, 56, 60, 55, 51, 51, 60, - 60, 42, 60, 20, 50, 60, 33, 56, 54, 61, - 50, 15, 53, 2, 54, 15, 29, 8, 66, 67, - 29, 8, 57, 29, 8, -1, 29, 25, 63, 27, - 34, 25, 36, 27, 34, 8, 36, 60, -1, 7, - 38, 61, 62, 29, 38, 12, 15, 29, -1, 29, - -1, -1, -1, 66, 67, 29, -1, 66, 67, -1, - 66, 67, 7, 66, 67, 34, -1, 36, 29, -1, - 61, 62, 29, 29, 61, 62, 29, 61, 62, 12, - 66, 67, 29, -1, 66, 67, 66, 67, 61, 62, - 57, -1, -1, 61, 62, 25, 63, 27, 18, 19, - 74, 29, 25, -1, 27, 66, 67, -1, 38, 66, - 67, 85, -1, 66, 67, 38, 61, 62, 74, 66, - 67, 29, 18, 19, 57, 45, 46, -1, 36, 85, - 63, 23, 24, 61, 62, -1, -1, -1, 66, 67, - 32, -1, -1, 35, 29, 37, -1, -1, -1, 45, - 46, 23, 24, -1, 29, -1, 29, -1, 66, 67, - 32, 23, 24, 35, -1, 37, -1, -1, 18, 19, - 32, 23, 24, 35, -1, 37, 61, 62, -1, -1, - 32, 66, 67, 35, -1, 37, 61, 62, 61, 62, - -1, 66, 67, 66, 67, 45, 46, 23, 24, -1, - -1, -1, -1, -1, -1, 31, 32, 23, 24, 35, - -1, 37, -1, -1, -1, 31, 32, 23, 24, 35, - 10, 37, -1, -1, -1, 31, 32, -1, -1, 35, - -1, 37, 22, 10, -1, 23, 24, -1, -1, 29, - -1, 23, 24, 31, 32, 22, -1, 35, -1, 37, - 32, -1, 29, 35, -1, 37, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 55, -1, -1, -1, 59, - -1, -1, -1, -1, -1, -1, 66, 67, 55, -1, - -1, -1, 59, -1, 74, -1, -1, -1, 3, 66, - 67, -1, -1, 83, -1, 85, -1, 74, 13, -1, - -1, -1, 17, -1, -1, -1, 83, -1, 85, 23, - 24, 26, -1, 28, -1, -1, -1, 31, 32, 3, - -1, 35, -1, 37, 39, -1, 41, 42, -1, 13, - -1, -1, -1, 17, 49, -1, -1, 52, 53, -1, - -1, -1, 26, 58, 28, -1, -1, 31, -1, 64, - -1, -1, -1, -1, -1, 39, -1, 41, 42, -1, - -1, -1, -1, -1, 79, 49, -1, -1, 52, 53, - -1, -1, -1, -1, 58, -1, -1, 3, -1, -1, - 64, -1, -1, -1, -1, -1, -1, 13, -1, -1, - -1, 17, -1, -1, -1, 79, -1, -1, -1, -1, - 26, -1, 28, -1, -1, -1, -1, -1, -1, -1, + 60, 8, 36, 36, 33, 33, 7, 60, 7, 36, + 29, 33, 7, 7, 7, 36, 7, 55, 7, 78, + 1, 78, 48, 1, 36, 33, 36, 36, 60, 5, + 55, 61, 2, 33, 8, 55, 60, 16, 7, 7, + 7, 5, 48, 60, 7, 2, 60, 20, 7, 5, + 48, 17, 55, 2, 31, 7, 61, 8, 33, 7, + 7, 7, 7, 60, 36, 36, 7, 0, 8, 7, + 7, 36, 7, 88, 36, 29, 36, 1, 60, 65, + 33, 17, 78, 1, 7, 7, 36, 7, 7, 33, + 33, 76, 8, 2, 55, 78, 88, 36, 8, 29, + 8, 8, 36, 61, 36, 36, 48, 36, 8, 8, + 8, 66, 40, 8, 40, 8, -1, 7, 8, 8, + -1, -1, -1, 51, 15, 51, 8, 40, 40, 50, + 6, 8, 10, 54, 61, 62, 61, 62, 51, 51, + 42, 8, 33, 8, 20, 7, 61, 62, 8, 29, + 60, 53, 60, 60, 29, 61, 62, 56, 56, 29, + 60, 56, 50, 56, 61, 62, 54, 61, 62, 61, + 62, 60, 8, 29, 61, 62, 7, 55, 7, 61, + 61, 62, 8, 60, 29, -1, 15, 15, 15, 12, + 29, 66, 67, 60, 74, 60, 66, 67, 15, 29, + 8, 61, 62, -1, 33, 85, 34, 34, 36, 36, + 66, 67, 8, 29, -1, -1, -1, 34, -1, 36, + 29, 66, 67, 29, -1, 61, 62, 66, 67, 7, + 61, 62, 29, -1, 57, 61, 62, 29, -1, 25, + 63, 27, 12, 25, 74, 27, 25, 12, 27, -1, + 66, 67, 38, 61, 62, 85, 38, 66, 67, 38, + 66, 67, 29, 18, 19, 61, 62, 29, -1, 66, + 67, 29, -1, -1, 66, 67, 8, -1, 36, 18, + 19, 29, -1, 61, 62, -1, -1, 57, 36, -1, + 45, 46, 57, 63, 18, 19, 18, 19, 63, 66, + 67, 33, 23, 24, 66, 67, 45, 46, 66, 67, + 29, 32, 29, 25, 35, 27, 37, -1, 66, 67, + 29, 45, 46, 45, 46, 29, 38, 23, 24, 61, + 62, -1, 29, -1, -1, -1, 32, -1, -1, 35, + -1, 37, 61, 62, 61, 62, -1, 66, 67, 66, + 67, 29, 61, 62, -1, 59, -1, 66, 67, 23, + 24, -1, 66, 67, 61, 62, 23, 24, 32, 66, + 67, 35, -1, 37, -1, 32, 29, -1, 35, 29, + 37, 85, -1, 61, 62, 23, 24, -1, 66, 67, + -1, -1, -1, 31, 32, 23, 24, 35, -1, 37, + -1, -1, -1, 31, 32, -1, 59, 35, -1, 37, + -1, 61, 62, 66, 67, -1, 66, 67, 10, 23, + 24, -1, -1, -1, -1, -1, -1, 31, 32, -1, + 22, 35, 85, 37, -1, 23, 24, 29, -1, 10, + -1, 23, 24, 31, 32, -1, -1, 35, -1, 37, + 32, 22, -1, 35, -1, 37, -1, -1, 29, -1, + -1, -1, -1, 55, -1, -1, -1, 59, -1, -1, + -1, -1, -1, -1, 66, 67, -1, -1, -1, -1, + -1, -1, 74, -1, 55, -1, -1, -1, 59, -1, + -1, 83, -1, 85, -1, 66, 67, 3, -1, -1, + -1, -1, -1, 74, -1, -1, -1, 13, -1, 23, + 24, 17, 83, -1, 85, -1, -1, 31, 32, -1, + 26, 35, 28, 37, -1, 31, -1, -1, -1, -1, + -1, -1, -1, 39, -1, 41, 42, -1, -1, 12, + 13, -1, -1, 49, -1, -1, 52, 53, -1, 22, + -1, -1, 58, -1, -1, -1, 29, -1, 64, -1, + 33, 34, -1, 36, -1, -1, -1, -1, -1, -1, + 43, -1, -1, 79, 47, -1, -1, 3, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, + -1, 17, 65, 66, 67, -1, 69, -1, -1, -1, + 26, -1, 28, -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, 39, -1, 41, 42, -1, -1, -1, -1, -1, -1, 49, -1, -1, 52, 53, -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, 64, -1, @@ -611,122 +669,161 @@ const int JavaScriptGrammar::action_check [] = { -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, - 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, - -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, - 73, -1, 75, -1, -1, -1, -1, 80, 81, 82, - -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, - 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, - -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, - 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, - 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, - 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, - -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, - 73, -1, 75, -1, -1, -1, -1, 80, 81, 82, - -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, - 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, - -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, - 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, - 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, 74, 75, -1, -1, -1, -1, 80, 81, 82, - -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, - 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, - 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, - -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 59, -1, -1, -1, -1, -1, -1, - 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, - 76, 77, -1, -1, 80, 81, 82, 83, 84, 85, - -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, - 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, - -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, - 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 59, -1, -1, -1, -1, -1, 65, 66, 67, 68, - 69, 70, -1, 72, 73, 74, 75, 76, 77, -1, - -1, 80, 81, 82, 83, 84, 85, -1, -1, -1, - -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, - -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, - 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, - 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, - -1, -1, -1, 55, -1, -1, -1, 59, -1, -1, - -1, -1, -1, 65, 66, 67, 68, 69, 70, -1, - 72, 73, 74, 75, 76, 77, -1, -1, 80, 81, - 82, 83, 84, 85, -1, -1, -1, -1, -1, 4, - -1, -1, -1, -1, 9, -1, 11, 12, 13, 14, - -1, -1, -1, -1, -1, -1, 21, 22, -1, -1, - -1, -1, -1, -1, 29, 30, -1, -1, 33, 34, - -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, - -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, - -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, -1, -1, 80, 81, 82, 83, 84, - -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, - -1, 9, -1, 11, 12, 13, 14, -1, -1, -1, - -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, + -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, + -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + -1, 51, -1, 53, -1, -1, 56, -1, -1, -1, + -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, + -1, 71, -1, 73, -1, 75, -1, -1, -1, -1, + 80, 81, 82, -1, -1, -1, -1, -1, -1, -1, + -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, + -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, + -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, + -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, + 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, + -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, + 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, + -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, + -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, + -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, + -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, + 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, + 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, + -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, + -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, + -1, 75, -1, -1, -1, -1, 80, 81, 82, -1, + -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, + 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, + -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, + -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, + -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, + 51, -1, 53, -1, -1, 56, -1, -1, -1, -1, + -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, + 71, -1, 73, -1, 75, -1, -1, -1, -1, 80, + 81, 82, -1, -1, -1, -1, -1, -1, -1, -1, + 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, + -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, + -1, 69, -1, 71, -1, 73, -1, 75, -1, -1, + -1, -1, 80, 81, 82, -1, -1, 85, -1, -1, + -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, - -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - -1, -1, 80, 81, 82, 83, 84, -1, -1, -1, - -1, -1, -1, 4, -1, -1, -1, -1, 9, -1, - 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 61, -1, -1, -1, 65, 66, 67, + -1, 69, -1, 71, -1, 73, -1, 75, -1, -1, + -1, -1, 80, 81, 82, -1, 84, -1, 86, -1, + -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, + 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, - -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, - -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, - 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, - 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, - 71, 72, 73, 74, 75, 76, 77, -1, -1, 80, - 81, 82, 83, 84, -1, 86, -1, -1, -1, -1, - 4, 5, 6, -1, -1, 9, 10, 11, 12, 13, + 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, + -1, -1, -1, -1, -1, 66, 67, 68, 69, 70, + -1, 72, 73, 74, 75, 76, 77, -1, -1, 80, + 81, 82, 83, 84, 85, -1, -1, -1, -1, -1, + 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, - -1, -1, -1, -1, -1, 29, 30, 31, 32, 33, - 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, - 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, - -1, 55, -1, -1, -1, 59, -1, 61, -1, -1, - -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, + -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, + -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, -1, -1, 80, 81, 82, 83, - 84, 85, -1, -1, -1, -1, -1, + 84, 85, -1, -1, -1, -1, -1, 4, 5, 6, + -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, + -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, + -1, -1, 29, 30, 31, 32, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, + 47, -1, -1, -1, -1, -1, -1, -1, 55, -1, + -1, -1, 59, -1, -1, -1, -1, -1, 65, 66, + 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, + 77, -1, -1, 80, 81, 82, 83, 84, 85, -1, + -1, -1, -1, -1, 4, -1, -1, -1, -1, 9, + -1, 11, 12, 13, 14, -1, -1, -1, -1, -1, + -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, + 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, + -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, -1, -1, + 80, 81, 82, 83, 84, -1, -1, -1, -1, -1, + -1, 4, -1, -1, -1, -1, 9, -1, 11, 12, + 13, 14, -1, -1, -1, -1, -1, -1, 21, 22, + -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, + 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, + 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, + 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, + -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, -1, -1, 80, 81, 82, + 83, 84, -1, -1, -1, -1, -1, -1, 4, 5, + 6, -1, -1, 9, 10, 11, 12, 13, 14, -1, + 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, + -1, -1, -1, 29, 30, 31, 32, 33, 34, -1, + 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, + -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, + -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, -1, -1, 80, 81, 82, 83, 84, 85, + -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, + 9, 10, 11, 12, 13, 14, -1, 16, -1, -1, + -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, + 29, 30, 31, 32, 33, 34, -1, 36, -1, -1, + -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, + -1, -1, 51, -1, 53, -1, 55, -1, -1, -1, + 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, -1, + -1, 80, 81, 82, 83, 84, 85, -1, -1, -1, + -1, -1, - 77, 25, 25, 63, 94, 63, 16, 89, 19, 77, - 16, 16, 16, 59, 10, 14, 19, 19, 19, 14, - 5, 19, 6, 14, 6, 25, 19, 19, 25, 19, - 19, 25, 63, 21, 14, 16, 92, 16, 16, 14, - 16, 63, 25, 16, 16, 19, 15, -1, 25, 16, - 14, 16, 14, 19, 25, 25, 14, 16, 14, 19, - 14, -1, 19, 16, 19, 16, 14, 14, 36, 14, - 14, 39, 14, 16, 14, 27, 25, 16, 16, 25, - 16, -1, 19, -1, 16, -1, 36, 16, 19, 14, - 40, 14, -1, 19, -1, 36, -1, 30, 25, 40, - 33, 36, 36, 38, 19, 32, 36, 41, 36, -1, - 6, -1, 40, 28, 36, 36, 36, 36, 48, 41, - 41, -1, 60, 42, 60, 36, 46, 36, 60, -1, - 41, 60, 41, 36, 36, 38, 38, 36, 36, 38, - -1, 36, 36, 41, 81, 39, 41, 36, 36, 38, - 38, 36, 83, 38, 36, 36, 38, 38, 25, 36, - 36, 38, 38, 36, 36, 32, 38, 36, 41, 95, - 36, 96, 36, 42, 36, 36, 30, 41, 101, 33, - 41, 36, -1, 36, 50, 36, 41, 38, 41, 36, - 52, 38, 36, 36, -1, 36, -1, 36, 36, 42, - 44, 42, 41, 41, -1, 36, 36, 36, 36, 38, - 41, 41, 43, 41, 53, -1, -1, 36, 36, -1, - 58, 51, 41, 41, 43, 17, 18, 19, 36, 36, - 58, -1, -1, 41, 41, -1, 43, 36, 36, 47, - 58, 36, 41, 41, 43, 8, 41, 36, 36, -1, - 45, 49, 41, 41, 17, 18, 19, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, - 58, -1, -1, -1, 19, -1, -1, -1, -1, -1, - -1, -1, -1, 28, 29, -1, -1, -1, -1, -1, + 14, 93, 66, 15, 23, 29, 76, 76, 23, 20, + 23, 14, 29, 23, 15, 23, 23, 14, 62, 23, + 14, 23, 10, 29, 5, 14, 66, 66, 14, 29, + 14, 23, 66, 66, 29, 66, 14, 66, 66, 14, + 23, 23, 14, 23, 14, 14, 66, 23, 66, 23, + 29, 14, 29, 14, 14, 23, 23, 66, 29, 14, + 14, 66, 14, 29, 23, 29, 91, 66, 66, 14, + 66, 29, 29, 66, 30, 14, -1, 39, 29, 25, + -1, 23, 44, 29, 35, 23, 39, -1, 15, 39, + 39, 39, 45, 41, 44, 44, 39, 88, 39, 39, + 41, 44, 39, 39, 44, 41, 39, 39, 45, 6, + 39, -1, 45, 42, 39, 39, 41, 41, 39, 66, + 39, 42, 41, 55, 63, 39, 23, 41, 39, 39, + 39, 41, 41, 39, 6, 41, 39, 39, 80, 14, + -1, 44, 53, 39, 39, 47, 14, 23, 44, 44, + 39, 23, 41, 100, 39, 39, 94, 41, 39, 44, + 41, 39, 33, 41, 29, 36, 39, -1, 66, 39, + 35, 44, 39, 43, -1, 33, -1, 44, 36, 39, + 39, 41, 41, 39, 39, 23, 33, 43, 63, 36, + 39, 39, 14, 31, 43, 63, 51, 95, 39, 39, + 41, 49, 39, -1, 44, 39, 82, 39, 45, 39, + 44, 39, 44, 39, 44, 39, 44, -1, 44, -1, + 44, -1, -1, 39, 50, 39, 54, 61, 44, 61, + 44, 61, 46, -1, -1, -1, -1, 61, 39, -1, + 56, 63, 39, 44, 39, 46, 41, 44, 39, 46, + -1, 39, 39, 44, 39, 46, 44, 44, 23, 44, + 11, 48, -1, -1, 52, 8, 31, 32, 11, -1, + 21, 22, 23, -1, -1, -1, 61, -1, 21, 22, + 23, 14, 15, 16, 17, 18, 19, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 23, -1, -1, -1, -1, -1, + 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1}; + -1, -1, -1}; diff --git a/src/declarative/qml/parser/javascriptgrammar_p.h b/src/declarative/qml/parser/javascriptgrammar_p.h index 70c9766..830f533 100644 --- a/src/declarative/qml/parser/javascriptgrammar_p.h +++ b/src/declarative/qml/parser/javascriptgrammar_p.h @@ -150,15 +150,15 @@ public: T_XOR = 78, T_XOR_EQ = 79, - ACCEPT_STATE = 552, - RULE_COUNT = 317, - STATE_COUNT = 553, + ACCEPT_STATE = 588, + RULE_COUNT = 323, + STATE_COUNT = 589, TERMINAL_COUNT = 91, - NON_TERMINAL_COUNT = 103, + NON_TERMINAL_COUNT = 102, - GOTO_INDEX_OFFSET = 553, - GOTO_INFO_OFFSET = 1717, - GOTO_CHECK_OFFSET = 1717 + GOTO_INDEX_OFFSET = 589, + GOTO_INFO_OFFSET = 2092, + GOTO_CHECK_OFFSET = 2092 }; static const char *const spell []; diff --git a/src/declarative/qml/parser/javascriptlexer.cpp b/src/declarative/qml/parser/javascriptlexer.cpp index c0a4b63..7455b87 100644 --- a/src/declarative/qml/parser/javascriptlexer.cpp +++ b/src/declarative/qml/parser/javascriptlexer.cpp @@ -44,13 +44,6 @@ #endif #include "javascriptengine_p.h" - - - - - - - #include "javascriptlexer_p.h" #include "javascriptgrammar_p.h" @@ -73,10 +66,12 @@ extern double qstrtod(const char *s00, char const **se, bool *ok); while (0) namespace JavaScript { -extern qjsreal integerFromString(const char *buf, int size, int radix); +extern double integerFromString(const char *buf, int size, int radix); } -JavaScript::Lexer::Lexer(JavaScriptEnginePrivate *eng) +using namespace JavaScript; + +Lexer::Lexer(Engine *eng) : driver(eng), yylineno(0), done(false), @@ -101,6 +96,7 @@ JavaScript::Lexer::Lexer(JavaScriptEnginePrivate *eng) parenthesesCount(0), prohibitAutomaticSemicolon(false) { + driver->setLexer(this); // allocate space for read buffers buffer8 = new char[size8]; buffer16 = new QChar[size16]; @@ -109,13 +105,13 @@ JavaScript::Lexer::Lexer(JavaScriptEnginePrivate *eng) } -JavaScript::Lexer::~Lexer() +Lexer::~Lexer() { delete [] buffer8; delete [] buffer16; } -void JavaScript::Lexer::setCode(const QString &c, int lineno) +void Lexer::setCode(const QString &c, int lineno) { errmsg = QString(); yylineno = lineno; @@ -135,7 +131,7 @@ void JavaScript::Lexer::setCode(const QString &c, int lineno) next3 = (length > 3) ? code[3].unicode() : 0; } -void JavaScript::Lexer::shift(uint p) +void Lexer::shift(uint p) { while (p--) { ++pos; @@ -147,13 +143,13 @@ void JavaScript::Lexer::shift(uint p) } } -void JavaScript::Lexer::setDone(State s) +void Lexer::setDone(State s) { state = s; done = true; } -int JavaScript::Lexer::findReservedWord(const QChar *c, int size) const +int Lexer::findReservedWord(const QChar *c, int size) const { switch (size) { case 2: { @@ -454,7 +450,7 @@ int JavaScript::Lexer::findReservedWord(const QChar *c, int size) const return -1; } -int JavaScript::Lexer::lex() +int Lexer::lex() { int token = 0; state = Start; @@ -772,10 +768,10 @@ int JavaScript::Lexer::lex() if (state == Number) { dval = qstrtod(buffer8, 0, 0); } else if (state == Hex) { // scan hex numbers - dval = JavaScript::integerFromString(buffer8, pos8, 16); + dval = integerFromString(buffer8, pos8, 16); state = Number; } else if (state == Octal) { // scan octal number - dval = JavaScript::integerFromString(buffer8, pos8, 8); + dval = integerFromString(buffer8, pos8, 8); state = Number; } @@ -843,18 +839,18 @@ int JavaScript::Lexer::lex() } } -bool JavaScript::Lexer::isWhiteSpace() const +bool Lexer::isWhiteSpace() const { return (current == ' ' || current == '\t' || current == 0x0b || current == 0x0c); } -bool JavaScript::Lexer::isLineTerminator() const +bool Lexer::isLineTerminator() const { return (current == '\n' || current == '\r'); } -bool JavaScript::Lexer::isIdentLetter(ushort c) +bool Lexer::isIdentLetter(ushort c) { /* TODO: allow other legitimate unicode chars */ return ((c >= 'a' && c <= 'z') @@ -863,24 +859,24 @@ bool JavaScript::Lexer::isIdentLetter(ushort c) || c == '_'); } -bool JavaScript::Lexer::isDecimalDigit(ushort c) +bool Lexer::isDecimalDigit(ushort c) { return (c >= '0' && c <= '9'); } -bool JavaScript::Lexer::isHexDigit(ushort c) const +bool Lexer::isHexDigit(ushort c) const { return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } -bool JavaScript::Lexer::isOctalDigit(ushort c) const +bool Lexer::isOctalDigit(ushort c) const { return (c >= '0' && c <= '7'); } -int JavaScript::Lexer::matchPunctuator(ushort c1, ushort c2, +int Lexer::matchPunctuator(ushort c1, ushort c2, ushort c3, ushort c4) { if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { @@ -987,7 +983,7 @@ int JavaScript::Lexer::matchPunctuator(ushort c1, ushort c2, } } -ushort JavaScript::Lexer::singleEscape(ushort c) const +ushort Lexer::singleEscape(ushort c) const { switch(c) { case 'b': @@ -1013,13 +1009,13 @@ ushort JavaScript::Lexer::singleEscape(ushort c) const } } -ushort JavaScript::Lexer::convertOctal(ushort c1, ushort c2, +ushort Lexer::convertOctal(ushort c1, ushort c2, ushort c3) const { return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); } -unsigned char JavaScript::Lexer::convertHex(ushort c) +unsigned char Lexer::convertHex(ushort c) { if (c >= '0' && c <= '9') return (c - '0'); @@ -1029,19 +1025,19 @@ unsigned char JavaScript::Lexer::convertHex(ushort c) return (c - 'A' + 10); } -unsigned char JavaScript::Lexer::convertHex(ushort c1, ushort c2) +unsigned char Lexer::convertHex(ushort c1, ushort c2) { return ((convertHex(c1) << 4) + convertHex(c2)); } -QChar JavaScript::Lexer::convertUnicode(ushort c1, ushort c2, +QChar Lexer::convertUnicode(ushort c1, ushort c2, ushort c3, ushort c4) { return QChar((convertHex(c3) << 4) + convertHex(c4), (convertHex(c1) << 4) + convertHex(c2)); } -void JavaScript::Lexer::record8(ushort c) +void Lexer::record8(ushort c) { Q_ASSERT(c <= 0xff); @@ -1057,7 +1053,7 @@ void JavaScript::Lexer::record8(ushort c) buffer8[pos8++] = (char) c; } -void JavaScript::Lexer::record16(QChar c) +void Lexer::record16(QChar c) { // enlarge buffer if full if (pos16 >= size16 - 1) { @@ -1071,14 +1067,14 @@ void JavaScript::Lexer::record16(QChar c) buffer16[pos16++] = c; } -void JavaScript::Lexer::recordStartPos() +void Lexer::recordStartPos() { startpos = pos; startlineno = yylineno; startcolumn = yycolumn; } -bool JavaScript::Lexer::scanRegExp(RegExpBodyPrefix prefix) +bool Lexer::scanRegExp(RegExpBodyPrefix prefix) { pos16 = 0; bool lastWasEscape = false; @@ -1110,7 +1106,7 @@ bool JavaScript::Lexer::scanRegExp(RegExpBodyPrefix prefix) flags = 0; while (isIdentLetter(current)) { - int flag = JavaScript::Ecma::RegExp::flagFromChar(current); + int flag = Ecma::RegExp::flagFromChar(current); if (flag == 0) { errmsg = QString::fromLatin1("Invalid regular expression flag '%0'") .arg(QChar(current)); @@ -1124,7 +1120,7 @@ bool JavaScript::Lexer::scanRegExp(RegExpBodyPrefix prefix) return true; } -void JavaScript::Lexer::syncProhibitAutomaticSemicolon() +void Lexer::syncProhibitAutomaticSemicolon() { if (parenthesesState == BalancedParentheses) { // we have seen something like "if (foo)", which means we should diff --git a/src/declarative/qml/parser/javascriptlexer_p.h b/src/declarative/qml/parser/javascriptlexer_p.h index e71c10c..092609c 100644 --- a/src/declarative/qml/parser/javascriptlexer_p.h +++ b/src/declarative/qml/parser/javascriptlexer_p.h @@ -59,15 +59,15 @@ QT_BEGIN_NAMESPACE -class JavaScriptEnginePrivate; -class JavaScriptNameIdImpl; - namespace JavaScript { +class Engine; +class NameId; + class Lexer { public: - Lexer(JavaScriptEnginePrivate *eng); + Lexer(Engine *eng); ~Lexer(); void setCode(const QString &c, int lineno); @@ -136,7 +136,7 @@ public: bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix); - JavaScriptNameIdImpl *pattern; + NameId *pattern; int flags; State lexerState() const @@ -155,7 +155,7 @@ public: { err = NoError; } private: - JavaScriptEnginePrivate *driver; + Engine *driver; int yylineno; bool done; char *buffer8; @@ -194,7 +194,7 @@ public: inline int ival() const { return qsyylval.ival; } inline double dval() const { return qsyylval.dval; } - inline JavaScriptNameIdImpl *ustr() const { return qsyylval.ustr; } + inline NameId *ustr() const { return qsyylval.ustr; } const QChar *characterBuffer() const { return buffer16; } int characterCount() const { return pos16; } @@ -219,7 +219,7 @@ private: union { int ival; double dval; - JavaScriptNameIdImpl *ustr; + NameId *ustr; } qsyylval; // current and following unicode characters diff --git a/src/declarative/qml/parser/javascriptnodepool_p.h b/src/declarative/qml/parser/javascriptnodepool_p.h index 3f59123..cb56fbb 100644 --- a/src/declarative/qml/parser/javascriptnodepool_p.h +++ b/src/declarative/qml/parser/javascriptnodepool_p.h @@ -60,8 +60,6 @@ QT_BEGIN_NAMESPACE -class JavaScriptEnginePrivate; - namespace JavaScript { namespace AST { @@ -70,6 +68,7 @@ class Node; class Code; class CompilationUnit; +class Engine; template <typename NodeType> inline NodeType *makeAstNode(MemoryPool *storage) @@ -109,13 +108,13 @@ inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg class NodePool : public MemoryPool { public: - NodePool(const QString &fileName, JavaScriptEnginePrivate *engine); + NodePool(const QString &fileName, Engine *engine); virtual ~NodePool(); Code *createCompiledCode(AST::Node *node, CompilationUnit &compilation); inline QString fileName() const { return m_fileName; } - inline JavaScriptEnginePrivate *engine() const { return m_engine; } + inline Engine *engine() const { return m_engine; } #ifndef J_SCRIPT_NO_EVENT_NOTIFY inline qint64 id() const { return m_id; } #endif @@ -123,7 +122,7 @@ public: private: QHash<AST::Node*, Code*> m_codeCache; QString m_fileName; - JavaScriptEnginePrivate *m_engine; + Engine *m_engine; #ifndef J_SCRIPT_NO_EVENT_NOTIFY qint64 m_id; #endif diff --git a/src/declarative/qml/parser/javascriptparser.cpp b/src/declarative/qml/parser/javascriptparser.cpp index ed791c8..7ff438e 100644 --- a/src/declarative/qml/parser/javascriptparser.cpp +++ b/src/declarative/qml/parser/javascriptparser.cpp @@ -53,6 +53,7 @@ #include "javascriptparser_p.h" +#include <QVarLengthArray> // // This file is automatically generated from javascript.g. @@ -63,7 +64,7 @@ using namespace JavaScript; QT_BEGIN_NAMESPACE -void JavaScriptParser::reallocateStack() +void Parser::reallocateStack() { if (! stack_size) stack_size = 128; @@ -75,7 +76,7 @@ void JavaScriptParser::reallocateStack() location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation))); } -inline static bool automatic(JavaScriptEnginePrivate *driver, int token) +inline static bool automatic(Engine *driver, int token) { return token == JavaScriptGrammar::T_RBRACE || token == 0 @@ -83,7 +84,8 @@ inline static bool automatic(JavaScriptEnginePrivate *driver, int token) } -JavaScriptParser::JavaScriptParser(): +Parser::Parser(Engine *engine): + driver(engine), tos(0), stack_size(0), sym_stack(0), @@ -94,7 +96,7 @@ JavaScriptParser::JavaScriptParser(): { } -JavaScriptParser::~JavaScriptParser() +Parser::~Parser() { if (stack_size) { qFree(sym_stack); @@ -113,7 +115,35 @@ static inline AST::SourceLocation location(Lexer *lexer) return loc; } -bool JavaScriptParser::parse(JavaScriptEnginePrivate *driver) +AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) +{ + QVarLengthArray<NameId *, 4> nameIds; + QVarLengthArray<AST::SourceLocation, 4> locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) { + AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name); + q->identifierToken = idExpr->identifierToken; + + AST::UiQualifiedId *currentId = q; + for (int i = nameIds.size() - 1; i != -1; --i) { + currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]); + currentId->identifierToken = locations[i]; + } + + return currentId->finish(); + } + + return 0; +} + +bool Parser::parse() { Lexer *lexer = driver->lexer(); bool hadErrors = false; @@ -166,7 +196,7 @@ bool JavaScriptParser::parse(JavaScriptEnginePrivate *driver) case 0: { program = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, sym(2).UiObjectMemberList->finish()); - sym(1).UiProgram = program; + sym(1).UiProgram = program; } break; case 2: { @@ -233,21 +263,12 @@ case 14: { } break; case 15: { - AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), sym(1).UiQualifiedId->finish(), - sym(3).sval, sym(4).UiObjectInitializer); - node->colonToken = loc(2); - node->identifierToken = loc(3); - sym(1).Node = node; -} break; - -case 16: { - AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).sval, + AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(2).UiObjectInitializer); - node->identifierToken = loc(1); sym(1).Node = node; } break; -case 18: { +case 17: { AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(4).UiObjectMemberList->finish()); node->colonToken = loc(2); @@ -256,34 +277,50 @@ case 18: { sym(1).Node = node; } break; -case 19: { +case 18: { AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); node->literalToken = loc(1); sym(1).Node = node; } break; -case 21: { +case 20: { AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; - case 22: -case 23: { + +case 21: { + if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(3).Expression)) { + AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + sym(1).UiQualifiedId->finish(), qualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + sym(1).Node = node; + } else { + sym(1).Node = 0; + + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(2), + QLatin1String("Expected a type name after token `:'"))); + + return false; // ### recover + } +} break; +case 22:case 23:case 24:case 25:case 26:case 27: +{ AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(3).Statement); node->colonToken = loc(2); sym(1).Node = node; } break; -case 24: +case 28: -case 25: { +case 29: { sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); break; } -case 27: { - AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (JavaScriptNameIdImpl *)0, sym(2).sval); +case 31: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); node->typeToken = loc(2); @@ -291,7 +328,7 @@ case 27: { sym(1).Node = node; } break; -case 29: { +case 33: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval); node->propertyToken = loc(1); node->typeToken = loc(2); @@ -300,7 +337,7 @@ case 29: { sym(1).Node = node; } break; -case 31: { +case 35: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval); node->isDefaultMember = true; node->defaultToken = loc(1); @@ -311,7 +348,7 @@ case 31: { sym(1).Node = node; } break; -case 33: { +case 37: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval, sym(5).Expression); node->propertyToken = loc(1); @@ -322,7 +359,7 @@ case 33: { sym(1).Node = node; } break; -case 35: { +case 39: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, sym(6).Expression); node->isDefaultMember = true; @@ -335,88 +372,76 @@ case 35: { sym(1).Node = node; } break; -case 36: { +case 40: { sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); } break; -case 37: { +case 41: { sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); } break; -case 38: -case 39: +case 42: +case 43: { AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 41: { +case 45: { QString s = QLatin1String(JavaScriptGrammar::spell[T_PROPERTY]); sym(1).sval = driver->intern(s.constData(), s.length()); break; } -case 42: { +case 46: { QString s = QLatin1String(JavaScriptGrammar::spell[T_SIGNAL]); sym(1).sval = driver->intern(s.constData(), s.length()); break; } -case 43: { - AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).sval); - node->identifierToken = loc(1); - sym(1).Node = node; -} break; - -case 44: { - AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).UiQualifiedId, sym(3).sval); - node->identifierToken = loc(3); - sym(1).Node = node; -} break; - -case 45: { +case 47: { AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool()); node->thisToken = loc(1); sym(1).Node = node; } break; -case 46: { +case 48: { AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 47: { +case 49: { AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool()); node->nullToken = loc(1); sym(1).Node = node; } break; -case 48: { +case 50: { AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool()); node->trueToken = loc(1); sym(1).Node = node; } break; -case 49: { +case 51: { AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool()); node->falseToken = loc(1); sym(1).Node = node; } break; -case 50: { +case 52: { AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval); node->literalToken = loc(1); sym(1).Node = node; } break; -case 51: { +case 53: { AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); node->literalToken = loc(1); sym(1).Node = node; } break; -case 52: { +case 54: { bool rx = lexer->scanRegExp(Lexer::NoPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); @@ -427,7 +452,7 @@ case 52: { sym(1).Node = node; } break; -case 53: { +case 55: { bool rx = lexer->scanRegExp(Lexer::EqualPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); @@ -438,29 +463,46 @@ case 53: { sym(1).Node = node; } break; -case 54: { - AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision); +case 56: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->rbracketToken = loc(2); + sym(1).Node = node; +} break; + +case 57: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; -case 55: { +case 58: { AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; -case 56: { - AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), sym(4).Elision); +case 59: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 60: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + sym(4).Elision->finish()); node->lbracketToken = loc(1); node->commaToken = loc(3); node->rbracketToken = loc(5); sym(1).Node = node; } break; -case 57: { +case 61: { AST::ObjectLiteral *node = 0; if (sym(2).Node) node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), @@ -472,7 +514,7 @@ case 57: { sym(1).Node = node; } break; -case 58: { +case 62: { AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), sym(2).PropertyNameAndValueList->finish ()); node->lbraceToken = loc(1); @@ -480,100 +522,104 @@ case 58: { sym(1).Node = node; } break; -case 59: { +case 63: { AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression); node->lparenToken = loc(1); node->rparenToken = loc(3); sym(1).Node = node; } break; -case 60: { - sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision, sym(2).Expression); +case 64: { + AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 65: { + AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).UiQualifiedId, sym(3).sval); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 66: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); } break; -case 61: { - AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision, sym(4).Expression); +case 67: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); +} break; + +case 68: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, + (AST::Elision *) 0, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 62: { +case 69: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(), + sym(4).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 70: { AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); node->commaToken = loc(1); sym(1).Node = node; } break; -case 63: { +case 71: { AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); node->commaToken = loc(2); sym(1).Node = node; } break; -case 64: { - sym(1).Node = 0; -} break; - -case 65: { - sym(1).Elision = sym(1).Elision->finish (); -} break; - -case 66: { +case 72: { AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), sym(1).PropertyName, sym(3).Expression); node->colonToken = loc(2); sym(1).Node = node; } break; -case 67: { +case 73: { AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); node->commaToken = loc(2); node->colonToken = loc(4); - sym(1).Node = node; + sym(1).Node = node; } break; -case 68: { +case 74: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; -case 69: -case 70: { +case 75: +case 76: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; -case 71: { +case 77: { AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; -case 72: { +case 78: { AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; -case 73: { +case 79: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); - sym(1).Node = node; + sym(1).Node = node; } break; -case 74: - -case 75: - -case 76: - -case 77: - -case 78: - -case 79: - case 80: case 81: @@ -623,25 +669,37 @@ case 102: case 103: case 104: + +case 105: + +case 106: + +case 107: + +case 108: + +case 109: + +case 110: { sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); } break; -case 109: { +case 115: { AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -case 110: { +case 116: { AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 111: { +case 117: { AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList); node->newToken = loc(1); node->lparenToken = loc(3); @@ -649,384 +707,384 @@ case 111: { sym(1).Node = node; } break; -case 113: { +case 119: { AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression); node->newToken = loc(1); sym(1).Node = node; } break; -case 114: { +case 120: { AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; -case 115: { +case 121: { AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; -case 116: { +case 122: { AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -case 117: { +case 123: { AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 118: { +case 124: { sym(1).Node = 0; } break; -case 119: { +case 125: { sym(1).Node = sym(1).ArgumentList->finish(); } break; -case 120: { +case 126: { sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression); } break; -case 121: { +case 127: { AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 125: { +case 131: { AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); node->incrementToken = loc(2); sym(1).Node = node; } break; -case 126: { +case 132: { AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); node->decrementToken = loc(2); sym(1).Node = node; } break; -case 128: { +case 134: { AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); node->deleteToken = loc(1); sym(1).Node = node; } break; -case 129: { +case 135: { AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression); node->voidToken = loc(1); sym(1).Node = node; } break; -case 130: { +case 136: { AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); node->typeofToken = loc(1); sym(1).Node = node; } break; -case 131: { +case 137: { AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); node->incrementToken = loc(1); sym(1).Node = node; } break; -case 132: { +case 138: { AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); node->decrementToken = loc(1); sym(1).Node = node; } break; -case 133: { +case 139: { AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); node->plusToken = loc(1); sym(1).Node = node; } break; -case 134: { +case 140: { AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); node->minusToken = loc(1); sym(1).Node = node; } break; -case 135: { +case 141: { AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression); node->tildeToken = loc(1); sym(1).Node = node; } break; -case 136: { +case 142: { AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression); node->notToken = loc(1); sym(1).Node = node; } break; -case 138: { +case 144: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Mul, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 139: { +case 145: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Div, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 140: { +case 146: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Mod, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 142: { +case 148: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Add, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 143: { +case 149: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Sub, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 145: { +case 151: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::LShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 146: { +case 152: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::RShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 147: { +case 153: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::URShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 149: { +case 155: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 150: { +case 156: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 151: { +case 157: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 152: { +case 158: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 153: { +case 159: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 154: { +case 160: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::In, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 156: { +case 162: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 157: { +case 163: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 158: { +case 164: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 159: { +case 165: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 160: { +case 166: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 162: { +case 168: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 163: { +case 169: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 164: { +case 170: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 165: { +case 171: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 167: { +case 173: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 168: { +case 174: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 169: { +case 175: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 170: { +case 176: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 172: { +case 178: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 174: { +case 180: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 176: { +case 182: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 178: { +case 184: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 180: { +case 186: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 182: { +case 188: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 184: { +case 190: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 186: { +case 192: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 188: { +case 194: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 190: { +case 196: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 192: { +case 198: { AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1034,7 +1092,7 @@ case 192: { sym(1).Node = node; } break; -case 194: { +case 200: { AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1042,112 +1100,112 @@ case 194: { sym(1).Node = node; } break; -case 196: { +case 202: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 198: { +case 204: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 199: { +case 205: { sym(1).ival = QSOperator::Assign; } break; -case 200: { +case 206: { sym(1).ival = QSOperator::InplaceMul; } break; -case 201: { +case 207: { sym(1).ival = QSOperator::InplaceDiv; } break; -case 202: { +case 208: { sym(1).ival = QSOperator::InplaceMod; } break; -case 203: { +case 209: { sym(1).ival = QSOperator::InplaceAdd; } break; -case 204: { +case 210: { sym(1).ival = QSOperator::InplaceSub; } break; -case 205: { +case 211: { sym(1).ival = QSOperator::InplaceLeftShift; } break; -case 206: { +case 212: { sym(1).ival = QSOperator::InplaceRightShift; } break; -case 207: { +case 213: { sym(1).ival = QSOperator::InplaceURightShift; } break; -case 208: { +case 214: { sym(1).ival = QSOperator::InplaceAnd; } break; -case 209: { +case 215: { sym(1).ival = QSOperator::InplaceXor; } break; -case 210: { +case 216: { sym(1).ival = QSOperator::InplaceOr; } break; -case 212: { +case 218: { AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 213: { +case 219: { sym(1).Node = 0; } break; -case 216: { +case 222: { AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 217: { +case 223: { sym(1).Node = 0; } break; -case 234: { +case 240: { AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -case 235: { +case 241: { sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement); } break; -case 236: { +case 242: { sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); } break; -case 237: { +case 243: { sym(1).Node = 0; } break; -case 238: { +case 244: { sym(1).Node = sym(1).StatementList->finish (); } break; -case 240: { +case 246: { AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(), sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); node->declarationKindToken = loc(1); @@ -1155,76 +1213,76 @@ case 240: { sym(1).Node = node; } break; -case 241: { +case 247: { sym(1).ival = T_CONST; } break; -case 242: { +case 248: { sym(1).ival = T_VAR; } break; -case 243: { +case 249: { sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); } break; -case 244: { +case 250: { AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); node->commaToken = loc(2); sym(1).Node = node; } break; -case 245: { +case 251: { sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); } break; -case 246: { +case 252: { sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); } break; -case 247: { +case 253: { AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 248: { +case 254: { AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 249: { +case 255: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -case 250: { +case 256: { sym(1).Node = 0; } break; -case 252: { +case 258: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -case 253: { +case 259: { sym(1).Node = 0; } break; -case 255: { +case 261: { AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool()); node->semicolonToken = loc(1); sym(1).Node = node; } break; -case 257: { +case 263: { AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 258: { +case 264: { AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1233,7 +1291,7 @@ case 258: { sym(1).Node = node; } break; -case 259: { +case 265: { AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1241,7 +1299,7 @@ case 259: { sym(1).Node = node; } break; -case 261: { +case 267: { AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression); node->doToken = loc(1); node->whileToken = loc(3); @@ -1251,7 +1309,7 @@ case 261: { sym(1).Node = node; } break; -case 262: { +case 268: { AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->whileToken = loc(1); node->lparenToken = loc(2); @@ -1259,7 +1317,7 @@ case 262: { sym(1).Node = node; } break; -case 263: { +case 269: { AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); node->forToken = loc(1); @@ -1270,7 +1328,7 @@ case 263: { sym(1).Node = node; } break; -case 264: { +case 270: { AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(), sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, sym(8).Expression, sym(10).Statement); @@ -1283,7 +1341,7 @@ case 264: { sym(1).Node = node; } break; -case 265: { +case 271: { AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Statement); node->forToken = loc(1); @@ -1293,7 +1351,7 @@ case 265: { sym(1).Node = node; } break; -case 266: { +case 272: { AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(), sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); node->forToken = loc(1); @@ -1304,14 +1362,14 @@ case 266: { sym(1).Node = node; } break; -case 268: { +case 274: { AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool()); node->continueToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 270: { +case 276: { AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval); node->continueToken = loc(1); node->identifierToken = loc(2); @@ -1319,14 +1377,14 @@ case 270: { sym(1).Node = node; } break; -case 272: { +case 278: { AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool()); node->breakToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 274: { +case 280: { AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval); node->breakToken = loc(1); node->identifierToken = loc(2); @@ -1334,14 +1392,14 @@ case 274: { sym(1).Node = node; } break; -case 276: { +case 282: { AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression); node->returnToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -case 277: { +case 283: { AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->withToken = loc(1); node->lparenToken = loc(2); @@ -1349,7 +1407,7 @@ case 277: { sym(1).Node = node; } break; -case 278: { +case 284: { AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); node->switchToken = loc(1); node->lparenToken = loc(2); @@ -1357,90 +1415,90 @@ case 278: { sym(1).Node = node; } break; -case 279: { +case 285: { AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -case 280: { +case 286: { AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(5); sym(1).Node = node; } break; -case 281: { +case 287: { sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); } break; -case 282: { +case 288: { sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); } break; -case 283: { +case 289: { sym(1).Node = 0; } break; -case 284: { +case 290: { sym(1).Node = sym(1).CaseClauses->finish (); } break; -case 285: { +case 291: { AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList); node->caseToken = loc(1); node->colonToken = loc(3); sym(1).Node = node; } break; -case 286: { +case 292: { AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList); node->defaultToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -case 287: -case 288: { +case 293: +case 294: { AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -case 289: { +case 295: { AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -case 291: { +case 297: { AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression); node->throwToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -case 292: { +case 298: { AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); node->tryToken = loc(1); sym(1).Node = node; } break; -case 293: { +case 299: { AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -case 294: { +case 300: { AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -case 295: { +case 301: { AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block); node->catchToken = loc(1); node->lparenToken = loc(2); @@ -1449,20 +1507,20 @@ case 295: { sym(1).Node = node; } break; -case 296: { +case 302: { AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block); node->finallyToken = loc(1); sym(1).Node = node; } break; -case 298: { +case 304: { AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool()); node->debuggerToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 299: { +case 305: { AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); node->identifierToken = loc(2); @@ -1473,7 +1531,7 @@ case 299: { sym(1).Node = node; } break; -case 300: { +case 306: { AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); if (sym(2).sval) @@ -1485,56 +1543,56 @@ case 300: { sym(1).Node = node; } break; -case 301: { +case 307: { AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 302: { +case 308: { AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); node->commaToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 303: { +case 309: { sym(1).Node = 0; } break; -case 304: { +case 310: { sym(1).Node = sym(1).FormalParameterList->finish (); } break; -case 305: { +case 311: { sym(1).Node = 0; } break; -case 307: { +case 313: { sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); } break; -case 308: { +case 314: { sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); } break; -case 309: { +case 315: { sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); } break; -case 310: { +case 316: { sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); } break; -case 311: { +case 317: { sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); } break; -case 312: { +case 318: { sym(1).sval = 0; } break; -case 314: { +case 320: { sym(1).Node = 0; } break; diff --git a/src/declarative/qml/parser/javascriptparser_p.h b/src/declarative/qml/parser/javascriptparser_p.h index 5e68fe7..2ae4c34 100644 --- a/src/declarative/qml/parser/javascriptparser_p.h +++ b/src/declarative/qml/parser/javascriptparser_p.h @@ -62,86 +62,71 @@ #include "javascriptgrammar_p.h" #include "javascriptast_p.h" +#include "javascriptengine_p.h" + #include <QtCore/QList> QT_BEGIN_NAMESPACE class QString; -class JavaScriptEnginePrivate; -class JavaScriptNameIdImpl; -class JavaScriptParser: protected JavaScriptGrammar +namespace JavaScript { + +class Engine; +class NameId; + +class Parser: protected JavaScriptGrammar { public: union Value { int ival; double dval; - JavaScriptNameIdImpl *sval; - JavaScript::AST::ArgumentList *ArgumentList; - JavaScript::AST::CaseBlock *CaseBlock; - JavaScript::AST::CaseClause *CaseClause; - JavaScript::AST::CaseClauses *CaseClauses; - JavaScript::AST::Catch *Catch; - JavaScript::AST::DefaultClause *DefaultClause; - JavaScript::AST::ElementList *ElementList; - JavaScript::AST::Elision *Elision; - JavaScript::AST::ExpressionNode *Expression; - JavaScript::AST::Finally *Finally; - JavaScript::AST::FormalParameterList *FormalParameterList; - JavaScript::AST::FunctionBody *FunctionBody; - JavaScript::AST::FunctionDeclaration *FunctionDeclaration; - JavaScript::AST::Node *Node; - JavaScript::AST::PropertyName *PropertyName; - JavaScript::AST::PropertyNameAndValueList *PropertyNameAndValueList; - JavaScript::AST::SourceElement *SourceElement; - JavaScript::AST::SourceElements *SourceElements; - JavaScript::AST::Statement *Statement; - JavaScript::AST::StatementList *StatementList; - JavaScript::AST::Block *Block; - JavaScript::AST::VariableDeclaration *VariableDeclaration; - JavaScript::AST::VariableDeclarationList *VariableDeclarationList; - - JavaScript::AST::UiProgram *UiProgram; - JavaScript::AST::UiImportList *UiImportList; - JavaScript::AST::UiImport *UiImport; - JavaScript::AST::UiPublicMember *UiPublicMember; - JavaScript::AST::UiObjectDefinition *UiObjectDefinition; - JavaScript::AST::UiObjectInitializer *UiObjectInitializer; - JavaScript::AST::UiObjectBinding *UiObjectBinding; - JavaScript::AST::UiScriptBinding *UiScriptBinding; - JavaScript::AST::UiArrayBinding *UiArrayBinding; - JavaScript::AST::UiObjectMember *UiObjectMember; - JavaScript::AST::UiObjectMemberList *UiObjectMemberList; - JavaScript::AST::UiQualifiedId *UiQualifiedId; - }; - - struct DiagnosticMessage { - enum Kind { Warning, Error }; - - DiagnosticMessage() - : kind(Error) {} - - DiagnosticMessage(Kind kind, const JavaScript::AST::SourceLocation &loc, const QString &message) - : kind(kind), loc(loc), message(message) {} - - bool isWarning() const - { return kind == Warning; } - - bool isError() const - { return kind == Error; } - - Kind kind; - JavaScript::AST::SourceLocation loc; - QString message; + NameId *sval; + AST::ArgumentList *ArgumentList; + AST::CaseBlock *CaseBlock; + AST::CaseClause *CaseClause; + AST::CaseClauses *CaseClauses; + AST::Catch *Catch; + AST::DefaultClause *DefaultClause; + AST::ElementList *ElementList; + AST::Elision *Elision; + AST::ExpressionNode *Expression; + AST::Finally *Finally; + AST::FormalParameterList *FormalParameterList; + AST::FunctionBody *FunctionBody; + AST::FunctionDeclaration *FunctionDeclaration; + AST::Node *Node; + AST::PropertyName *PropertyName; + AST::PropertyNameAndValueList *PropertyNameAndValueList; + AST::SourceElement *SourceElement; + AST::SourceElements *SourceElements; + AST::Statement *Statement; + AST::StatementList *StatementList; + AST::Block *Block; + AST::VariableDeclaration *VariableDeclaration; + AST::VariableDeclarationList *VariableDeclarationList; + + AST::UiProgram *UiProgram; + AST::UiImportList *UiImportList; + AST::UiImport *UiImport; + AST::UiPublicMember *UiPublicMember; + AST::UiObjectDefinition *UiObjectDefinition; + AST::UiObjectInitializer *UiObjectInitializer; + AST::UiObjectBinding *UiObjectBinding; + AST::UiScriptBinding *UiScriptBinding; + AST::UiArrayBinding *UiArrayBinding; + AST::UiObjectMember *UiObjectMember; + AST::UiObjectMemberList *UiObjectMemberList; + AST::UiQualifiedId *UiQualifiedId; }; public: - JavaScriptParser(); - ~JavaScriptParser(); + Parser(Engine *engine); + ~Parser(); - bool parse(JavaScriptEnginePrivate *driver); + bool parse(); - JavaScript::AST::UiProgram *ast() + AST::UiProgram *ast() { return program; } QList<DiagnosticMessage> diagnosticMessages() const @@ -172,17 +157,20 @@ protected: inline Value &sym(int index) { return sym_stack [tos + index - 1]; } - inline JavaScript::AST::SourceLocation &loc(int index) + inline AST::SourceLocation &loc(int index) { return location_stack [tos + index - 1]; } + AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); + protected: + Engine *driver; int tos; int stack_size; Value *sym_stack; int *state_stack; - JavaScript::AST::SourceLocation *location_stack; + AST::SourceLocation *location_stack; - JavaScript::AST::UiProgram *program; + AST::UiProgram *program; // error recovery enum { TOKEN_BUFFER_SIZE = 3 }; @@ -190,12 +178,12 @@ protected: struct SavedToken { int token; double dval; - JavaScript::AST::SourceLocation loc; + AST::SourceLocation loc; }; double yylval; - JavaScript::AST::SourceLocation yylloc; - JavaScript::AST::SourceLocation yyprevlloc; + AST::SourceLocation yylloc; + AST::SourceLocation yyprevlloc; SavedToken token_buffer[TOKEN_BUFFER_SIZE]; SavedToken *first_token; @@ -204,10 +192,13 @@ protected: QList<DiagnosticMessage> diagnostic_messages; }; +} // end of namespace JavaScript + + -#define J_SCRIPT_REGEXPLITERAL_RULE1 52 +#define J_SCRIPT_REGEXPLITERAL_RULE1 54 -#define J_SCRIPT_REGEXPLITERAL_RULE2 53 +#define J_SCRIPT_REGEXPLITERAL_RULE2 55 QT_END_NAMESPACE diff --git a/src/declarative/qml/parser/javascriptprettypretty.cpp b/src/declarative/qml/parser/javascriptprettypretty.cpp index 6e632b7..0342b39 100644 --- a/src/declarative/qml/parser/javascriptprettypretty.cpp +++ b/src/declarative/qml/parser/javascriptprettypretty.cpp @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE namespace JavaScript { -QString numberToString(qjsreal value); +QString numberToString(double value); } using namespace JavaScript; @@ -182,7 +182,7 @@ void PrettyPretty::endVisit(AST::ThisExpression *node) bool PrettyPretty::visit(AST::IdentifierExpression *node) { - out << JavaScriptEnginePrivate::toString(node->name); + out << Engine::toString(node->name); return true; } @@ -229,7 +229,7 @@ void PrettyPretty::endVisit(AST::FalseLiteral *node) bool PrettyPretty::visit(AST::StringLiteral *node) { - QString lit = JavaScriptEnginePrivate::toString(node->value); + QString lit = Engine::toString(node->value); lit.replace(QLatin1String("\\"), QLatin1String("\\\\")); out << "\"" << lit << "\""; return false; @@ -253,7 +253,7 @@ void PrettyPretty::endVisit(AST::NumericLiteral *node) bool PrettyPretty::visit(AST::RegExpLiteral *node) { - out << "/" << JavaScriptEnginePrivate::toString(node->pattern) << "/"; + out << "/" << Engine::toString(node->pattern) << "/"; if (node->flags) out << JavaScript::Ecma::RegExp::flagsToString(node->flags); @@ -348,7 +348,7 @@ void PrettyPretty::endVisit(AST::PropertyNameAndValueList *node) bool PrettyPretty::visit(AST::IdentifierPropertyName *node) { - out << JavaScriptEnginePrivate::toString(node->id); + out << Engine::toString(node->id); return false; } @@ -359,7 +359,7 @@ void PrettyPretty::endVisit(AST::IdentifierPropertyName *node) bool PrettyPretty::visit(AST::StringLiteralPropertyName *node) { - QString lit = JavaScriptEnginePrivate::toString(node->id); + QString lit = Engine::toString(node->id); lit.replace(QLatin1String("\\"), QLatin1String("\\\\")); out << lit; return false; @@ -398,7 +398,7 @@ void PrettyPretty::endVisit(AST::ArrayMemberExpression *node) bool PrettyPretty::visit(AST::FieldMemberExpression *node) { accept(node->base); - out << "." << JavaScriptEnginePrivate::toString(node->name); + out << "." << Engine::toString(node->name); return false; } @@ -803,7 +803,7 @@ void PrettyPretty::endVisit(AST::VariableStatement *node) bool PrettyPretty::visit(AST::VariableDeclaration *node) { - out << JavaScriptEnginePrivate::toString(node->name); + out << Engine::toString(node->name); if (node->expression) { out << " = "; accept(node->expression); @@ -959,7 +959,7 @@ bool PrettyPretty::visit(AST::ContinueStatement *node) { out << "continue"; if (node->label) { - out << " " << JavaScriptEnginePrivate::toString(node->label); + out << " " << Engine::toString(node->label); } out << ";"; return false; @@ -974,7 +974,7 @@ bool PrettyPretty::visit(AST::BreakStatement *node) { out << "break"; if (node->label) { - out << " " << JavaScriptEnginePrivate::toString(node->label); + out << " " << Engine::toString(node->label); } out << ";"; return false; @@ -1095,7 +1095,7 @@ void PrettyPretty::endVisit(AST::DefaultClause *node) bool PrettyPretty::visit(AST::LabelledStatement *node) { - out << JavaScriptEnginePrivate::toString(node->label) << ": "; + out << Engine::toString(node->label) << ": "; return true; } @@ -1123,7 +1123,7 @@ bool PrettyPretty::visit(AST::TryStatement *node) out << "try "; acceptAsBlock(node->statement); if (node->catchExpression) { - out << " catch (" << JavaScriptEnginePrivate::toString(node->catchExpression->name) << ") "; + out << " catch (" << Engine::toString(node->catchExpression->name) << ") "; acceptAsBlock(node->catchExpression->statement); } if (node->finallyExpression) { @@ -1166,13 +1166,13 @@ bool PrettyPretty::visit(AST::FunctionDeclaration *node) out << "function"; if (node->name) - out << " " << JavaScriptEnginePrivate::toString(node->name); + out << " " << Engine::toString(node->name); // the arguments out << "("; for (AST::FormalParameterList *it = node->formals; it; it = it->next) { if (it->name) - out << JavaScriptEnginePrivate::toString(it->name); + out << Engine::toString(it->name); if (it->next) out << ", "; @@ -1205,13 +1205,13 @@ bool PrettyPretty::visit(AST::FunctionExpression *node) out << "function"; if (node->name) - out << " " << JavaScriptEnginePrivate::toString(node->name); + out << " " << Engine::toString(node->name); // the arguments out << "("; for (AST::FormalParameterList *it = node->formals; it; it = it->next) { if (it->name) - out << JavaScriptEnginePrivate::toString(it->name); + out << Engine::toString(it->name); if (it->next) out << ", "; diff --git a/src/declarative/qml/parser/javascriptvalue.h b/src/declarative/qml/parser/javascriptvalue.h deleted file mode 100644 index c68b817..0000000 --- a/src/declarative/qml/parser/javascriptvalue.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef JAVASCRIPTVALUE_H -#define JAVASCRIPTVALUE_H - -typedef double qjsreal; - -#endif // JAVASCRIPTVALUE_H diff --git a/src/declarative/qml/parser/parser.pri b/src/declarative/qml/parser/parser.pri index 130aeaf..b4d226a 100644 --- a/src/declarative/qml/parser/parser.pri +++ b/src/declarative/qml/parser/parser.pri @@ -8,8 +8,7 @@ HEADERS += $$PWD/javascriptast_p.h \ $$PWD/javascriptmemorypool_p.h \ $$PWD/javascriptnodepool_p.h \ $$PWD/javascriptparser_p.h \ - $$PWD/javascriptprettypretty_p.h \ - $$PWD/javascriptvalue.h \ + $$PWD/javascriptprettypretty_p.h SOURCES += $$PWD/javascriptast.cpp \ $$PWD/javascriptastvisitor.cpp \ diff --git a/src/declarative/qml/qmlbindablevalue.h b/src/declarative/qml/qmlbindablevalue.h index c4ef64a..7831177 100644 --- a/src/declarative/qml/qmlbindablevalue.h +++ b/src/declarative/qml/qmlbindablevalue.h @@ -42,10 +42,10 @@ #ifndef QMLBINDABLEVALUE_H #define QMLBINDABLEVALUE_H -#include <QObject> -#include <qfxglobal.h> -#include <qml.h> -#include <qmlpropertyvaluesource.h> +#include <QtCore/QObject> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> #include <QtDeclarative/qmlexpression.h> diff --git a/src/declarative/qml/qmlbindablevalue_p.h b/src/declarative/qml/qmlbindablevalue_p.h index d9af0ef..9973bdc 100644 --- a/src/declarative/qml/qmlbindablevalue_p.h +++ b/src/declarative/qml/qmlbindablevalue_p.h @@ -43,8 +43,8 @@ #define QMLBINDABLEVALUE_P_H #include <private/qobject_p.h> -#include <qmlbindablevalue.h> -#include <qmlmetaproperty.h> +#include <QtDeclarative/qmlbindablevalue.h> +#include <QtDeclarative/qmlmetaproperty.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/qmlboundsignal_p.h b/src/declarative/qml/qmlboundsignal_p.h index e84f0c1..2c05770 100644 --- a/src/declarative/qml/qmlboundsignal_p.h +++ b/src/declarative/qml/qmlboundsignal_p.h @@ -42,7 +42,7 @@ #ifndef QMLBOUNDSIGNAL_P_H #define QMLBOUNDSIGNAL_P_H -#include <qmlexpression.h> +#include <QtDeclarative/qmlexpression.h> #include <private/qobject_p.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/qmlcompiledcomponent_p.h b/src/declarative/qml/qmlcompiledcomponent_p.h index c5e1226..2201423 100644 --- a/src/declarative/qml/qmlcompiledcomponent_p.h +++ b/src/declarative/qml/qmlcompiledcomponent_p.h @@ -42,7 +42,7 @@ #ifndef QMLCOMPILEDCOMPONENT_P_H #define QMLCOMPILEDCOMPONENT_P_H -#include <qml.h> +#include <QtDeclarative/qml.h> #include <private/qmlinstruction_p.h> #include <private/qmlcompiler_p.h> #include <private/qmlrefcount_p.h> diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index b205efb..8990732 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -1050,8 +1050,9 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, COMPILE_EXCEPTION("Can only assign one binding to lists"); assignedBinding = true; - compileBinding(v->value.asScript(), prop, ctxt, - obj->metaObject(), v->location.start.line); + COMPILE_CHECK(compileBinding(v->value.asScript(), prop, ctxt, + obj->metaObject(), + v->location.start.line)); v->type = Value::PropertyBinding; } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); @@ -1204,8 +1205,9 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, { if (v->value.isScript()) { - compileBinding(v->value.asScript(), prop, ctxt, obj->metaObject(), - v->location.start.line); + COMPILE_CHECK(compileBinding(v->value.asScript(), prop, ctxt, + obj->metaObject(), + v->location.start.line)); v->type = Value::PropertyBinding; @@ -1214,37 +1216,24 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, QmlInstruction assign; assign.line = v->location.start.line; - bool doassign = true; if (prop->index != -1) { QString value = v->primitive(); StoreInstructionResult r = generateStoreInstruction(*output, assign, obj->metaObject()->property(prop->index), prop->index, -1, &value); if (r == Ok) { - doassign = false; } else if (r == InvalidData) { //### 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_EXCEPTION2(v, "Cannot assign value" << v->primitive() << "to property" << obj->metaObject()->property(prop->index).name()); - doassign = false; } else if (r == ReadOnly) { COMPILE_EXCEPTION2(v, "Cannot assign value" << v->primitive() << "to the read-only property" << obj->metaObject()->property(prop->index).name()); } else { - doassign = true; + COMPILE_EXCEPTION2(prop, "Cannot assign value to property" << obj->metaObject()->property(prop->index).name() << "of unknown type"); } - } - - if (doassign) { - assign.type = QmlInstruction::AssignConstant; - if (prop->isDefault) { - assign.assignConstant.property = -1; - } else { - assign.assignConstant.property = - output->indexForByteArray(prop->name); - } - assign.assignConstant.constant = - output->indexForString(v->primitive()); + } else { + COMPILE_EXCEPTION2(prop, "Cannot assign value to non-existant property" << prop->name); } output->bytecode << assign; @@ -1342,7 +1331,7 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) return true; } -void QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, +bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, int ctxt, const QMetaObject *mo, qint64 line) { QmlBasicScript bs; @@ -1355,10 +1344,12 @@ void QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, bref = output->indexForString(bind); } - QmlInstruction assign; - assign.assignBinding.context = ctxt; - assign.line = line; if (prop->index != -1) { + + QmlInstruction assign; + assign.assignBinding.context = ctxt; + assign.line = line; + if (bs.isValid()) assign.type = QmlInstruction::StoreCompiledBinding; else @@ -1368,20 +1359,18 @@ void QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, assign.assignBinding.value = bref; assign.assignBinding.category = QmlMetaProperty::Unknown; if (mo) { - //XXX we should generate an exception if the property is read-only + // ### we should generate an exception if the property is read-only QMetaProperty mp = mo->property(assign.assignBinding.property); assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); } + + output->bytecode << assign; + } else { - if (bs.isValid()) - assign.type = QmlInstruction::AssignCompiledBinding; - else - assign.type = QmlInstruction::AssignBinding; - assign.assignBinding.property = output->indexForByteArray(prop->name); - assign.assignBinding.value = bref; - assign.assignBinding.category = QmlMetaProperty::Unknown; + COMPILE_EXCEPTION2(prop, "Cannot assign binding to non-existant property" << prop->name); } - output->bytecode << assign; + + return true; } int QmlCompiler::optimizeExpressions(int start, int end, int patch) @@ -1414,9 +1403,7 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) continue; } - if (instr.type == QmlInstruction::AssignBinding || - instr.type == QmlInstruction::AssignCompiledBinding || - instr.type == QmlInstruction::StoreBinding || + if (instr.type == QmlInstruction::StoreBinding || instr.type == QmlInstruction::StoreCompiledBinding) { ++bindingsCount; } else if (instr.type == QmlInstruction::TryBeginObject || diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 64400c5..bc04cfa 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -44,8 +44,8 @@ #include <QtCore/qbytearray.h> #include <QtCore/qset.h> -#include <qml.h> -#include <qmlerror.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlerror.h> #include <private/qmlinstruction_p.h> #include <private/qmlcompositetypemanager_p.h> #include <private/qmlparser_p.h> @@ -164,7 +164,7 @@ private: int ctxt); bool compileDynamicMeta(QmlParser::Object *obj); - void compileBinding(const QString &, QmlParser::Property *prop, + bool compileBinding(const QString &, QmlParser::Property *prop, int ctxt, const QMetaObject *, qint64); int optimizeExpressions(int start, int end, int patch = -1); diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 4de47c6..254d9ba 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -42,21 +42,21 @@ #ifndef QMLCOMPONENT_P_H #define QMLCOMPONENT_P_H -#include <QString> -#include <QStringList> -#include <QList> -#include "private/qobject_p.h" -#include "private/qmlengine_p.h" -#include "private/qmlcompositetypemanager_p.h" -#include <qmlerror.h> -#include "qmlcomponent.h" +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QList> +#include <private/qobject_p.h> +#include <private/qmlengine_p.h> +#include <private/qmlcompositetypemanager_p.h> +#include <QtDeclarative/qmlerror.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qml.h> + +QT_BEGIN_NAMESPACE + class QmlComponent; class QmlEngine; class QmlCompiledComponent; -#include "qml.h" - - -QT_BEGIN_NAMESPACE class QmlComponentPrivate : public QObjectPrivate { diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h index f03b2cb..9312819 100644 --- a/src/declarative/qml/qmlcompositetypemanager_p.h +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -42,10 +42,10 @@ #ifndef QMLCOMPOSITETYPEMANAGER_P_H #define QMLCOMPOSITETYPEMANAGER_P_H -#include <qglobal.h> +#include <QtCore/qglobal.h> #include <private/qmlscriptparser_p.h> #include <private/qmlrefcount_p.h> -#include <qmlerror.h> +#include <QtDeclarative/qmlerror.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index fa36eb1..ea72ebf 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -149,7 +149,7 @@ void QmlContextPrivate::addDefaultObject(QObject *object, Priority priority) QmlContext context(engine.rootContext()); context.setContextProperty("myModel", modelData); - QmlComponent component("ListView { model=myModel }"); + QmlComponent component(&engine, "ListView { model=myModel }"); component.create(&context); \endcode @@ -176,7 +176,7 @@ void QmlContextPrivate::addDefaultObject(QObject *object, Priority priority) QmlContext context(engine.rootContext()); context.addDefaultObject(&myDataSet); - QmlComponent component("ListView { model=myModel }"); + QmlComponent component(&engine, "ListView { model=myModel }"); component.create(&context); \endcode diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index 6f1e486..4d88fc2 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -42,11 +42,11 @@ #ifndef QMLCONTEXT_P_H #define QMLCONTEXT_P_H -#include <qmlcontext.h> +#include <QtDeclarative/qmlcontext.h> #include <private/qobject_p.h> #include <private/qmldeclarativedata_p.h> -#include <qhash.h> -#include <qscriptvalue.h> +#include <QtCore/qhash.h> +#include <QtScript/qscriptvalue.h> #include <QtCore/qset.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/qmlcustomparser.cpp b/src/declarative/qml/qmlcustomparser.cpp index e864df9..a60f783 100644 --- a/src/declarative/qml/qmlcustomparser.cpp +++ b/src/declarative/qml/qmlcustomparser.cpp @@ -120,6 +120,7 @@ QmlCustomParserNodePrivate::fromObject(QmlParser::Object *root) return rootNode; } +#include <QtCore/qdebug.h> QmlCustomParserProperty QmlCustomParserNodePrivate::fromProperty(QmlParser::Property *p) { @@ -127,20 +128,23 @@ QmlCustomParserNodePrivate::fromProperty(QmlParser::Property *p) prop.d->name = p->name; prop.d->isList = (p->values.count() > 1); - for(int ii = 0; ii < p->values.count(); ++ii) { - Value *v = p->values.at(ii); + if (p->value) { + QmlCustomParserNode node = fromObject(p->value); + QList<QmlCustomParserProperty> props = node.properties(); + for (int ii = 0; ii < props.count(); ++ii) + prop.d->values << QVariant::fromValue(props.at(ii)); + } else { + for(int ii = 0; ii < p->values.count(); ++ii) { + Value *v = p->values.at(ii); + + if(v->object) { + QmlCustomParserNode node = fromObject(v->object); + prop.d->values << QVariant::fromValue(node); + } else { + prop.d->values << QVariant::fromValue(v->value); + } - // We skip fetched properties for now - if(v->object && v->object->type == -1) - continue; - - if(v->object) { - QmlCustomParserNode node = fromObject(v->object); - prop.d->values << QVariant::fromValue(node); - } else { - prop.d->values << QVariant::fromValue(v->primitive()); } - } return prop; diff --git a/src/declarative/qml/qmlcustomparser_p.h b/src/declarative/qml/qmlcustomparser_p.h index e4e6089..fd780d6 100644 --- a/src/declarative/qml/qmlcustomparser_p.h +++ b/src/declarative/qml/qmlcustomparser_p.h @@ -65,6 +65,8 @@ public: QByteArray name() const; bool isList() const; + // Will be one of QmlParser::Variant, QmlCustomParserProperty or + // QmlCustomParserNode QList<QVariant> assignedValues() const; private: diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index 673520e..9871fcb 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -477,12 +477,7 @@ QmlDomObjectPrivate::properties(QmlParser::Property *property) const iter->second.prepend(name); } else { - - // We don't display "id" sets as a property in the dom - if (property->values.count() != 1 || - property->values.at(0)->type != QmlParser::Value::Id) - rv << qMakePair(property, property->name); - + rv << qMakePair(property, property->name); } return rv; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 227aeb0..c0ea463 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -193,6 +193,7 @@ void QmlEnginePrivate::clear(SimpleList<QmlParserStatus> &pss) void QmlEnginePrivate::init() { + scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); rootContext = new QmlContext(q); @@ -424,8 +425,8 @@ bool QmlEnginePrivate::loadCache(QmlBasicScriptNodeCache &cache, const QString & \code QmlEngine engine; - QmlComponent component("Text { text: \"Hello world!\" }"); - QFxItem *item = qobject_cast<QFxItem *>(component.create(&engine)); + QmlComponent component(&engine, "Text { text: \"Hello world!\" }"); + QFxItem *item = qobject_cast<QFxItem *>(component.create()); //add item to view, etc ... @@ -614,6 +615,35 @@ QUrl QmlEngine::componentUrl(const QUrl& src, const QUrl& baseUrl) const } /*! + Returns the list of base urls the engine browses to find sub-components. + + The search path consists of the base of the \a url, and, in the case of local files, + the directories imported using the "import" statement in \a qml. + */ +QList<QUrl> QmlEngine::componentSearchPath(const QByteArray &qml, const QUrl &url) const +{ + QList<QUrl> searchPath; + + searchPath << url.resolved(QUrl(QLatin1String("."))); + + if (QFileInfo(url.toLocalFile()).exists()) { + QmlScriptParser parser; + if (parser.parse(qml, url)) { + for (int i = 0; i < parser.imports().size(); ++i) { + QUrl importUrl = QUrl(parser.imports().at(i).uri); + if (importUrl.isRelative()) { + searchPath << url.resolved(importUrl); + } else { + searchPath << importUrl; + } + } + } + } + + return searchPath; +} + +/*! Sets the common QNetworkAccessManager, \a network, used by all QML elements instantiated by this engine. @@ -781,17 +811,17 @@ QmlEngine *QmlEngine::activeEngine() QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), id(0), log(0) +: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), id(0), log(0) +: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr, bool ssecompile) -: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), id(0), log(0) +: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { if (ssecompile) { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -996,7 +1026,7 @@ QVariant QmlExpression::value() for (int i = context()->d_func()->scopeChain.size() - 1; i > -1; --i) { scriptEngine->currentContext()->pushScope(context()->d_func()->scopeChain.at(i)); } - QScriptValue svalue = scriptEngine->evaluate(expression()); + QScriptValue svalue = scriptEngine->evaluate(expression(), d->fileName, d->line); if (scriptEngine->hasUncaughtException()) { if (scriptEngine->uncaughtException().isError()){ QScriptValue exception = scriptEngine->uncaughtException(); @@ -1027,9 +1057,7 @@ QVariant QmlExpression::value() } rv = QVariant::fromValue(list); } - } /*else if (svalue.isVariant()) { - rv = svalue.toVariant(); - }*/ else if (svalue.isObject()) { + } else if (svalue.isObject()) { QScriptValue objValue = svalue.data(); if (objValue.isValid()) rv = objValue.toVariant(); @@ -1153,6 +1181,16 @@ void QmlExpression::setTrackChange(bool trackChange) } /*! + Set the location of this expression to \a line of \a fileName. This information + is used by the script engine. +*/ +void QmlExpression::setSourceLocation(const QString &fileName, int line) +{ + d->fileName = fileName; + d->line = line; +} + +/*! Returns the expression's scope object, if provided, otherwise 0. In addition to data provided by the expression's QmlContext, the scope diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h index fde84d4..9382389 100644 --- a/src/declarative/qml/qmlengine.h +++ b/src/declarative/qml/qmlengine.h @@ -78,6 +78,8 @@ public: QMap<QString,QString> nameSpacePaths() const; QUrl componentUrl(const QUrl& src, const QUrl& baseUrl) const; + QList<QUrl> componentSearchPath(const QByteArray &qml, const QUrl &url) const; + void setNetworkAccessManager(QNetworkAccessManager *); QNetworkAccessManager *networkAccessManager() const; diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 7578fdf..0dc4736 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -42,9 +42,9 @@ #ifndef QMLENGINE_P_H #define QMLENGINE_P_H -#include <QScriptClass> -#include <QScriptValue> -#include <QScriptString> +#include <QtScript/QScriptClass> +#include <QtScript/QScriptValue> +#include <QtScript/QScriptString> #include <QtCore/qstring.h> #include <QtCore/qlist.h> #include <QtCore/qpair.h> @@ -52,11 +52,11 @@ #include <private/qobject_p.h> #include <private/qmlclassfactory_p.h> #include <private/qmlcompositetypemanager_p.h> -#include <qml.h> -#include <qmlbasicscript.h> -#include <qmlcontext.h> -#include <qmlengine.h> -#include <qmlexpression.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlbasicscript.h> +#include <QtDeclarative/qmlcontext.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlexpression.h> #include <QtScript/qscriptengine.h> QT_BEGIN_NAMESPACE @@ -277,6 +277,8 @@ public: BindExpressionProxy *proxy; QObject *me; bool trackChange; + QString fileName; + int line; quint32 id; diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index 2c6b1ad..ea3b093 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -78,6 +78,8 @@ public: bool trackChange() const; void setTrackChange(bool); + void setSourceLocation(const QString &fileName, int line); + QObject *scopeObject() const; quint32 id() const; diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 6b49359..923d36f 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -124,18 +124,9 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::StoreSignal: qWarning() << idx << "\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value); break; - case QmlInstruction::AssignConstant: - qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CONSTANT\t" << instr->assignConstant.property << "\t" << instr->assignConstant.constant << "\t\t" << datas.at(instr->assignConstant.property) << primitives.at(instr->assignConstant.constant); - break; case QmlInstruction::AssignSignalObject: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); break; - case QmlInstruction::AssignBinding: - qWarning() << idx << "\t" << line << "\t" << "ASSIGN_BINDING\t\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context << datas.at(instr->assignBinding.property) << primitives.at(instr->assignBinding.value); - break; - case QmlInstruction::AssignCompiledBinding: - qWarning() << idx << "\t" << line << "\t" << "ASSIGN_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context << datas.at(instr->assignBinding.property); - break; case QmlInstruction::AssignValueSource: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t\t\t" << datas.at(instr->assignValueSource.property); break; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index f06f0e6..a21ccee 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -42,7 +42,7 @@ #ifndef QMLINSTRUCTION_P_H #define QMLINSTRUCTION_P_H -#include <qfxglobal.h> +#include <QtDeclarative/qfxglobal.h> QT_BEGIN_NAMESPACE @@ -110,14 +110,9 @@ public: // // Unresolved single assignment // - // AssignConstant - Store a value in a property. Will resolve into - // a Store* instruction. - AssignConstant, /* assignConstant */ AssignSignalObject, /* assignSignalObject */ AssignCustomType, /* assignCustomType */ - AssignBinding, /* assignBinding */ - AssignCompiledBinding, /* assignBinding */ AssignValueSource, /* assignValueSource */ StoreBinding, /* assignBinding */ StoreCompiledBinding, /* assignBinding */ @@ -187,10 +182,6 @@ public: } setId; struct { int property; - int constant; - } assignConstant; - struct { - int property; int castValue; } assignObject; struct { diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 59d6b38..e3e9ff5 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -100,9 +100,16 @@ QmlMetaProperty::~QmlMetaProperty() delete d; d = 0; } -// ### not thread safe -static QHash<const QMetaObject *, QMetaPropertyEx> qmlCacheDefProp; +struct CachedPropertyData { + CachedPropertyData(const QString &n, int pt, int ci) + : name(n), propType(pt), coreIdx(ci) {} + QString name; + int propType; + int coreIdx; +}; +// ### not thread safe +static QHash<const QMetaObject *, CachedPropertyData> qmlCacheDefProp; /*! Creates a QmlMetaProperty for the default property of \a obj. If there is no @@ -131,23 +138,22 @@ void QmlMetaProperty::initDefault(QObject *obj) return; d->object = obj; - QHash<const QMetaObject *, QMetaPropertyEx>::ConstIterator iter = + QHash<const QMetaObject *, CachedPropertyData>::ConstIterator iter = qmlCacheDefProp.find(obj->metaObject()); if (iter != qmlCacheDefProp.end()) { - d->prop = *iter; - d->propType = iter->propertyType; - d->coreIdx = iter->propertyType; + d->name = iter->name; + d->propType = iter->propType; + d->coreIdx = iter->coreIdx; } else { QMetaPropertyEx p(QmlMetaType::defaultProperty(obj)); - d->prop = p; + d->name = QLatin1String(p.name()); d->propType = p.propertyType; - d->coreIdx = d->prop.propertyIndex(); + d->coreIdx = p.propertyIndex(); if (!QObjectPrivate::get(obj)->metaObject) - qmlCacheDefProp.insert(obj->metaObject(), d->prop); + qmlCacheDefProp.insert(obj->metaObject(), CachedPropertyData(d->name, d->propType, d->coreIdx)); } - if (d->prop.name() != 0) { + if (!d->name.isEmpty()) { d->type = Property | Default; - d->name = QLatin1String(d->prop.name()); } } @@ -166,15 +172,14 @@ QmlMetaProperty::QmlMetaProperty(QObject *obj, int idx, PropertyCategory cat, Qm d->type = Property; d->category = cat; QMetaPropertyEx p(obj->metaObject()->property(idx)); - d->prop = p; d->propType = p.propertyType; d->coreIdx = idx; - if (d->prop.name() != 0) - d->name = QLatin1String(d->prop.name()); + if (p.name() != 0) + d->name = QLatin1String(p.name()); } // ### Not thread safe!!!! -static QHash<const QMetaObject *, QHash<QString, QMetaPropertyEx> > qmlCacheProps; +static QHash<const QMetaObject *, QHash<QString, CachedPropertyData> > qmlCacheProps; /*! Creates a QmlMetaProperty for the property \a name of \a obj. */ @@ -225,21 +230,21 @@ void QmlMetaProperty::initProperty(QObject *obj, const QString &name) } // Property - QHash<QString, QMetaPropertyEx> &props = qmlCacheProps[obj->metaObject()]; - QHash<QString, QMetaPropertyEx>::ConstIterator iter = props.find(name); + QHash<QString, CachedPropertyData> &props = qmlCacheProps[obj->metaObject()]; + QHash<QString, CachedPropertyData>::ConstIterator iter = props.find(name); if (iter != props.end()) { - d->prop = *iter; - d->propType = iter->propertyType; - d->coreIdx = iter->propertyIndex(); + d->name = iter->name; + d->propType = iter->propType; + d->coreIdx = iter->coreIdx; } else { QMetaPropertyEx p = QmlMetaType::property(obj, name.toLatin1().constData()); - d->prop = p; + d->name = QLatin1String(p.name()); d->propType = p.propertyType; d->coreIdx = p.propertyIndex(); if (!QObjectPrivate::get(obj)->metaObject) - props.insert(name, p); + props.insert(name, CachedPropertyData(d->name, d->propType, d->coreIdx)); } - if (d->prop.name() != 0) + if (!d->name.isEmpty()) d->type = Property; if (d->type == Invalid) { @@ -352,8 +357,8 @@ QmlMetaProperty::propertyCategory(const QMetaProperty &prop) */ const char *QmlMetaProperty::propertyTypeName() const { - if (d->prop.name()) { - return d->prop.typeName(); + if (!d->name.isEmpty()) { + return d->object->metaObject()->property(d->coreIdx).typeName(); } else { return 0; } @@ -365,7 +370,7 @@ const char *QmlMetaProperty::propertyTypeName() const */ bool QmlMetaProperty::operator==(const QmlMetaProperty &other) const { - return d->prop.name() == other.d->prop.name() && + return d->name == other.d->name && d->signal.signature() == other.d->signal.signature() && d->type == other.d->type && d->object == other.d->object; @@ -384,7 +389,7 @@ int QmlMetaPropertyPrivate::propertyType() const { int rv = QVariant::Invalid; - if (prop.name()) { + if (!name.isEmpty()) { if (propType == (int)QVariant::LastType) rv = qMetaTypeId<QVariant>(); else @@ -434,7 +439,6 @@ QObject *QmlMetaProperty::object() const QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other) { d->name = other.d->name; - d->prop = other.d->prop; d->propType = other.d->propType; d->type = other.d->type; d->signal = other.d->signal; @@ -452,8 +456,8 @@ bool QmlMetaProperty::isWritable() const { if (propertyCategory() == List || propertyCategory() == QmlList) return true; - else if (d->prop.name() != 0) - return d->prop.isWritable(); + else if (!d->name.isEmpty()) + return d->object->metaObject()->property(d->coreIdx).isWritable(); else if (type() & SignalProperty) return true; else @@ -465,8 +469,8 @@ bool QmlMetaProperty::isWritable() const */ bool QmlMetaProperty::isDesignable() const { - if (d->prop.name() != 0) - return d->prop.isDesignable(); + if (!d->name.isEmpty()) + return d->object->metaObject()->property(d->coreIdx).isDesignable(); else return false; } @@ -510,9 +514,9 @@ QString QmlMetaProperty::name() const Returns the \l{QMetaProperty} {Qt property} associated with this QML property. */ -const QMetaProperty &QmlMetaProperty::property() const +QMetaProperty QmlMetaProperty::property() const { - return d->prop; + return d->object->metaObject()->property(d->coreIdx); } /*! @@ -602,7 +606,7 @@ QVariant QmlMetaProperty::read() const if (type() & Attached) return QVariant::fromValue(d->attachedObject()); else - return d->prop.read(object()); + return d->object->metaObject()->property(d->coreIdx).read(object()); } return QVariant(); } @@ -636,6 +640,7 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value) { + QMetaProperty prop = object->metaObject()->property(coreIdx); if (prop.isEnumType()) { QVariant v = value; if (value.type() == QVariant::Double) { //enum values come through the script engine as doubles @@ -805,13 +810,14 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value) */ void QmlMetaProperty::write(const QVariant &value) const { + QMetaProperty prop = d->object->metaObject()->property(d->coreIdx); if (type() & SignalProperty) { d->writeSignalProperty(value); - } else if (d->prop.name()) { + } else if (prop.name()) { - if (d->prop.isEnumType()) { + if (prop.isEnumType()) { QVariant v = value; if (value.type() == QVariant::Double) { //enum values come through the script engine as doubles double integral; @@ -819,7 +825,7 @@ void QmlMetaProperty::write(const QVariant &value) const if (qFuzzyCompare(fractional, (double)0.0)) v.convert(QVariant::Int); } - d->prop.write(object(), v); + prop.write(object(), v); } else { if (!value.isValid()) return; @@ -836,13 +842,13 @@ void QmlMetaProperty::write(const QVariant &value) const } else if (qMetaTypeId<QVariant>() == t) { - d->prop.write(object(), value); + prop.write(object(), value); } else if (propertyCategory() == Object) { QObject *o = QmlMetaType::toQObject(value); if (o) - d->prop.write(object(), QmlMetaType::fromObject(o, propertyType())); + prop.write(object(), QmlMetaType::fromObject(o, propertyType())); } else if (propertyCategory() == List) { @@ -850,7 +856,7 @@ void QmlMetaProperty::write(const QVariant &value) const if (value.userType() == qMetaTypeId<QList<QObject *> >()) { const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value); - QVariant listVar = d->prop.read(object()); + QVariant listVar = prop.read(object()); QmlMetaType::clear(listVar); for (int ii = 0; ii < list.count(); ++ii) { QVariant v = QmlMetaType::fromObject(list.at(ii), listType); @@ -859,14 +865,14 @@ void QmlMetaProperty::write(const QVariant &value) const } else if (vt == listType || value.userType() == listType) { - QVariant listVar = d->prop.read(object()); + QVariant listVar = prop.read(object()); if (!QmlMetaType::append(listVar, value)) { qWarning() << "QmlMetaProperty: Unable to assign object to list"; } } } else if (propertyCategory() == QmlList) { // XXX - optimize! - QVariant list = d->prop.read(object()); + QVariant list = prop.read(object()); QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)list.constData(); @@ -969,7 +975,7 @@ void QmlMetaProperty::write(const QVariant &value) const default: break; } - d->prop.write(object(), value); + prop.write(object(), value); } } @@ -982,7 +988,7 @@ void QmlMetaProperty::write(const QVariant &value) const bool QmlMetaProperty::hasChangedNotifier() const { if (type() & Property && !(type() & Attached)) { - return d->prop.hasNotifySignal(); + return d->object->metaObject()->property(d->coreIdx).hasNotifySignal(); } return false; } @@ -1012,8 +1018,9 @@ bool QmlMetaProperty::connectNotifier(QObject *dest, int method) const if (!(type() & Property) || type() & Attached) return false; - if (d->prop.hasNotifySignal()) { - return QMetaObject::connect(d->object, d->prop.notifySignalIndex(), dest, method, Qt::DirectConnection); + QMetaProperty prop = d->object->metaObject()->property(d->coreIdx); + if (prop.hasNotifySignal()) { + return QMetaObject::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection); } else { return false; } @@ -1032,8 +1039,9 @@ bool QmlMetaProperty::connectNotifier(QObject *dest, const char *slot) const if (!(type() & Property) || type() & Attached) return false; - if (d->prop.hasNotifySignal()) { - QByteArray signal(QByteArray("2") + d->prop.notifySignal().signature()); + QMetaProperty prop = d->object->metaObject()->property(d->coreIdx); + if (prop.hasNotifySignal()) { + QByteArray signal(QByteArray("2") + prop.notifySignal().signature()); return QObject::connect(d->object, signal.constData(), dest, slot); } else { return false; @@ -1098,7 +1106,7 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj) d->attachedFunc = id; } else if (d->type & Property) { QMetaPropertyEx p(obj->metaObject()->property(id)); - d->prop = p; + d->name = QLatin1String(p.name()); d->propType = p.propertyType; d->coreIdx = id; } else if (d->type & SignalProperty || d->type & Signal) { diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h index 68b06e5..9daef59 100644 --- a/src/declarative/qml/qmlmetaproperty.h +++ b/src/declarative/qml/qmlmetaproperty.h @@ -43,7 +43,7 @@ #define QMLMETAPROPERTY_H #include <QtDeclarative/qfxglobal.h> -#include <QMetaProperty> +#include <QtCore/QMetaProperty> QT_BEGIN_HEADER @@ -121,7 +121,7 @@ public: bool operator==(const QmlMetaProperty &) const; - const QMetaProperty &property() const; + QMetaProperty property() const; QmlBindableValue *binding(); static int findSignal(const QObject *, const char *); diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 1ea38e9..738bfec 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -54,7 +54,7 @@ public: QmlMetaPropertyPrivate(const QmlMetaPropertyPrivate &other) : name(other.name), signal(other.signal), context(other.context), coreIdx(other.coreIdx), type(other.type), attachedFunc(other.attachedFunc), - object(other.object), prop(other.prop), propType(other.propType), + object(other.object), propType(other.propType), category(other.category) {} QString name; @@ -64,7 +64,6 @@ public: uint type; int attachedFunc; QObject *object; - QMetaProperty prop; int propType; mutable QmlMetaProperty::PropertyCategory category; diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp index 7825e5c..2e490a4 100644 --- a/src/declarative/qml/qmlmetatype.cpp +++ b/src/declarative/qml/qmlmetatype.cpp @@ -95,8 +95,8 @@ struct QmlMetaTypeData QBitArray qmllists; QBitArray lists; }; -Q_GLOBAL_STATIC(QmlMetaTypeData, metaTypeData); -Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock); +Q_GLOBAL_STATIC(QmlMetaTypeData, metaTypeData) +Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock) class QmlTypePrivate { @@ -388,7 +388,8 @@ int QmlMetaType::registerInterface(const QmlPrivate::MetaTypeIds &id, data->idToType.insert(type->typeId(), type); data->idToType.insert(type->qListTypeId(), type); data->idToType.insert(type->qmlListTypeId(), type); - data->nameToType.insert(type->qmlTypeName(), type); + if (!type->qmlTypeName().isEmpty()) + data->nameToType.insert(type->qmlTypeName(), type); if (data->interfaces.size() < id.typeId) data->interfaces.resize(id.typeId + 16); @@ -864,6 +865,14 @@ QmlType *QmlMetaType::qmlType(const QByteArray &name) return data->nameToType.value(name); } +QmlType *QmlMetaType::qmlType(const QMetaObject *metaObject) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + return data->metaObjectToType.value(metaObject); +} + QList<QByteArray> QmlMetaType::qmlTypeNames() { QReadLocker lock(metaTypeDataLock()); diff --git a/src/declarative/qml/qmlmetatype.h b/src/declarative/qml/qmlmetatype.h index 7ab01a5..cc3887c 100644 --- a/src/declarative/qml/qmlmetatype.h +++ b/src/declarative/qml/qmlmetatype.h @@ -64,9 +64,11 @@ public: static bool copy(int type, void *data, const void *copy = 0); - static QmlType *qmlType(const QByteArray &); static QList<QByteArray> qmlTypeNames(); + static QmlType *qmlType(const QByteArray &); + static QmlType *qmlType(const QMetaObject *); + static QMetaProperty defaultProperty(const QMetaObject *); static QMetaProperty defaultProperty(QObject *); static QMetaMethod defaultMethod(const QMetaObject *); @@ -108,7 +110,7 @@ public: }; class QmlTypePrivate; -class QmlType +class Q_DECLARATIVE_EXPORT QmlType { public: QByteArray typeName() const; diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index d4f279b..add5773 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -42,10 +42,10 @@ #ifndef QMLPARSER_P_H #define QMLPARSER_P_H -#include <QByteArray> -#include <QList> +#include <QtCore/QByteArray> +#include <QtCore/QList> #include <QtCore/qstring.h> -#include <qml.h> +#include <QtDeclarative/qml.h> #include <private/qmlrefcount_p.h> #include <private/qobject_p.h> @@ -272,10 +272,10 @@ namespace QmlParser void dump(int = 0) const; }; } - -#endif // QMLPARSER_P_H - +Q_DECLARE_METATYPE(QmlParser::Variant); QT_END_NAMESPACE QT_END_HEADER + +#endif // QMLPARSER_P_H diff --git a/src/declarative/qml/qmlpropertyvaluesource.h b/src/declarative/qml/qmlpropertyvaluesource.h index 6ef2e38..736b25f 100644 --- a/src/declarative/qml/qmlpropertyvaluesource.h +++ b/src/declarative/qml/qmlpropertyvaluesource.h @@ -42,9 +42,9 @@ #ifndef QMLPROPERTYVALUESOURCE_H #define QMLPROPERTYVALUESOURCE_H -#include <qfxglobal.h> -#include <qml.h> -#include <QObject> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> +#include <QtCore/QObject> QT_BEGIN_HEADER diff --git a/src/declarative/qml/qmlproxymetaobject_p.h b/src/declarative/qml/qmlproxymetaobject_p.h index 594e7a3..0ffa365 100644 --- a/src/declarative/qml/qmlproxymetaobject_p.h +++ b/src/declarative/qml/qmlproxymetaobject_p.h @@ -42,11 +42,11 @@ #ifndef QMLPROXYMETAOBJECT_P_H #define QMLPROXYMETAOBJECT_P_H -#include <QMetaObject> +#include <QtCore/QMetaObject> +#include <QtCore/QObject> #include <private/qmetaobjectbuilder_p.h> #include <private/qobject_p.h> -#include <QObject> -#include <qml.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/qml/qmlrefcount_p.h b/src/declarative/qml/qmlrefcount_p.h index 90b50a8..1355c86 100644 --- a/src/declarative/qml/qmlrefcount_p.h +++ b/src/declarative/qml/qmlrefcount_p.h @@ -42,7 +42,7 @@ #ifndef QMLREFCOUNT_P_H #define QMLREFCOUNT_P_H -#include <qglobal.h> +#include <QtCore/qglobal.h> QT_BEGIN_HEADER diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index ff19d25..ead7ee5 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -62,18 +62,16 @@ public: void operator()(const QString &code, AST::Node *node); protected: - Object *defineObjectBinding(int line, - AST::UiQualifiedId *propertyName, - const QString &objectType, - AST::SourceLocation typeLocation, - LocationSpan location, - AST::UiObjectInitializer *initializer = 0); - Object *defineObjectBinding_helper(int line, - AST::UiQualifiedId *propertyName, - const QString &objectType, - AST::SourceLocation typeLocation, - LocationSpan location, - AST::UiObjectInitializer *initializer = 0); + Object *defineObjectBinding(AST::UiQualifiedId *propertyName, + AST::UiQualifiedId *objectTypeName, + LocationSpan location, + AST::UiObjectInitializer *initializer = 0); + + Object *defineObjectBinding_helper(AST::UiQualifiedId *propertyName, + const QString &objectType, + AST::SourceLocation typeLocation, + LocationSpan location, + AST::UiObjectInitializer *initializer = 0); QmlParser::Variant getVariant(AST::ExpressionNode *expr); @@ -199,8 +197,7 @@ QString ProcessAST::asString(AST::UiQualifiedId *node) const } Object * -ProcessAST::defineObjectBinding_helper(int line, - AST::UiQualifiedId *propertyName, +ProcessAST::defineObjectBinding_helper(AST::UiQualifiedId *propertyName, const QString &objectType, AST::SourceLocation typeLocation, LocationSpan location, @@ -283,16 +280,17 @@ ProcessAST::defineObjectBinding_helper(int line, } } -Object *ProcessAST::defineObjectBinding(int line, - AST::UiQualifiedId *qualifiedId, - const QString &objectType, - AST::SourceLocation typeLocation, - LocationSpan location, - AST::UiObjectInitializer *initializer) +Object *ProcessAST::defineObjectBinding(AST::UiQualifiedId *qualifiedId, + AST::UiQualifiedId *objectTypeName, + LocationSpan location, + AST::UiObjectInitializer *initializer) { + const QString objectType = asString(objectTypeName); + const AST::SourceLocation typeLocation = objectTypeName->identifierToken; + if (objectType == QLatin1String("Connection")) { - Object *obj = defineObjectBinding_helper(line, 0, objectType, typeLocation, location); + Object *obj = defineObjectBinding_helper(/*propertyName = */0, objectType, typeLocation, location); _stateStack.pushObject(obj); @@ -331,7 +329,7 @@ Object *ProcessAST::defineObjectBinding(int line, return obj; } - return defineObjectBinding_helper(line, qualifiedId, objectType, typeLocation, location, initializer); + return defineObjectBinding_helper(qualifiedId, objectType, typeLocation, location, initializer); } LocationSpan ProcessAST::location(AST::UiQualifiedId *id) @@ -446,16 +444,14 @@ bool ProcessAST::visit(AST::UiPublicMember *node) } -// UiObjectMember: T_IDENTIFIER UiObjectInitializer ; +// UiObjectMember: UiQualifiedId UiObjectInitializer ; bool ProcessAST::visit(AST::UiObjectDefinition *node) { LocationSpan l = location(node->firstSourceLocation(), - node->lastSourceLocation());; + node->lastSourceLocation()); - defineObjectBinding(node->identifierToken.startLine, - 0, - node->name->asString(), - node->identifierToken, + defineObjectBinding(/*propertyName = */ 0, + node->qualifiedTypeNameId, l, node->initializer); @@ -463,16 +459,14 @@ bool ProcessAST::visit(AST::UiObjectDefinition *node) } -// UiObjectMember: UiQualifiedId T_COLON T_IDENTIFIER UiObjectInitializer ; +// UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ; bool ProcessAST::visit(AST::UiObjectBinding *node) { - LocationSpan l; - l = location(node->identifierToken, node->initializer->rbraceToken); + LocationSpan l = location(node->qualifiedTypeNameId->identifierToken, + node->initializer->rbraceToken); - defineObjectBinding(node->identifierToken.startLine, - node->qualifiedId, - node->name->asString(), - node->identifierToken, + defineObjectBinding(node->qualifiedId, + node->qualifiedTypeNameId, l, node->initializer); @@ -632,20 +626,19 @@ bool QmlScriptParser::parse(const QByteArray &data, const QUrl &url) QTextStream stream(data, QIODevice::ReadOnly); const QString code = stream.readAll(); - JavaScriptParser parser; - JavaScriptEnginePrivate driver; + Engine engine; - NodePool nodePool(fileName, &driver); - driver.setNodePool(&nodePool); + NodePool nodePool(fileName, &engine); - Lexer lexer(&driver); + Lexer lexer(&engine); lexer.setCode(code, /*line = */ 1); - driver.setLexer(&lexer); - if (! parser.parse(&driver) || !_errors.isEmpty()) { + Parser parser(&engine); + + if (! parser.parse() || !_errors.isEmpty()) { // Extract errors from the parser - foreach (const JavaScriptParser::DiagnosticMessage &m, parser.diagnosticMessages()) { + foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { if (m.isWarning()) continue; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 51534e7..1552cb5 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -87,10 +87,7 @@ Q_DECLARE_PERFORMANCE_LOG(QFxCompiler) { Q_DECLARE_PERFORMANCE_METRIC(InstrStoreObject); Q_DECLARE_PERFORMANCE_METRIC(InstrStoreSignal); Q_DECLARE_PERFORMANCE_METRIC(InstrStoreObjectQmlList); - Q_DECLARE_PERFORMANCE_METRIC(InstrAssignConstant); Q_DECLARE_PERFORMANCE_METRIC(InstrAssignSignalObject); - Q_DECLARE_PERFORMANCE_METRIC(InstrAssignBinding); - Q_DECLARE_PERFORMANCE_METRIC(InstrAssignCompiledBinding); Q_DECLARE_PERFORMANCE_METRIC(InstrAssignValueSource); Q_DECLARE_PERFORMANCE_METRIC(InstrStoreBinding); Q_DECLARE_PERFORMANCE_METRIC(InstrStoreCompiledBinding); @@ -136,10 +133,7 @@ Q_DEFINE_PERFORMANCE_LOG(QFxCompiler, "QFxCompiler") { Q_DEFINE_PERFORMANCE_METRIC(InstrStoreObject, "StoreObject"); Q_DEFINE_PERFORMANCE_METRIC(InstrStoreSignal, "StoreSignal"); Q_DEFINE_PERFORMANCE_METRIC(InstrStoreObjectQmlList, "StoreObjectQmlList"); - Q_DEFINE_PERFORMANCE_METRIC(InstrAssignConstant, "AssignConstant"); Q_DEFINE_PERFORMANCE_METRIC(InstrAssignSignalObject, "AssignSignalObject"); - Q_DEFINE_PERFORMANCE_METRIC(InstrAssignBinding, "AssignBinding"); - Q_DEFINE_PERFORMANCE_METRIC(InstrAssignCompiledBinding, "AssignCompiledBinding"); Q_DEFINE_PERFORMANCE_METRIC(InstrAssignValueSource, "AssignValueSource"); Q_DEFINE_PERFORMANCE_METRIC(InstrStoreBinding, "StoreBinding"); Q_DEFINE_PERFORMANCE_METRIC(InstrStoreCompiledBinding, "StoreCompiledBinding"); @@ -409,64 +403,6 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in } break; - case QmlInstruction::AssignConstant: - { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxCompilerTimer<QFxCompiler::InstrAssignConstant> cc; -#endif - // Fixup instruction - QObject *target = stack.top(); - int propIdx = instr.assignConstant.property; - int idx = instr.assignConstant.constant; - QByteArray pr; - if (propIdx == -1) { - pr = QmlMetaType::defaultProperty(target).name(); - if (pr.isEmpty()) - VME_EXCEPTION("Cannot resolve defalt property on type" << target->metaObject()->className()); - } else { - pr = datas.at(propIdx); - } - - int coreIdx = qIndexOfProperty(target, pr); - - if (coreIdx != -1) { - QMetaProperty prop = - target->metaObject()->property(coreIdx); - bool replace = !prop.isDynamic(); - - QmlInstruction *writeInstr = 0; - QmlInstruction dummy; - if (replace) { - writeInstr = &instr; - } else { - writeInstr = &dummy; - dummy = instr; - } - - QmlCompiler::StoreInstructionResult r = QmlCompiler::generateStoreInstruction(*comp, *writeInstr, prop, - coreIdx, idx, &primitives.at(idx)); - if (r != QmlCompiler::Ok) { - if (prop.isEnumType()){ - VME_EXCEPTION(primitives.at(idx) << "is not a valid enumeration value"); - } else if (r == QmlCompiler::UnknownType) { - VME_EXCEPTION("Property" << prop.name() << "is of an unknown type"); - } else if (r == QmlCompiler::InvalidData) { - VME_EXCEPTION("Cannot assign value" << primitives.at(idx) << "to property" << prop.name()); - } else if (r == QmlCompiler::ReadOnly) { - VME_EXCEPTION("Cannot assign value" << primitives.at(idx) << "to read-only property" << prop.name()); - } else { - VME_EXCEPTION("Invalid property assignment for property" << prop.name()); - } - } else { - runStoreInstruction(stack, *writeInstr, comp); - } - - } else { - VME_EXCEPTION("Unknown property" << pr); - } - } - break; - case QmlInstruction::TryBeginObject: { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -530,31 +466,6 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in } break; - case QmlInstruction::AssignCompiledBinding: - case QmlInstruction::AssignBinding: - { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxCompilerTimer<QFxCompiler::InstrAssignBinding> cc; -#endif - QObject *target = stack.top(); - const QByteArray &pr = datas.at(instr.fetch.property); - int idx = qIndexOfProperty(target, pr); - - // XXX - need to check if the type is QmlBindableValue* - if (idx == -1) { - VME_EXCEPTION("Unknown property" << pr); - } else { - if (QmlInstruction::AssignCompiledBinding == instr.type) - instr.type = QmlInstruction::StoreCompiledBinding; - else - instr.type = QmlInstruction::StoreBinding; - instr.assignBinding.property = idx; - instr.assignBinding.category = QmlMetaProperty::Unknown; - } - ii--; - } - break; - case QmlInstruction::AssignValueSource: { QObject *target = stack.at(stack.count() - 2); @@ -613,6 +524,7 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in QFx_setParent_noEvent(bind, target); bind->setTarget(mp); + bind->setSourceLocation(comp->url.toString(), instr.line); } break; @@ -638,6 +550,7 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in QFx_setParent_noEvent(bind, target); bind->setTarget(mp); + bind->setSourceLocation(comp->url.toString(), instr.line); } break; diff --git a/src/declarative/qml/qmlvme_p.h b/src/declarative/qml/qmlvme_p.h index f7e13d6..4e5c6c1 100644 --- a/src/declarative/qml/qmlvme_p.h +++ b/src/declarative/qml/qmlvme_p.h @@ -42,12 +42,12 @@ #ifndef QMLVME_P_H #define QMLVME_P_H -#include <QString> -#include <QStack> -#include <qmlerror.h> -class QObject; +#include <QtCore/QString> +#include <QtCore/QStack> +#include <QtDeclarative/qmlerror.h> QT_BEGIN_NAMESPACE +class QObject; class QmlInstruction; class QmlCompiledComponent; class QmlCompiledData; diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index d8ed242..6f1e31b 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -42,9 +42,9 @@ #ifndef QMLVMEMETAOBJECT_P_H #define QMLVMEMETAOBJECT_P_H -#include <qml.h> -#include <QMetaObject> -#include <QBitArray> +#include <QtDeclarative/qml.h> +#include <QtCore/QMetaObject> +#include <QtCore/QBitArray> #include <private/qobject_p.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/script/lexer.h b/src/declarative/qml/script/lexer.h index 7781ee8..9de4afd 100644 --- a/src/declarative/qml/script/lexer.h +++ b/src/declarative/qml/script/lexer.h @@ -11,7 +11,7 @@ #ifndef LEXER_H #define LEXER_H -#include <QList> +#include <QtCore/QList> #include "tokens.h" diff --git a/src/declarative/qml/script/qmlbasicscript.h b/src/declarative/qml/script/qmlbasicscript.h index d465f04..5ef2148 100644 --- a/src/declarative/qml/script/qmlbasicscript.h +++ b/src/declarative/qml/script/qmlbasicscript.h @@ -13,10 +13,10 @@ #define QMLBASICSCRIPT_H #include "instructions.h" -#include <QList> -#include <QByteArray> +#include <QtCore/QList> +#include <QtCore/QByteArray> #include "lexer.h" -#include <QVariant> +#include <QtCore/QVariant> QT_BEGIN_HEADER diff --git a/src/declarative/test/qfxtestengine.h b/src/declarative/test/qfxtestengine.h index 6698645..44a140f 100644 --- a/src/declarative/test/qfxtestengine.h +++ b/src/declarative/test/qfxtestengine.h @@ -42,8 +42,7 @@ #ifndef _QFXTESTENGINE_H_ #define _QFXTESTENGINE_H_ -#include <QObject> -class QSimpleCanvas; +#include <QtCore/QObject> QT_BEGIN_HEADER @@ -51,6 +50,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) +class QSimpleCanvas; class QFxTestEnginePrivate; class Q_DECLARATIVE_EXPORT QFxTestEngine : public QObject { diff --git a/src/declarative/test/qfxtestobjects.h b/src/declarative/test/qfxtestobjects.h index 4273d4e..653656e 100644 --- a/src/declarative/test/qfxtestobjects.h +++ b/src/declarative/test/qfxtestobjects.h @@ -42,10 +42,10 @@ #ifndef _QFXTESTOBJECTS_H_ #define _QFXTESTOBJECTS_H_ -#include <QObject> -#include <QPoint> -#include <QList> -#include <QXmlStreamWriter> +#include <QtCore/QObject> +#include <QtCore/QPoint> +#include <QtCore/QList> +#include <QtCore/QXmlStreamWriter> QT_BEGIN_HEADER diff --git a/src/declarative/test/qfxtestview.h b/src/declarative/test/qfxtestview.h index 33275b9..a8f78bf 100644 --- a/src/declarative/test/qfxtestview.h +++ b/src/declarative/test/qfxtestview.h @@ -42,7 +42,7 @@ #ifndef _QFXTESTVIEW_H_ #define _QFXTESTVIEW_H_ -#include <QFxView> +#include <QtDeclarative/QFxView> QT_BEGIN_HEADER diff --git a/src/declarative/timeline/qmltimeline.h b/src/declarative/timeline/qmltimeline.h index ce9d1f2..23bdd64 100644 --- a/src/declarative/timeline/qmltimeline.h +++ b/src/declarative/timeline/qmltimeline.h @@ -42,9 +42,9 @@ #ifndef QMLTIMELINE_H #define QMLTIMELINE_H -#include <QObject> -#include <qfxglobal.h> -#include <QAbstractAnimation> +#include <QtCore/QObject> +#include <QtCore/QAbstractAnimation> +#include <QtDeclarative/qfxglobal.h> QT_BEGIN_HEADER diff --git a/src/declarative/timeline/qmltimelinevalueproxy.h b/src/declarative/timeline/qmltimelinevalueproxy.h index 853db4e..9ecdba1 100644 --- a/src/declarative/timeline/qmltimelinevalueproxy.h +++ b/src/declarative/timeline/qmltimelinevalueproxy.h @@ -42,7 +42,7 @@ #ifndef QMLTIMELINEVALUEPROXY_H #define QMLTIMELINEVALUEPROXY_H -#include "qmltimeline.h" +#include <QtDeclarative/qmltimeline.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qbindablemap.h b/src/declarative/util/qbindablemap.h index d617867..c76928d 100644 --- a/src/declarative/util/qbindablemap.h +++ b/src/declarative/util/qbindablemap.h @@ -42,11 +42,11 @@ #ifndef QBINDABLEMAP_H #define QBINDABLEMAP_H -#include <qfxglobal.h> -#include <QObject> -#include <QHash> -#include <QStringList> -#include <QVariant> +#include <QtDeclarative/qfxglobal.h> +#include <QtCore/QObject> +#include <QtCore/QHash> +#include <QtCore/QStringList> +#include <QtCore/QVariant> QT_BEGIN_HEADER diff --git a/src/declarative/util/qfxglobal.h b/src/declarative/util/qfxglobal.h index 887351d..6ba9409 100644 --- a/src/declarative/util/qfxglobal.h +++ b/src/declarative/util/qfxglobal.h @@ -42,8 +42,8 @@ #ifndef QFXGLOBAL_H #define QFXGLOBAL_H -#include <qglobal.h> -#include <QObject> +#include <QtCore/qglobal.h> +#include <QtCore/QObject> QT_BEGIN_HEADER diff --git a/src/declarative/util/qfxview.cpp b/src/declarative/util/qfxview.cpp index 1c24e28..0d5b796 100644 --- a/src/declarative/util/qfxview.cpp +++ b/src/declarative/util/qfxview.cpp @@ -93,7 +93,7 @@ class QFxViewPrivate { public: QFxViewPrivate(QFxView *w) - : q(w), root(0), component(0) {} + : q(w), root(0), component(0), resizable(false) {} QFxView *q; QFxItem *root; @@ -106,6 +106,7 @@ public: QBasicTimer resizetimer; QSize initialSize; + bool resizable; void init(); }; @@ -344,7 +345,18 @@ void QFxView::continueExecute() d->root = item; connect(item, SIGNAL(widthChanged()), this, SLOT(sizeChanged())); connect(item, SIGNAL(heightChanged()), this, SLOT(sizeChanged())); - emit sceneResized(QSize(d->root->width(),d->root->height())); + if (d->initialSize.height() <= 0 && d->root->width() > 0) + d->initialSize.setWidth(d->root->width()); + if (d->initialSize.height() <= 0 && d->root->height() > 0) + d->initialSize.setHeight(d->root->height()); + if (d->resizable) { + d->root->setWidth(width()); + d->root->setHeight(height()); + } else { + QSize sz(d->root->width(),d->root->height()); + emit sceneResized(sz); + resize(sz); + } } else if (QWidget *wid = qobject_cast<QWidget *>(obj)) { window()->setAttribute(Qt::WA_OpaquePaintEvent, false); window()->setAttribute(Qt::WA_NoSystemBackground, false); @@ -381,14 +393,55 @@ void QFxView::sizeChanged() */ void QFxView::timerEvent(QTimerEvent* e) { - if (e->timerId() == d->resizetimer.timerId()) { - if (d->root) - emit sceneResized(QSize(d->root->width(),d->root->height())); + if (!e || e->timerId() == d->resizetimer.timerId()) { + if (d->root) { + QSize sz(d->root->width(),d->root->height()); + emit sceneResized(sz); + //if (!d->resizable) + //resize(sz); + } d->resizetimer.stop(); updateGeometry(); } } +// modelled on QScrollArea::widgetResizable +/*! + \property QFxView::contentResizable + \brief whether the view should resize the canvas contents + + If this property is set to false (the default), the view + resizes with the root item in the QML. + + If this property is set to true, the view will + automatically resize the root item. + + Regardless of this property, the sizeHint of the view + is the initial size of the root item. +*/ + +void QFxView::setContentResizable(bool on) +{ + if (d->resizable != on) { + d->resizable = on; + if (d->root) { + if (on) { + d->root->setWidth(width()); + d->root->setHeight(height()); + } else { + d->root->setWidth(d->initialSize.width()); + d->root->setHeight(d->initialSize.height()); + } + } + } +} + +bool QFxView::contentResizable() const +{ + return d->resizable; +} + + /*! The size hint is the size of the root item. */ @@ -481,7 +534,7 @@ QFxItem *QFxView::root() const */ void QFxView::resizeEvent(QResizeEvent *e) { - if (d->root) { + if (d->resizable && d->root) { d->root->setWidth(width()); d->root->setHeight(height()); } diff --git a/src/declarative/util/qfxview.h b/src/declarative/util/qfxview.h index d6f786c..05bf005 100644 --- a/src/declarative/util/qfxview.h +++ b/src/declarative/util/qfxview.h @@ -42,11 +42,11 @@ #ifndef QFXVIEW_H #define QFXVIEW_H -#include <qfxglobal.h> #include <QtCore/qdatetime.h> #include <QtGui/qgraphicssceneevent.h> #include <QtGui/qwidget.h> -#include <qsimplecanvas.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qsimplecanvas.h> QT_BEGIN_HEADER @@ -82,6 +82,8 @@ public: virtual QFxItem *root() const; + void setContentResizable(bool); + bool contentResizable() const; QSize sizeHint() const; void dumpRoot(); diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index dd4e1eb..24bcac98 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -243,8 +243,12 @@ void QmlAbstractAnimation::setRunning(bool r) d->startOnCompletion = true; emit started(); } else { - if (!d->finishPlaying) + if (d->finishPlaying) { + if (d->repeat) + qtAnimation()->setLoopCount(qtAnimation()->currentLoop()+1); + } else qtAnimation()->stop(); + emit completed(); } @@ -512,7 +516,11 @@ void QmlAbstractAnimation::transition(QmlStateActions &actions, void QmlAbstractAnimation::timelineComplete() { + Q_D(QmlAbstractAnimation); setRunning(false); + if (d->finishPlaying && d->repeat) { + qtAnimation()->setLoopCount(-1); + } } /*! diff --git a/src/declarative/util/qmlanimation.h b/src/declarative/util/qmlanimation.h index 578631c..8bd53e2 100644 --- a/src/declarative/util/qmlanimation.h +++ b/src/declarative/util/qmlanimation.h @@ -43,12 +43,12 @@ #define QMLANIMATION_H #include <QtCore/qvariant.h> +#include <QtCore/QAbstractAnimation> #include <QtGui/qcolor.h> -#include <qmltransition.h> -#include <qmlpropertyvaluesource.h> -#include <qmlstate.h> -#include <qml.h> -#include <QAbstractAnimation> +#include <QtDeclarative/qmltransition.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> +#include <QtDeclarative/qmlstate.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index 00937a6..36b826f 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -44,15 +44,15 @@ #include <private/qobject_p.h> #include <private/qmlnullablevalue_p.h> -#include <qmlanimation.h> -#include <qml.h> -#include <qmlcontext.h> #include <private/qvariantanimation_p.h> -#include <QPauseAnimation> -#include <QVariantAnimation> -#include <QAnimationGroup> -#include <QColor> -#include <qmltimelinevalueproxy.h> +#include <QtCore/QPauseAnimation> +#include <QtCore/QVariantAnimation> +#include <QtCore/QAnimationGroup> +#include <QtGui/QColor> +#include <QtDeclarative/qmlanimation.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlcontext.h> +#include <QtDeclarative/qmltimelinevalueproxy.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/util/qmlbehaviour.h b/src/declarative/util/qmlbehaviour.h index 3d25cd8..7a54d63 100644 --- a/src/declarative/util/qmlbehaviour.h +++ b/src/declarative/util/qmlbehaviour.h @@ -42,9 +42,9 @@ #ifndef QMLBEHAVIOUR_H #define QMLBEHAVIOUR_H -#include <qmlpropertyvaluesource.h> -#include <qml.h> -#include <qmlstate.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlstate.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmlbind.h b/src/declarative/util/qmlbind.h index 355edfd..5576957 100644 --- a/src/declarative/util/qmlbind.h +++ b/src/declarative/util/qmlbind.h @@ -42,9 +42,9 @@ #ifndef QMLBIND_H #define QMLBIND_H -#include <qfxglobal.h> +#include <QtDeclarative/qfxglobal.h> #include <QtCore/qobject.h> -#include "qml.h" +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmlfollow.h b/src/declarative/util/qmlfollow.h index bd9363a..fa0bff8 100644 --- a/src/declarative/util/qmlfollow.h +++ b/src/declarative/util/qmlfollow.h @@ -42,8 +42,8 @@ #ifndef QMLFOLLOW_H #define QMLFOLLOW_H -#include <qmlpropertyvaluesource.h> -#include <qml.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmlfont.h b/src/declarative/util/qmlfont.h index b6bce7c..3a21c34 100644 --- a/src/declarative/util/qmlfont.h +++ b/src/declarative/util/qmlfont.h @@ -43,7 +43,7 @@ #define QMLFONT_H #include <QtCore/qobject.h> -#include <qml.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmllistaccessor.h b/src/declarative/util/qmllistaccessor.h index 29f910d..dd766b2 100644 --- a/src/declarative/util/qmllistaccessor.h +++ b/src/declarative/util/qmllistaccessor.h @@ -42,7 +42,7 @@ #ifndef QMLLISTACCESSOR_H #define QMLLISTACCESSOR_H -#include <QVariant> +#include <QtCore/QVariant> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 8184bda..80eb9c3 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -43,6 +43,7 @@ #include <QtCore/qstack.h> #include <QXmlStreamReader> #include <private/qmlcustomparser_p.h> +#include <private/qmlparser_p.h> #include "qmlopenmetaobject.h" #include <qmlcontext.h> #include <qmlbindablevalue.h> @@ -414,8 +415,11 @@ bool ListModelParser::compileProperty(const QmlCustomParserProperty &prop, QList } else { + QmlParser::Variant variant = + qvariant_cast<QmlParser::Variant>(value); + int ref = data.count(); - QByteArray d = value.toString().toLatin1(); + QByteArray d = variant.asScript().toLatin1(); d.append('\0'); data.append(d); diff --git a/src/declarative/util/qmllistmodel.h b/src/declarative/util/qmllistmodel.h index 36aa009..ddf1e13 100644 --- a/src/declarative/util/qmllistmodel.h +++ b/src/declarative/util/qmllistmodel.h @@ -42,14 +42,14 @@ #ifndef QMLLISTMODEL_H #define QMLLISTMODEL_H -#include <QObject> -#include <qfxglobal.h> -#include <QStringList> -#include <QHash> -#include <QList> -#include <QVariant> -#include <qml.h> -#include <qlistmodelinterface.h> +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtCore/QHash> +#include <QtCore/QList> +#include <QtCore/QVariant> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qlistmodelinterface.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmlopenmetaobject.h b/src/declarative/util/qmlopenmetaobject.h index f842f96..239276d 100644 --- a/src/declarative/util/qmlopenmetaobject.h +++ b/src/declarative/util/qmlopenmetaobject.h @@ -42,9 +42,9 @@ #ifndef QMLOPENMETAOBJECT_H #define QMLOPENMETAOBJECT_H -#include <QMetaObject> +#include <QtCore/QMetaObject> #include <QtCore/private/qobject_p.h> -#include <QObject> +#include <QtCore/QObject> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmlpackage.h b/src/declarative/util/qmlpackage.h index 6652b98..3861890 100644 --- a/src/declarative/util/qmlpackage.h +++ b/src/declarative/util/qmlpackage.h @@ -42,7 +42,7 @@ #ifndef QMLPACKAGE_H #define QMLPACKAGE_H -#include <qml.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmlscript.h b/src/declarative/util/qmlscript.h index 8047a88..b739fd7 100644 --- a/src/declarative/util/qmlscript.h +++ b/src/declarative/util/qmlscript.h @@ -42,9 +42,9 @@ #ifndef QMLSCRIPT_H #define QMLSCRIPT_H -#include <qfxglobal.h> +#include <QtDeclarative/qfxglobal.h> #include <QtCore/qobject.h> -#include "qml.h" +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER QT_BEGIN_NAMESPACE diff --git a/src/declarative/util/qmlsetproperties.cpp b/src/declarative/util/qmlsetproperties.cpp index 9b5a58e..c986864 100644 --- a/src/declarative/util/qmlsetproperties.cpp +++ b/src/declarative/util/qmlsetproperties.cpp @@ -44,61 +44,12 @@ #include "qmlsetproperties.h" #include <QtCore/qdebug.h> #include <QtDeclarative/qmlinfo.h> +#include <private/qmlcustomparser_p.h> +#include <private/qmlparser_p.h> +#include <QtDeclarative/qmlexpression.h> QT_BEGIN_NAMESPACE -class QmlSetPropertiesMetaObject : public QmlOpenMetaObject -{ -public: - QmlSetPropertiesMetaObject(QObject *); - -protected: - virtual void propertyRead(int); - virtual void propertyWrite(int); -}; - -class QmlSetPropertiesProxyObject : public QObject -{ -Q_OBJECT -public: - QmlSetPropertiesProxyObject(QObject *); - - QmlSetPropertiesMetaObject *fxMetaObject() const { return _mo; } -private: - QmlSetPropertiesMetaObject *_mo; -}; - -QmlSetPropertiesProxyObject::QmlSetPropertiesProxyObject(QObject *parent) -: QObject(parent), _mo(new QmlSetPropertiesMetaObject(this)) -{ -} - -QmlSetPropertiesMetaObject::QmlSetPropertiesMetaObject(QObject *obj) -: QmlOpenMetaObject(obj) -{ -} - -void QmlSetPropertiesMetaObject::propertyRead(int id) -{ - if (!value(id).isValid()) - setValue(id, QVariant::fromValue((QObject *)new QmlSetPropertiesProxyObject(object()))); - - QmlOpenMetaObject::propertyRead(id); -} - -void QmlSetPropertiesMetaObject::propertyWrite(int id) -{ - if (value(id).userType() == qMetaTypeId<QObject *>()) { - QObject *val = qvariant_cast<QObject *>(value(id)); - QmlSetPropertiesProxyObject *proxy = qobject_cast<QmlSetPropertiesProxyObject *>(val); - if (proxy) { - setValue(id, QVariant()); - delete proxy; - } - } - QmlOpenMetaObject::propertyWrite(id); -} - /*! \qmlclass SetProperties QmlSetProperties \brief The SetProperties element describes new property values for a state. @@ -149,109 +100,263 @@ void QmlSetPropertiesMetaObject::propertyWrite(int id) \sa QmlSetProperty */ +/*! + \qmlproperty Object SetProperties::target + This property holds the object that the properties to change belong to +*/ + +/*! + \property QmlSetProperties::target + \brief the object that the properties to change belong to +*/ class QmlSetPropertiesPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QmlSetProperties) public: - QmlSetPropertiesPrivate() : obj(0), mo(0) {} + QmlSetPropertiesPrivate() : object(0), decoded(true), restore(true) {} + + QObject *object; + QByteArray data; + bool decoded; + void decode(); + + bool restore; - QObject *obj; - QmlSetPropertiesMetaObject *mo; + QList<QPair<QByteArray, QVariant> > properties; + QList<QPair<QByteArray, QmlExpression *> > expressions; + + QmlMetaProperty property(const QByteArray &); }; -QML_DEFINE_TYPE(QmlSetProperties,SetProperties); -QmlSetProperties::QmlSetProperties() - : QmlStateOperation(*(new QmlSetPropertiesPrivate)) +class QmlSetPropertiesParser : public QmlCustomParser { - Q_D(QmlSetProperties); - d->mo = new QmlSetPropertiesMetaObject(this); +public: + void compileList(QList<QPair<QByteArray, QVariant> > &list, const QByteArray &pre, const QmlCustomParserProperty &prop); + + virtual QByteArray compile(const QList<QmlCustomParserProperty> &, bool *ok); + virtual void setCustomData(QObject *, const QByteArray &); +}; + +void +QmlSetPropertiesParser::compileList(QList<QPair<QByteArray, QVariant> > &list, + const QByteArray &pre, + const QmlCustomParserProperty &prop) +{ + QByteArray propName = pre + prop.name(); + + QList<QVariant> values = prop.assignedValues(); + for (int ii = 0; ii < values.count(); ++ii) { + const QVariant &value = values.at(ii); + + if (value.userType() == qMetaTypeId<QmlCustomParserNode>()) { + continue; + } else if(value.userType() == qMetaTypeId<QmlCustomParserProperty>()) { + + QmlCustomParserProperty prop = + qvariant_cast<QmlCustomParserProperty>(value); + QByteArray pre = propName + "."; + compileList(list, pre, prop); + + } else { + list << qMakePair(propName, value); + } + } } -QmlSetProperties::QmlSetProperties(QObject *parent) - : QmlStateOperation(*(new QmlSetPropertiesPrivate), parent) +QByteArray +QmlSetPropertiesParser::compile(const QList<QmlCustomParserProperty> &props, + bool *ok) { - Q_D(QmlSetProperties); - d->mo = new QmlSetPropertiesMetaObject(this); + *ok = true; + + QList<QPair<QByteArray, QVariant> > data; + for(int ii = 0; ii < props.count(); ++ii) + compileList(data, QByteArray(), props.at(ii)); + + QByteArray rv; + QDataStream ds(&rv, QIODevice::WriteOnly); + + ds << data.count(); + for(int ii = 0; ii < data.count(); ++ii) { + QmlParser::Variant v = qvariant_cast<QmlParser::Variant>(data.at(ii).second); + QVariant var; + bool isScript = v.isScript(); + switch(v.type()) { + case QmlParser::Variant::Boolean: + var = QVariant(v.asBoolean()); + break; + case QmlParser::Variant::Number: + var = QVariant(v.asNumber()); + break; + case QmlParser::Variant::String: + var = QVariant(v.asString()); + break; + case QmlParser::Variant::Invalid: + case QmlParser::Variant::Script: + var = QVariant(v.asScript()); + break; + } + + ds << data.at(ii).first << isScript << var; + } + + return rv; } -QmlSetProperties::~QmlSetProperties() +void QmlSetPropertiesPrivate::decode() { + if (decoded) + return; + + QDataStream ds(&data, QIODevice::ReadOnly); + + int count; + ds >> count; + for (int ii = 0; ii < count; ++ii) { + QByteArray name; + bool isScript; + QVariant data; + ds >> name; + ds >> isScript; + ds >> data; + + if (isScript) { + QmlExpression *expression = new QmlExpression(qmlContext(object), data.toString(), object); + expression->setTrackChange(false); + expressions << qMakePair(name, expression); + } else { + properties << qMakePair(name, data); + } + } + + decoded = true; + data.clear(); } -/*! - \qmlproperty Object SetProperties::target - This property holds the object that the properties to change belong to -*/ +void QmlSetPropertiesParser::setCustomData(QObject *object, + const QByteArray &data) +{ + QmlSetPropertiesPrivate *p = + static_cast<QmlSetPropertiesPrivate *>(QObjectPrivate::get(object)); + p->data = data; + p->decoded = false; +} -/*! - \property QmlSetProperties::target - \brief the object that the properties to change belong to -*/ -QObject *QmlSetProperties::object() +QmlSetProperties::QmlSetProperties() +: QmlStateOperation(*(new QmlSetPropertiesPrivate)) +{ +} + +QmlSetProperties::~QmlSetProperties() { Q_D(QmlSetProperties); - return d->obj; + for(int ii = 0; ii < d->expressions.count(); ++ii) + delete d->expressions.at(ii).second; +} + +QObject *QmlSetProperties::object() const +{ + Q_D(const QmlSetProperties); + return d->object; } void QmlSetProperties::setObject(QObject *o) { Q_D(QmlSetProperties); - d->obj = o; + d->object = o; +} + +bool QmlSetProperties::restoreEntryValues() const +{ + Q_D(const QmlSetProperties); + return d->restore; +} + +void QmlSetProperties::setRestoreEntryValues(bool v) +{ + Q_D(QmlSetProperties); + d->restore = v; +} + +QmlMetaProperty +QmlSetPropertiesPrivate::property(const QByteArray &property) +{ + Q_Q(QmlSetProperties); + QList<QByteArray> path = property.split('.'); + + QObject *obj = this->object; + + for (int jj = 0; jj < path.count() - 1; ++jj) { + const QByteArray &pathName = path.at(jj); + QmlMetaProperty prop(obj, QLatin1String(pathName)); + QObject *objVal = QmlMetaType::toQObject(prop.read()); + if (!objVal) { + qmlInfo(q) << obj->metaObject()->className() + << "has no object property named" << pathName; + return QmlMetaProperty(); + } + obj = objVal; + } + + const QByteArray &name = path.last(); + QmlMetaProperty prop(obj, QLatin1String(name)); + if (!prop.isValid()) { + qmlInfo(q) << obj->metaObject()->className() + << "has no property named" << name; + return QmlMetaProperty(); + } else if (!prop.isWritable()) { + qmlInfo(q) << obj->metaObject()->className() + << name << "is not writable, and cannot be set."; + return QmlMetaProperty(); + } else { + return prop; + } } -QmlSetProperties::ActionList -QmlSetProperties::doAction(QmlSetPropertiesMetaObject *metaObject, - QObject *object) +QmlSetProperties::ActionList QmlSetProperties::actions() { + Q_D(QmlSetProperties); + + d->decode(); + ActionList list; - for (int ii = 0; ii < metaObject->count(); ++ii) { + for (int ii = 0; ii < d->properties.count(); ++ii) { + + QByteArray property = d->properties.at(ii).first; + QmlMetaProperty prop = d->property(property); - QByteArray name = metaObject->name(ii); - QVariant value = metaObject->value(ii); + if (prop.isValid()) { + Action a; + a.restore = restoreEntryValues(); + a.property = prop; + a.fromValue = a.property.read(); + a.toValue = d->properties.at(ii).second; - QmlSetPropertiesProxyObject *po = qobject_cast<QmlSetPropertiesProxyObject *>(qvariant_cast<QObject *>(value)); + list << a; + } + } - QmlMetaProperty prop(object, QLatin1String(name)); + for (int ii = 0; ii < d->expressions.count(); ++ii) { - if (po) { - QObject *objVal = QmlMetaType::toQObject(prop.read()); - if (!objVal) { - qmlInfo(this) << object->metaObject()->className() - << "has no object property named" << name; - continue; - } + QByteArray property = d->expressions.at(ii).first; + QmlMetaProperty prop = d->property(property); - list << doAction(po->fxMetaObject(), objVal); - } else if (!prop.isValid()) { - qmlInfo(this) << object->metaObject()->className() - << "has no property named" << name; - continue; - } else if (!prop.isWritable()) { - qmlInfo(this) << object->metaObject()->className() - << name << "is not writable, and cannot be set."; - continue; - } else { - //append action + if (prop.isValid()) { Action a; + a.restore = restoreEntryValues(); a.property = prop; - a.fromValue = prop.read(); - a.toValue = value; + a.fromValue = a.property.read(); + a.toValue = d->expressions.at(ii).second->value(); list << a; } + } return list; } -QmlSetProperties::ActionList QmlSetProperties::actions() -{ - Q_D(QmlSetProperties); - if (!d->obj) - return ActionList(); - - return doAction(d->mo, d->obj); -} +QML_DEFINE_CUSTOM_TYPE(QmlSetProperties,SetProperties,QmlSetPropertiesParser); QT_END_NAMESPACE -#include "qmlsetproperties.moc" diff --git a/src/declarative/util/qmlsetproperties.h b/src/declarative/util/qmlsetproperties.h index 456b672..24ad99a 100644 --- a/src/declarative/util/qmlsetproperties.h +++ b/src/declarative/util/qmlsetproperties.h @@ -42,7 +42,7 @@ #ifndef QMLSETPROPERTIES_H #define QMLSETPROPERTIES_H -#include <qmlstateoperations.h> +#include <QtDeclarative/qmlstateoperations.h> QT_BEGIN_HEADER @@ -50,7 +50,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QmlSetPropertiesMetaObject; + class QmlSetPropertiesPrivate; class Q_DECLARATIVE_EXPORT QmlSetProperties : public QmlStateOperation { @@ -58,26 +58,23 @@ class Q_DECLARATIVE_EXPORT QmlSetProperties : public QmlStateOperation Q_DECLARE_PRIVATE(QmlSetProperties); Q_PROPERTY(QObject *target READ object WRITE setObject); - + Q_PROPERTY(bool restoreEntryValues READ restoreEntryValues WRITE setRestoreEntryValues); public: QmlSetProperties(); - QmlSetProperties(QObject *parent); ~QmlSetProperties(); - QObject *object(); + QObject *object() const; void setObject(QObject *); - virtual ActionList actions(); + bool restoreEntryValues() const; + void setRestoreEntryValues(bool); -private: - ActionList doAction(QmlSetPropertiesMetaObject *, QObject *); - //QmlSetProperties::ActionList appendDotActions(const QVariant &, const QVariant &); + virtual ActionList actions(); }; QML_DECLARE_TYPE(QmlSetProperties); -#endif // QMLSETPROPERTIES_H - - QT_END_NAMESPACE QT_END_HEADER + +#endif // QMLSETPROPERTIES_H diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index 194cc1b..6261003 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG); -Action::Action() : bv(0), event(0), actionDone(false) +Action::Action() : restore(true), bv(0), event(0), actionDone(false) { } @@ -344,7 +344,7 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever for (int ii = 0; ii < applyList.count(); ++ii) { const Action &action = applyList.at(ii); - if (action.event) + if (action.event || !action.restore) continue; bool found = false; diff --git a/src/declarative/util/qmlstate.h b/src/declarative/util/qmlstate.h index 68c43fa..aa8871f 100644 --- a/src/declarative/util/qmlstate.h +++ b/src/declarative/util/qmlstate.h @@ -43,9 +43,9 @@ #define QMLSTATE_H #include <QtCore/qobject.h> -#include <qfxglobal.h> -#include <qml.h> -#include <QSequentialAnimationGroup> +#include <QtCore/QSequentialAnimationGroup> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER @@ -61,6 +61,7 @@ public: Action(); QmlMetaProperty property; + bool restore; QVariant fromValue; QVariant toValue; QString fromBinding; diff --git a/src/declarative/util/qmlstate_p.h b/src/declarative/util/qmlstate_p.h index 28e1781..a2f18eb 100644 --- a/src/declarative/util/qmlstate_p.h +++ b/src/declarative/util/qmlstate_p.h @@ -42,9 +42,9 @@ #ifndef QMLSTATE_P_H #define QMLSTATE_P_H -#include <qmlstate.h> -#include "private/qobject_p.h" -#include "private/qmlanimation_p.h" +#include <QtDeclarative/qmlstate.h> +#include <private/qobject_p.h> +#include <private/qmlanimation_p.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/util/qmlstategroup.h b/src/declarative/util/qmlstategroup.h index 55b84eb..cca1015 100644 --- a/src/declarative/util/qmlstategroup.h +++ b/src/declarative/util/qmlstategroup.h @@ -42,7 +42,7 @@ #ifndef QMLSTATEGROUP_H #define QMLSTATEGROUP_H -#include <qmlstate.h> +#include <QtDeclarative/qmlstate.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmlstateoperations.h b/src/declarative/util/qmlstateoperations.h index 8ecdcd2..720c639 100644 --- a/src/declarative/util/qmlstateoperations.h +++ b/src/declarative/util/qmlstateoperations.h @@ -42,7 +42,7 @@ #ifndef QMLSTATEOPERATIONS_H #define QMLSTATEOPERATIONS_H -#include <qmlstate.h> +#include <QtDeclarative/qmlstate.h> QT_BEGIN_HEADER diff --git a/src/declarative/util/qmltransition.h b/src/declarative/util/qmltransition.h index 0b7ea14..646746e 100644 --- a/src/declarative/util/qmltransition.h +++ b/src/declarative/util/qmltransition.h @@ -43,9 +43,9 @@ #define QMLTRANSITION_H #include <QtCore/qobject.h> -#include <qfxglobal.h> -#include <qmlstate.h> -#include <qml.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qmlstate.h> +#include <QtDeclarative/qml.h> QT_BEGIN_HEADER diff --git a/src/declarative/widgets/graphicslayouts.h b/src/declarative/widgets/graphicslayouts.h index beb4b65..e9930f1 100644 --- a/src/declarative/widgets/graphicslayouts.h +++ b/src/declarative/widgets/graphicslayouts.h @@ -42,9 +42,9 @@ #ifndef GRAPHICSLAYOUTS_H #define GRAPHICSLAYOUTS_H -#include "graphicswidgets.h" -#include <QGraphicsLinearLayout> -#include <QGraphicsGridLayout> +#include <QtDeclarative/graphicswidgets.h> +#include <QtGui/QGraphicsLinearLayout> +#include <QtGui/QGraphicsGridLayout> QT_BEGIN_HEADER diff --git a/src/declarative/widgets/graphicswidgets.h b/src/declarative/widgets/graphicswidgets.h index 47a753a..cec15b6 100644 --- a/src/declarative/widgets/graphicswidgets.h +++ b/src/declarative/widgets/graphicswidgets.h @@ -42,11 +42,11 @@ #ifndef GRAPHICSWIDGETS_H #define GRAPHICSWIDGETS_H -#include <qml.h> -#include <QGraphicsScene> -#include <QGraphicsView> -#include <QGraphicsWidget> -#include <QGraphicsItem> +#include <QtDeclarative/qml.h> +#include <QtGui/QGraphicsScene> +#include <QtGui/QGraphicsView> +#include <QtGui/QGraphicsWidget> +#include <QtGui/QGraphicsItem> QT_BEGIN_NAMESPACE diff --git a/src/gui/dialogs/qsidebar.cpp b/src/gui/dialogs/qsidebar.cpp index 26108d7..000a06b 100644 --- a/src/gui/dialogs/qsidebar.cpp +++ b/src/gui/dialogs/qsidebar.cpp @@ -249,9 +249,9 @@ void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move) continue; for (int j = 0; move && j < rowCount(); ++j) { #if defined(Q_OS_WIN) - if (index(j, 0).data(UrlRole).toUrl().toLocalFile().toLower() == url.toLocalFile().toLower()) { + if (QDir::cleanPath(index(j, 0).data(UrlRole).toUrl().toLocalFile()).toLower() == QDir::cleanPath(url.toLocalFile()).toLower()) { #else - if (index(j, 0).data(UrlRole) == url) { + if (QDir::cleanPath(index(j, 0).data(UrlRole).toUrl().toLocalFile()) == QDir::cleanPath(url.toLocalFile())) { #endif removeRow(j); if (j <= row) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index ca112d7..e02b3eb 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2640,6 +2640,10 @@ QTransform QGraphicsItem::sceneTransform() const */ QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) const { + // Ensure we return the standard transform if we're not untransformable. + if (!d_ptr->itemIsUntransformable()) + return sceneTransform() * viewportTransform; + // Find the topmost item that ignores view transformations. const QGraphicsItem *untransformedAncestor = this; QList<const QGraphicsItem *> parents; @@ -2836,7 +2840,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) if (oldTransform == newTransform) return; - // Notify the item that the matrix is changing. + // Notify the item that the transformation matrix is changing. QVariant newTransformVariant(itemChange(ItemMatrixChange, qVariantFromValue<QMatrix>(newTransform.toAffine()))); newTransform = QTransform(qVariantValue<QMatrix>(newTransformVariant)); diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index bc5c091..c421f05 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1330,8 +1330,7 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou bool disabled = !item->isEnabled(); bool isWindow = item->isWindow(); if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick - && item != lastMouseGrabberItem && lastMouseGrabberItem) - { + && item != lastMouseGrabberItem && lastMouseGrabberItem) { // If this item is different from the item that received the last // mouse event, and mouseEvent is a doubleclick event, then the // event is converted to a press. Known limitation: @@ -2326,12 +2325,7 @@ void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRect // Calculate a simple level-of-detail metric. // ### almost identical code in QGraphicsView::paintEvent() // and QGraphicsView::render() - consider refactoring - QTransform itemToDeviceTransform; - if (item->d_ptr->itemIsUntransformable()) { - itemToDeviceTransform = item->deviceTransform(painterTransform); - } else { - itemToDeviceTransform = item->sceneTransform() * painterTransform; - } + QTransform itemToDeviceTransform = item->deviceTransform(painterTransform); option.levelOfDetail = qSqrt(itemToDeviceTransform.map(v1).length() * itemToDeviceTransform.map(v2).length()); option.matrix = itemToDeviceTransform.toAffine(); //### discards perspective @@ -5135,11 +5129,7 @@ void QGraphicsScene::drawItems(QPainter *painter, // optimization, but it's hit very rarely. for (int i = clippers.size() - 1; i >= 0; --i) { QGraphicsItem *clipper = clippers[i]; - if (clipper->d_ptr->itemIsUntransformable()) { - painter->setWorldTransform(clipper->deviceTransform(viewTransform), false); - } else { - painter->setWorldTransform(clipper->sceneTransform() * viewTransform, false); - } + painter->setWorldTransform(clipper->deviceTransform(viewTransform), false); childClippers.append(clipper); painter->save(); @@ -5150,12 +5140,8 @@ void QGraphicsScene::drawItems(QPainter *painter, } // Set up the painter transform - if (item->d_ptr->itemIsUntransformable()) { - painter->setWorldTransform(item->deviceTransform(viewTransform), false); - } else { - painter->setWorldTransform(item->sceneTransform() * viewTransform, false); - } - + painter->setWorldTransform(item->deviceTransform(viewTransform), false); + // Save painter bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape)); if (saveState) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 2876016..7181045 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1163,11 +1163,7 @@ void QGraphicsViewPrivate::generateStyleOptions(const QList<QGraphicsItem *> &it // Calculate a simple level-of-detail metric. // ### almost identical code in QGraphicsScene::render() // and QGraphicsView::render() - consider refactoring - if (item->d_ptr->itemIsUntransformable()) { - itemToViewportTransform = item->deviceTransform(worldTransform); - } else { - itemToViewportTransform = item->sceneTransform() * worldTransform; - } + itemToViewportTransform = item->deviceTransform(worldTransform); if (itemToViewportTransform.type() <= QTransform::TxTranslate) { // Translation and rotation only? The LOD is 1. @@ -1691,6 +1687,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene) disconnect(d->scene, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(updateSceneRect(QRectF))); d->scene->d_func()->views.removeAll(this); + d->connectedToScene = false; } // Assign the new scene and update the contents (scrollbars, etc.)). @@ -2175,12 +2172,7 @@ void QGraphicsView::render(QPainter *painter, const QRectF &target, const QRect // Calculate a simple level-of-detail metric. // ### almost identical code in QGraphicsScene::render() // and QGraphicsView::paintEvent() - consider refactoring - QTransform itemToViewportTransform; - if (item->d_ptr->itemIsUntransformable()) { - itemToViewportTransform = item->deviceTransform(painterMatrix); - } else { - itemToViewportTransform = item->sceneTransform() * painterMatrix; - } + QTransform itemToViewportTransform = item->deviceTransform(painterMatrix); option->levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length()); option->matrix = itemToViewportTransform.toAffine(); diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 0514567..b2b8c13 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -856,6 +856,9 @@ void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state) QImageWriter::supportedImageFormats() functions to retrieve a complete list of the supported file formats. + Note: When you add a non-empty filename to a QIcon, the icon becomes + non-null, even if the file doesn't exist or points to a corrupt file. + \sa addPixmap() */ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state) diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp index 20bed02..d4ebef7 100644 --- a/src/gui/image/qpixmap_win.cpp +++ b/src/gui/image/qpixmap_win.cpp @@ -319,6 +319,7 @@ static QImage qt_fromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h) } else { qWarning("qt_fromWinHBITMAP(), failed to get bitmap bits"); } + qFree(data); return image; } diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index 9f33af3..054f4cf 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -416,26 +416,22 @@ QString QFileIconProvider::type(const QFileInfo &info) const } if (info.isDir()) - return QApplication::translate("QFileDialog", #ifdef Q_WS_WIN - "File Folder", "Match Windows Explorer" + return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer"); #else - "Folder", "All other platforms" + return QApplication::translate("QFileDialog", "Folder", "All other platforms"); #endif - ); // Windows - "File Folder" // OS X - "Folder" // Konqueror - "Folder" // Nautilus - "folder" if (info.isSymLink()) - return QApplication::translate("QFileDialog", #ifdef Q_OS_MAC - "Alias", "Mac OS X Finder" + return QApplication::translate("QFileDialog", "Alias", "Mac OS X Finder"); #else - "Shortcut", "All other platforms" + return QApplication::translate("QFileDialog", "Shortcut", "All other platforms"); #endif - ); // OS X - "Alias" // Windows - "Shortcut" // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp index 3e00cd0..1071c1d 100644 --- a/src/gui/itemviews/qlistview.cpp +++ b/src/gui/itemviews/qlistview.cpp @@ -1608,6 +1608,10 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con if (!selection.at(i).isValid()) continue; QModelIndex parent = selection.at(i).topLeft().parent(); + //we only display the children of the root in a listview + //we're not interested in the other model indexes + if (parent != d->root) + continue; int t = selection.at(i).topLeft().row(); int b = selection.at(i).bottomRight().row(); if (d->viewMode == IconMode || d->isWrapping()) { // in non-static mode, we have to go through all selected items @@ -1616,8 +1620,8 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con } else { // in static mode, we can optimize a bit while (t <= b && d->isHidden(t)) ++t; while (b >= t && d->isHidden(b)) --b; - const QModelIndex top = d->model->index(t, c, d->root); - const QModelIndex bottom = d->model->index(b, c, d->root); + const QModelIndex top = d->model->index(t, c, parent); + const QModelIndex bottom = d->model->index(b, c, parent); QRect rect(visualRect(top).topLeft(), visualRect(bottom).bottomRight()); selectionRegion += QRegion(rect); diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index f6c5cf0..d742698 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -3086,10 +3086,6 @@ void QTreeViewPrivate::layout(int i) Q_Q(QTreeView); QModelIndex current; QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i); - // modelIndex() will return an index that don't have a parent if column 0 is hidden, - // so we must make sure that parent points to the actual parent that has children. - if (parent != root) - parent = model->index(parent.row(), 0, parent.parent()); if (i>=0 && !parent.isValid()) { //modelIndex() should never return something invalid for the real items. diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 27dfab6..a9424db 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -2028,12 +2028,10 @@ QWidget *QApplication::focusWidget() void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) { - if (focus && focus->window() #ifndef QT_NO_GRAPHICSVIEW - && focus->window()->graphicsProxyWidget() -#endif - ) + if (focus && focus->window()->graphicsProxyWidget()) return; +#endif hidden_focus_widget = 0; diff --git a/src/gui/kernel/qdnd_x11.cpp b/src/gui/kernel/qdnd_x11.cpp index ed93b34..9b2305d 100644 --- a/src/gui/kernel/qdnd_x11.cpp +++ b/src/gui/kernel/qdnd_x11.cpp @@ -543,7 +543,7 @@ bool QX11Data::xdndMimeDataForAtom(Atom a, QMimeData *mimeData, QByteArray *data (dm->xdndMimeTransferedPixmapIndex + 1) % 2; } } else { - DEBUG("QClipboard: xdndMimeDataForAtom(): converting to type '%s' is not supported", atomName); + DEBUG("QClipboard: xdndMimeDataForAtom(): converting to type '%s' is not supported", qPrintable(atomName)); } } return data; @@ -624,7 +624,6 @@ QVariant QX11Data::xdndMimeConvertToFormat(Atom a, const QByteArray &data, const if (format == QLatin1String("image/ppm")) { if (a == XA_PIXMAP && data.size() == sizeof(Pixmap)) { Pixmap xpm = *((Pixmap*)data.data()); - Display *dpy = display; if (!xpm) return QByteArray(); QPixmap qpm = QPixmap::fromX11Pixmap(xpm); diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index a77325c..c8d40d8 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -714,12 +714,13 @@ QWheelEvent::QWheelEvent(const QPoint &pos, const QPoint& globalPos, int delta, The \a type parameter must be QEvent::KeyPress, QEvent::KeyRelease, or QEvent::ShortcutOverride. - If \a key is 0, the event is not a result of - a known key; for example, it may be the result of a compose - sequence or keyboard macro. The \a modifiers holds the keyboard - modifiers, and the given \a text is the Unicode text that the - key generated. If \a autorep is true, isAutoRepeat() will be - true. \a count is the number of keys involved in the event. + Int \a key is the code for the Qt::Key that the event loop should listen + for. If \a key is 0, the event is not a result of a known key; for + example, it may be the result of a compose sequence or keyboard macro. + The \a modifiers holds the keyboard modifiers, and the given \a text + is the Unicode text that the key generated. If \a autorep is true, + isAutoRepeat() will be true. \a count is the number of keys involved + in the event. */ QKeyEvent::QKeyEvent(Type type, int key, Qt::KeyboardModifiers modifiers, const QString& text, bool autorep, ushort count) diff --git a/src/gui/kernel/qlayoutitem.cpp b/src/gui/kernel/qlayoutitem.cpp index 0fd73b8..c70ab2d 100644 --- a/src/gui/kernel/qlayoutitem.cpp +++ b/src/gui/kernel/qlayoutitem.cpp @@ -54,7 +54,8 @@ QT_BEGIN_NAMESPACE inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) { - return priv->fromOrToLayoutItemRect(rect, -1); + return rect.adjusted(priv->leftLayoutItemMargin, priv->topLayoutItemMargin, + -priv->rightLayoutItemMargin, -priv->bottomLayoutItemMargin); } inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) @@ -64,7 +65,8 @@ inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) { - return priv->fromOrToLayoutItemRect(rect, +1); + return rect.adjusted(-priv->leftLayoutItemMargin, -priv->topLayoutItemMargin, + priv->rightLayoutItemMargin, priv->bottomLayoutItemMargin); } inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size) diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index b6703e2..f998bb2 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -751,6 +751,7 @@ bool QShortcutMap::correctGraphicsWidgetContext(Qt::ShortcutContext context, QGr tw = tw->parentWidget(); return tw == w; } + return false; } // Below is Qt::WindowShortcut context diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index b50eb24..e52a517 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -167,39 +167,48 @@ static inline bool bypassGraphicsProxyWidget(QWidget *p) extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp -QWidgetPrivate::QWidgetPrivate(int version) : - QObjectPrivate(version), extra(0), focus_child(0) - ,layout(0), widgetItem(0) - ,leftmargin(0), topmargin(0), rightmargin(0), bottommargin(0) - ,leftLayoutItemMargin(0), topLayoutItemMargin(0), rightLayoutItemMargin(0) - ,bottomLayoutItemMargin(0) - ,fg_role(QPalette::NoRole) - ,bg_role(QPalette::NoRole) - ,hd(0) - ,dirty(0) - ,needsFlush(0) - ,dirtyOpaqueChildren(1) - ,isOpaque(0) - ,inDirtyList(0) - ,isScrolled(0) - ,isMoved(0) - ,usesDoubleBufferedGLContext(0) -#ifdef Q_WS_WIN - ,noPaintOnScreen(0) -#endif - ,inheritedFontResolveMask(0) - ,inheritedPaletteResolveMask(0) +QWidgetPrivate::QWidgetPrivate(int version) + : QObjectPrivate(version) + , extra(0) + , focus_next(0) + , focus_prev(0) + , focus_child(0) + , layout(0) + , needsFlush(0) + , redirectDev(0) + , widgetItem(0) + , extraPaintEngine(0) + , polished(0) + , inheritedFontResolveMask(0) + , inheritedPaletteResolveMask(0) + , leftmargin(0) + , topmargin(0) + , rightmargin(0) + , bottommargin(0) + , leftLayoutItemMargin(0) + , topLayoutItemMargin(0) + , rightLayoutItemMargin(0) + , bottomLayoutItemMargin(0) + , hd(0) + , size_policy(QSizePolicy::Preferred, QSizePolicy::Preferred) + , fg_role(QPalette::NoRole) + , bg_role(QPalette::NoRole) + , dirtyOpaqueChildren(1) + , isOpaque(0) + , inDirtyList(0) + , isScrolled(0) + , isMoved(0) + , usesDoubleBufferedGLContext(0) #if defined(Q_WS_X11) - ,picture(0) + , picture(0) +#elif defined(Q_WS_WIN) + , noPaintOnScreen(0) +#elif defined(Q_WS_MAC) + , needWindowChange(0) + , isGLWidget(0) + , window_event(0) + , qd_hd(0) #endif -#ifdef Q_WS_MAC - ,needWindowChange(0) - ,isGLWidget(0) -#endif - ,polished(0) - - , size_policy(QSizePolicy::Preferred, QSizePolicy::Preferred) - , redirectDev(0) { if (!qApp) { qFatal("QWidget: Must construct a QApplication before a QPaintDevice"); @@ -1345,7 +1354,7 @@ QWidget::~QWidget() d->setDirtyOpaqueRegion(); if (isWindow() && isVisible() && internalWinId()) - hide(); + d->close_helper(QWidgetPrivate::CloseNoEvent); #if defined(Q_WS_WIN) || defined(Q_WS_X11) else if (!internalWinId() && isVisible()) qApp->d_func()->sendSyntheticEnterLeave(this); @@ -1412,36 +1421,26 @@ void QWidgetPrivate::createTLExtra() createExtra(); if (!extra->topextra) { QTLWExtra* x = extra->topextra = new QTLWExtra; + x->icon = 0; + x->iconPixmap = 0; + x->backingStore = 0; x->windowSurface = 0; + x->sharedPainter = 0; + x->incw = x->inch = 0; + x->basew = x->baseh = 0; + x->frameStrut.setCoords(0, 0, 0, 0); + x->normalGeometry = QRect(0,0,-1,-1); + x->savedFlags = 0; x->opacity = 255; x->posFromMove = false; x->sizeAdjusted = false; x->inTopLevelResize = false; x->inRepaint = false; - x->backingStore = 0; - x->icon = 0; - x->iconPixmap = 0; - x->frameStrut.setCoords(0, 0, 0, 0); - x->incw = x->inch = 0; - x->basew = x->baseh = 0; - x->normalGeometry = QRect(0,0,-1,-1); -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC) x->embedded = 0; -#endif -#if defined(Q_WS_X11) - x->parentWinId = 0; - x->spont_unmapped = 0; - x->dnd = 0; -#endif - x->savedFlags = 0; -#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) - x->qwsManager = 0; -#endif - x->sharedPainter = 0; createTLSysExtra(); #ifdef QWIDGET_EXTRA_DEBUG - static int count = 0; - qDebug() << "tlextra" << ++count; + static int count = 0; + qDebug() << "tlextra" << ++count; #endif } } @@ -1455,27 +1454,28 @@ void QWidgetPrivate::createExtra() { if (!extra) { // if not exists extra = new QWExtra; - extra->minw = extra->minh = 0; - extra->maxw = extra->maxh = QWIDGETSIZE_MAX; + extra->glContext = 0; + extra->topextra = 0; + extra->proxyWidget = 0; +#ifndef QT_NO_CURSOR + extra->curs = 0; +#endif + extra->minw = 0; + extra->minh = 0; + extra->maxw = QWIDGETSIZE_MAX; + extra->maxh = QWIDGETSIZE_MAX; + extra->customDpiX = 0; + extra->customDpiY = 0; extra->explicitMinSize = 0; extra->explicitMaxSize = 0; extra->autoFillBackground = 0; extra->nativeChildrenForced = 0; extra->inRenderWithPainter = 0; extra->hasMask = 0; -#ifndef QT_NO_CURSOR - extra->curs = 0; -#endif - extra->style = 0; - extra->topextra = 0; - extra->proxyWidget = 0; - extra->glContext = 0; - extra->customDpiX = 0; - extra->customDpiY = 0; createSysExtra(); #ifdef QWIDGET_EXTRA_DEBUG - static int count = 0; - qDebug() << "extra" << ++count; + static int count = 0; + qDebug() << "extra" << ++count; #endif } } @@ -1516,45 +1516,6 @@ void QWidgetPrivate::deleteExtra() } /* - Returns true if the background is inherited; otherwise returns - false. - - Mainly used in the paintOnScreen case. -*/ - -bool QWidgetPrivate::isBackgroundInherited() const -{ - Q_Q(const QWidget); - - // windows do not inherit their background - if (q->isWindow() || q->windowType() == Qt::SubWindow) - return false; - - if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent)) - return false; - - const QPalette &pal = q->palette(); - QPalette::ColorRole bg = q->backgroundRole(); - QBrush brush = pal.brush(bg); - - // non opaque brushes leaves us no choice, we must inherit - if (!q->autoFillBackground() || !brush.isOpaque()) - return true; - - if (brush.style() == Qt::SolidPattern) { - // the background is just a solid color. If there is no - // propagated contents, then we claim as performance - // optimization that it was not inheritet. This is the normal - // case in standard Windows or Motif style. - const QWidget *w = q->parentWidget(); - if (!w->d_func()->isBackgroundInherited()) - return false; - } - - return true; -} - -/* Returns true if there are widgets above this which overlap with \a rect, which is in parent's coordinate system (same as crect). */ @@ -1900,24 +1861,6 @@ void QWidgetPrivate::clipToEffectiveMask(QRegion ®ion) const } } -bool QWidgetPrivate::hasBackground() const -{ - Q_Q(const QWidget); - if (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_PaintOnScreen)) - return true; - if (q->testAttribute(Qt::WA_PaintOnScreen)) - return true; - if (!q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) { - const QPalette &pal = q->palette(); - QPalette::ColorRole bg = q->backgroundRole(); - QBrush bgBrush = pal.brush(bg); - return (bgBrush.style() != Qt::NoBrush && - ((q->isWindow() || q->windowType() == Qt::SubWindow) - || (QPalette::ColorRole(bg_role) != QPalette::NoRole || (pal.resolve() & (1<<bg))))); - } - return false; -} - bool QWidgetPrivate::paintOnScreen() const { #if defined(Q_WS_QWS) @@ -6157,14 +6100,6 @@ int QWidgetPrivate::pointToRect(const QPoint &p, const QRect &r) return dx + dy; } -QRect QWidgetPrivate::fromOrToLayoutItemRect(const QRect &rect, int sign) const -{ - QRect r = rect; - r.adjust(-sign * leftLayoutItemMargin, -sign * topLayoutItemMargin, - +sign * rightLayoutItemMargin, +sign * bottomLayoutItemMargin); - return r; -} - /*! \property QWidget::frameSize \brief the size of the widget including any window frame diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 1896b97..cc291e3 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -728,6 +728,7 @@ static OSWindowRef qt_mac_create_window(QWidget *, WindowClass wclass, WindowAtt static EventTypeSpec window_events[] = { { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowExpanded }, + { kEventClassWindow, kEventWindowHidden }, { kEventClassWindow, kEventWindowZoomed }, { kEventClassWindow, kEventWindowCollapsed }, { kEventClassWindow, kEventWindowToolbarSwitchMode }, @@ -780,16 +781,6 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, // By also setting the current modal window back into the event, we // help Carbon determining which window is supposed to be raised. handled_event = qApp->activePopupWidget() ? true : false; - QWidget *top = 0; - if (!QApplicationPrivate::tryModalHelper(widget, &top) && top && top != widget){ - if(!qt_mac_is_macsheet(top) || top->parentWidget() != widget) { - handled_event = true; - WindowPtr topWindowRef = qt_mac_window_for(top); - SetEventParameter(event, kEventParamModalWindow, typeWindowRef, sizeof(topWindowRef), &topWindowRef); - HIModalClickResult clickResult = kHIModalClickIsModal; - SetEventParameter(event, kEventParamModalClickResult, typeModalClickResult, sizeof(clickResult), &clickResult); - } - } #endif } else if(ekind == kEventWindowClose) { widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent); @@ -997,6 +988,19 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, } } } + } else if (ekind == kEventWindowHidden) { + // Make sure that we also hide any visible sheets on our window. + // Cocoa does the right thing for us. + const QObjectList children = widget->children(); + const int childCount = children.count(); + for (int i = 0; i < childCount; ++i) { + QObject *obj = children.at(i); + if (obj->isWidgetType()) { + QWidget *widget = static_cast<QWidget *>(obj); + if (qt_mac_is_macsheet(widget) && widget->isVisible()) + widget->hide(); + } + } } else { handled_event = false; } @@ -1599,24 +1603,6 @@ bool QWidgetPrivate::qt_create_root_win() return true; } -bool QWidgetPrivate::qt_recreate_root_win() -{ - if(!qt_root_win) //sanity check - return false; - //store old - OSWindowRef old_root_win = qt_root_win; - //recreate - qt_root_win = 0; - qt_create_root_win(); - //cleanup old window -#ifdef QT_MAC_USE_COCOA - [old_root_win release]; -#else - CFRelease(old_root_win); -#endif - return true; -} - bool QWidgetPrivate::qt_widget_rgn(QWidget *widget, short wcode, RgnHandle rgn, bool force = false) { bool ret = false; @@ -4438,11 +4424,13 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { + extra->topextra->resizer = 0; + extra->topextra->isSetGeometry = 0; + extra->topextra->isMove = 0; + extra->topextra->wattr = 0; extra->topextra->wclass = 0; extra->topextra->group = 0; extra->topextra->windowIcon = 0; - extra->topextra->resizer = 0; - extra->topextra->isSetGeometry = 0; extra->topextra->savedWindowAttributesFromMaximized = 0; } diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 8c6a234..bf4f091 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -99,88 +99,92 @@ class QWidgetItemV2; class QStyle; struct QTLWExtra { + // *************************** Cross-platform variables ***************************** + + // Regular pointers (keep them together to avoid gaps on 64 bits architectures). + QIcon *icon; // widget icon + QPixmap *iconPixmap; + QWidgetBackingStore *backingStore; + QWindowSurface *windowSurface; + QPainter *sharedPainter; + + // Implicit pointers (shared_null). QString caption; // widget caption QString iconText; // widget icon text QString role; // widget role QString filePath; // widget file path - QIcon *icon; // widget icon - QPixmap *iconPixmap; + + // Other variables. short incw, inch; // size increments + short basew, baseh; // base sizes // frame strut, don't use these directly, use QWidgetPrivate::frameStrut() instead. QRect frameStrut; + QRect normalGeometry; // used by showMin/maximized/FullScreen + Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen + + // *************************** Cross-platform bit fields **************************** uint opacity : 8; uint posFromMove : 1; uint sizeAdjusted : 1; uint inTopLevelResize : 1; uint inRepaint : 1; - QWidgetBackingStore *backingStore; -#if defined(Q_WS_WIN) - ulong savedFlags; // Save window flags while showing fullscreen - uint embedded : 1; // window is embedded in another application -#else - Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen -#endif - short basew, baseh; // base sizes -#if defined(Q_WS_X11) - WId parentWinId; // parent window Id (valid after reparenting) - uint embedded : 1; // window is embedded in another Qt application + uint embedded : 1; + + // *************************** Platform specific values (bit fields first) ********** +#if defined(Q_WS_X11) // <----------------------------------------------------------- X11 uint spont_unmapped: 1; // window was spontaneously unmapped uint dnd : 1; // DND properties installed uint validWMState : 1; // is WM_STATE valid? uint waitingForMapNotify : 1; // show() has been called, haven't got the MapNotify yet + WId parentWinId; // parent window Id (valid after reparenting) WId userTimeWindow; // window id that contains user-time timestamp when WM supports a _NET_WM_USER_TIME_WINDOW atom QPoint fullScreenOffset; -#endif -#if defined(Q_WS_MAC) +#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + HICON winIconBig; // internal big Windows icon + HICON winIconSmall; // internal small Windows icon +#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC + uint resizer : 4; + uint isSetGeometry : 1; + uint isMove : 1; quint32 wattr; quint32 wclass; WindowGroupRef group; IconRef windowIcon; // the current window icon, if set with setWindowIcon_sys. quint32 savedWindowAttributesFromMaximized; // Saved attributes from when the calling updateMaximizeButton_sys() - uint resizer : 4; - uint isSetGeometry : 1; - uint isMove : 1; - uint embedded : 1; -#endif -#if defined(Q_WS_QWS) && !defined (QT_NO_QWS_MANAGER) +#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS +#ifndef QT_NO_QWS_MANAGER QWSManager *qwsManager; #endif -#if defined(Q_WS_WIN) - HICON winIconBig; // internal big Windows icon - HICON winIconSmall; // internal small Windows icon #endif - QRect normalGeometry; // used by showMin/maximized/FullScreen - QWindowSurface *windowSurface; - QPainter *sharedPainter; }; struct QWExtra { - qint32 minw, minh; // minimum size - qint32 maxw, maxh; // maximum size - QPointer<QWidget> focus_proxy; -#ifndef QT_NO_CURSOR - QCursor *curs; -#endif + // *************************** Cross-platform variables ***************************** + + // Regular pointers (keep them together to avoid gaps on 64 bits architectures). + void *glContext; // if the widget is hijacked by QGLWindowSurface QTLWExtra *topextra; // only useful for TLWs QGraphicsProxyWidget *proxyWidget; // if the widget is embedded - void *glContext; // if the widget is hijacked by QGLWindowSurface -#if defined(Q_WS_WIN) && !defined(QT_NO_DRAGANDDROP) - QOleDropTarget *dropTarget; // drop target - QList<QPointer<QWidget> > oleDropWidgets; -#endif -#if defined(Q_WS_X11) - WId xDndProxy; // XDND forwarding to embedded windows +#ifndef QT_NO_CURSOR + QCursor *curs; #endif + QPointer<QStyle> style; + QPointer<QWidget> focus_proxy; + + // Implicit pointers (shared_empty/shared_null). QRegion mask; // widget mask + QString styleSheet; + + // Other variables. + qint32 minw; + qint32 minh; // minimum size + qint32 maxw; + qint32 maxh; // maximum size + quint16 customDpiX; + quint16 customDpiY; QSize staticContentsSize; -//bit flags at the end to improve packing -#if defined(Q_WS_WIN) - uint shown_mode : 8; // widget show mode -#endif -#if defined(Q_WS_X11) - uint compress_events : 1; -#endif + // *************************** Cross-platform bit fields **************************** uint explicitMinSize : 2; uint explicitMaxSize : 2; uint autoFillBackground : 1; @@ -188,16 +192,22 @@ struct QWExtra { uint inRenderWithPainter : 1; uint hasMask : 1; - QPointer<QStyle> style; - QString styleSheet; - - quint16 customDpiX; - quint16 customDpiY; -#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + // *************************** Platform specific values (bit fields first) ********** +#if defined(Q_WS_WIN) // <----------------------------------------------------------- WIN +#ifndef QT_NO_DRAGANDDROP + QOleDropTarget *dropTarget; // drop target + QList<QPointer<QWidget> > oleDropWidgets; +#endif +#elif defined(Q_WS_X11) // <--------------------------------------------------------- X11 + uint compress_events : 1; + WId xDndProxy; // XDND forwarding to embedded windows +#elif defined(Q_WS_MAC) // <------------------------------------------------------ MAC +#ifdef QT_MAC_USE_COCOA // Cocoa Mask stuff QImage maskBits; CGImageRef imageMask; #endif +#endif }; class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate @@ -205,6 +215,24 @@ class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QWidget) public: + // *************************** Cross-platform *************************************** + enum DrawWidgetFlags { + DrawAsRoot = 0x01, + DrawPaintOnScreen = 0x02, + DrawRecursive = 0x04, + DrawInvisible = 0x08, + DontSubtractOpaqueChildren = 0x10, + DontSetCompositionMode = 0x20, + DontDrawOpaqueChildren = 0x40 + }; + + enum CloseMode { + CloseNoEvent, + CloseWithEvent, + CloseWithSpontaneousEvent + }; + + // Functions. explicit QWidgetPrivate(int version = QObjectPrivateVersion); ~QWidgetPrivate(); @@ -214,10 +242,6 @@ public: QPainter *sharedPainter() const; void setSharedPainter(QPainter *painter); QWidgetBackingStore *maybeBackingStore() const; -#ifdef Q_WS_QWS - void setMaxWindowState_helper(); - void setFullScreenSize_helper(); -#endif void init(QWidget *desktopWidget, Qt::WindowFlags f); void create_sys(WId window, bool initializeWindow, bool destroyOldWindow); void createRecursively(); @@ -238,24 +262,6 @@ public: QPalette naturalWidgetPalette(uint inheritedMask) const; void setMask_sys(const QRegion &); -#ifdef Q_WS_WIN - bool shouldShowMaximizeButton(); - void winUpdateIsOpaque(); -#endif - -#ifdef Q_WS_MAC - void macUpdateSizeAttribute(); - void macUpdateHideOnSuspend(); - void macUpdateOpaqueSizeGrip(); - void macUpdateIgnoreMouseEvents(); - void macUpdateMetalAttribute(); - void macUpdateIsOpaque(); - void setEnabled_helper_sys(bool enable); - bool isRealWindow() const; - void adjustWithinMaxAndMinSize(int &w, int &h); - void applyMaxAndMinSizeOnWindow(); -#endif - void raise_sys(); void lower_sys(); void stackUnder_sys(QWidget *); @@ -280,20 +286,9 @@ public: void setStyle_helper(QStyle *newStyle, bool propagate, bool metalHack = false); void inheritStyle(); - bool isBackgroundInherited() const; - void setUpdatesEnabled_helper(bool ); void paintBackground(QPainter *, const QRegion &, const QPoint & = QPoint(), int flags = DrawAsRoot) const; - enum DrawWidgetFlags { - DrawAsRoot = 0x01, - DrawPaintOnScreen = 0x02, - DrawRecursive = 0x04, - DrawInvisible = 0x08, - DontSubtractOpaqueChildren = 0x10, - DontSetCompositionMode = 0x20, - DontDrawOpaqueChildren = 0x40 - }; bool isAboutToShow() const; QRegion prepareToRender(const QRegion ®ion, QWidget::RenderFlags renderFlags); void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, @@ -316,10 +311,6 @@ public: QWindowSurface *createDefaultWindowSurface(); QWindowSurface *createDefaultWindowSurface_sys(); void repaint_sys(const QRegion &rgn); -#ifdef Q_WS_MAC - void update_sys(const QRect &rect); - void update_sys(const QRegion &rgn); -#endif QRect clipRect() const; QRegion clipRegion() const; @@ -330,42 +321,20 @@ public: void updateIsOpaque(); void setOpaque(bool opaque); void updateIsTranslucent(); - bool hasBackground() const; bool paintOnScreen() const; QRegion getOpaqueRegion() const; const QRegion &getOpaqueChildren() const; void setDirtyOpaqueRegion(); - QRegion opaqueChildren; - - enum CloseMode { - CloseNoEvent, - CloseWithEvent, - CloseWithSpontaneousEvent - }; bool close_helper(CloseMode mode); - bool compositeEvent(QEvent *e); void setWindowIcon_helper(); void setWindowIcon_sys(bool forceReset = false); void setWindowOpacity_sys(qreal opacity); - void adjustQuitOnCloseAttribute(); -#if defined(Q_WS_X11) - void setWindowRole(); - void sendStartupMessage(const char *message) const; - void setNetWmWindowTypes(); - void x11UpdateIsOpaque(); -#endif - -#if defined (Q_WS_WIN) - void reparentChildren(); -#endif - void scrollChildren(int dx, int dy); - void moveRect(const QRect &, int dx, int dy); void scrollRect(const QRect &, int dx, int dy); void invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize); @@ -379,7 +348,6 @@ public: void reparentFocusWidgets(QWidget *oldtlw); static int pointToRect(const QPoint &p, const QRect &r); - QRect fromOrToLayoutItemRect(const QRect &rect, int sign) const; void setWinId(WId); void showChildren(bool spontaneous); @@ -389,9 +357,6 @@ public: void scroll_sys(int dx, int dy, const QRect &r); void deactivateWidgetCleanup(); void setGeometry_sys(int, int, int, int, bool); -#ifdef Q_WS_MAC - void setGeometry_sys_helper(int, int, int, int, bool); -#endif void sendPendingMoveAndResizeEvents(bool recursive = false, bool disableUpdates = false); void activateChildLayoutsRecursively(); void show_recursive(); @@ -403,10 +368,6 @@ public: void setEnabled_helper(bool); void registerDropSite(bool); -#if defined(Q_WS_WIN) && !defined(QT_NO_DRAGANDDROP) - QOleDropTarget *registerOleDnd(QWidget *widget); - void unregisterOleDnd(QWidget *widget, QOleDropTarget *target); -#endif static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0); void updateFrameStrut(); @@ -416,32 +377,11 @@ public: void setWindowIconText_helper(const QString &cap); void setWindowTitle_sys(const QString &cap); -#ifdef Q_OS_WIN - void grabMouseWhileInWindow(); -#endif - #ifndef QT_NO_CURSOR void setCursor_sys(const QCursor &cursor); void unsetCursor_sys(); #endif -#ifdef Q_WS_MAC - void setWindowModified_sys(bool b); - void updateMaximizeButton_sys(); - void setWindowFilePath_sys(const QString &filePath); - void createWindow_sys(); - void recreateMacWindow(); -#ifndef QT_MAC_USE_COCOA - void initWindowPtr(); - void finishCreateWindow_sys_Carbon(OSWindowRef windowRef); -#else - void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef); - void syncCocoaMask(); - void finishCocoaMaskSetup(); -#endif - void determineWindowClass(); - void transferChildren(); -#endif void setWindowTitle_helper(const QString &cap); void setWindowFilePath_helper(const QString &filePath); @@ -457,59 +397,89 @@ public: QInputContext *inputContext() const; -#if defined(Q_WS_QWS) - void moveSurface(QWindowSurface *surface, const QPoint &offset); + void setModal_sys(); - QRegion localRequestedRegion() const; - QRegion localAllocatedRegion() const; + inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) + { + Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); + redirectDev = replacement; + redirectOffset = offset; + } - void blitToScreen(const QRegion &globalrgn); -#ifndef QT_NO_CURSOR - void updateCursor() const; -#endif + inline QPaintDevice *redirected(QPoint *offset) const + { + if (offset) + *offset = redirectDev ? redirectOffset : QPoint(); + return redirectDev; + } - QScreen* getScreen() const; + inline void restoreRedirected() + { redirectDev = 0; } - friend class QWSManager; - friend class QWSManagerPrivate; - friend class QDecoration; -#endif + inline void enforceNativeChildren() + { + if (!extra) + createExtra(); - static int instanceCounter; // Current number of widget instances - static int maxInstances; // Maximum number of widget instances + if (extra->nativeChildrenForced) + return; + extra->nativeChildrenForced = 1; -#ifdef QT_KEYPAD_NAVIGATION - static QPointer<QWidget> editingWidget; -#endif + for (int i = 0; i < children.size(); ++i) { + if (QWidget *child = qobject_cast<QWidget *>(children.at(i))) + child->setAttribute(Qt::WA_NativeWindow); + } + } - QWidgetData data; + inline bool nativeChildrenForced() const + { + return extra ? extra->nativeChildrenForced : false; + } + + QSize adjustedSize() const; + +#ifndef Q_WS_QWS // Almost cross-platform :-) + void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); + + inline QPoint mapToWS(const QPoint &p) const + { return p - data.wrect.topLeft(); } + + inline QPoint mapFromWS(const QPoint &p) const + { return p + data.wrect.topLeft(); } + + inline QRect mapToWS(const QRect &r) const + { QRect rr(r); rr.translate(-data.wrect.topLeft()); return rr; } + + inline QRect mapFromWS(const QRect &r) const + { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; } +#endif + // Variables. + // Regular pointers (keep them together to avoid gaps on 64 bit architectures). QWExtra *extra; QWidget *focus_next; QWidget *focus_prev; QWidget *focus_child; -#ifndef QT_NO_ACTION - QList<QAction*> actions; -#endif QLayout *layout; + QRegion *needsFlush; + QPaintDevice *redirectDev; QWidgetItemV2 *widgetItem; -#if !defined(QT_NO_IM) - QPointer<QInputContext> ic; -#endif + QPaintEngine *extraPaintEngine; + mutable const QMetaObject *polished; // All widgets are initially added into the uncreatedWidgets set. Once // they receive a window id they are removed and added to the mapper static QWidgetMapper *mapper; static QWidgetSet *uncreatedWidgets; +#if !defined(QT_NO_IM) + QPointer<QInputContext> ic; +#endif +#ifdef QT_KEYPAD_NAVIGATION + static QPointer<QWidget> editingWidget; +#endif - short leftmargin, topmargin, rightmargin, bottommargin; - - signed char leftLayoutItemMargin; - signed char topLayoutItemMargin; - signed char rightLayoutItemMargin; - signed char bottomLayoutItemMargin; - - // ### TODO: reorganize private/extra/topextra to save memory - QPointer<QWidget> compositeChildGrab; + // Implicit pointers (shared_null/shared_empty). + QRegion opaqueChildren; + QRegion dirty; #ifndef QT_NO_TOOLTIP QString toolTip; #endif @@ -519,14 +489,37 @@ public: #ifndef QT_NO_WHATSTHIS QString whatsThis; #endif - QString accessibleName, accessibleDescription; +#ifndef QT_NO_ACCESSIBILITY + QString accessibleName; + QString accessibleDescription; +#endif + + // Other variables. + uint inheritedFontResolveMask; + uint inheritedPaletteResolveMask; + short leftmargin; + short topmargin; + short rightmargin; + short bottommargin; + signed char leftLayoutItemMargin; + signed char topLayoutItemMargin; + signed char rightLayoutItemMargin; + signed char bottomLayoutItemMargin; + static int instanceCounter; // Current number of widget instances + static int maxInstances; // Maximum number of widget instances + Qt::HANDLE hd; + QWidgetData data; + QSizePolicy size_policy; + QLocale locale; + QPoint redirectOffset; +#ifndef QT_NO_ACTION + QList<QAction*> actions; +#endif + // Bit fields. + uint high_attributes[3]; // the low ones are in QWidget::widget_attributes QPalette::ColorRole fg_role : 8; QPalette::ColorRole bg_role : 8; - uint high_attributes[3]; // the low ones are in QWidget::widget_attributes - Qt::HANDLE hd; - QRegion dirty; - QRegion *needsFlush; uint dirtyOpaqueChildren : 1; uint isOpaque : 1; uint inDirtyList : 1; @@ -534,35 +527,33 @@ public: uint isMoved : 1; uint usesDoubleBufferedGLContext : 1; -#ifdef Q_WS_WIN - uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() -#endif - - uint inheritedFontResolveMask; - uint inheritedPaletteResolveMask; -#if defined(Q_WS_X11) + // *************************** Platform specific ************************************ +#if defined(Q_WS_X11) // <----------------------------------------------------------- X11 QX11Info xinfo; Qt::HANDLE picture; + static QWidget *mouseGrabber; + static QWidget *keyboardGrabber; + + void setWindowRole(); + void sendStartupMessage(const char *message) const; + void setNetWmWindowTypes(); + void x11UpdateIsOpaque(); + bool isBackgroundInherited() const; +#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() + + bool shouldShowMaximizeButton(); + void winUpdateIsOpaque(); + void reparentChildren(); +#ifndef QT_NO_DRAGANDDROP + QOleDropTarget *registerOleDnd(QWidget *widget); + void unregisterOleDnd(QWidget *widget, QOleDropTarget *target); #endif -#if defined(Q_WS_MAC) - enum PaintChildrenOPs { - PC_None = 0x00, - PC_Now = 0x01, - PC_NoPaint = 0x04, - PC_Later = 0x10 - }; - EventHandlerRef window_event; - bool qt_mac_dnd_event(uint, DragRef); - void toggleDrawers(bool); - //mac event functions - static bool qt_create_root_win(); - static void qt_clean_root_win(); - static bool qt_recreate_root_win(); - static bool qt_mac_update_sizer(QWidget *, int up = 0); - static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *); - static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *); - static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool); - static bool qt_widget_shape(QWidget *, short, HIMutableShapeRef, bool); + void grabMouseWhileInWindow(); +#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC + // This is new stuff + uint needWindowChange : 1; + uint isGLWidget : 1; // Each wiget keeps a list of all its child and grandchild OpenGL widgets. // This list is used to update the gl context whenever a parent and a granparent @@ -575,95 +566,70 @@ public: QWidget * widget; QWidget * lastUpdateWidget; }; - QList<GlWidgetInfo> glWidgets; // dirtyOnWidget contains the areas in the widget that needs to be repained, // in the same way as dirtyOnScreen does for the window. Areas are added in // dirtyWidget_sys and cleared in the paint event. In scroll_sys we then use // this information repaint invalid areas when widgets are scrolled. QRegion dirtyOnWidget; + EventHandlerRef window_event; + QList<GlWidgetInfo> glWidgets; //these are here just for code compat (HIViews) Qt::HANDLE qd_hd; - // This is new stuff - uint needWindowChange : 1; - uint isGLWidget : 1; -#endif - -#if defined(Q_WS_X11) || defined (Q_WS_WIN) || defined(Q_WS_MAC) -#ifdef Q_WS_MAC - void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); + void macUpdateSizeAttribute(); + void macUpdateHideOnSuspend(); + void macUpdateOpaqueSizeGrip(); + void macUpdateIgnoreMouseEvents(); + void macUpdateMetalAttribute(); + void macUpdateIsOpaque(); + void setEnabled_helper_sys(bool enable); + bool isRealWindow() const; + void adjustWithinMaxAndMinSize(int &w, int &h); + void applyMaxAndMinSizeOnWindow(); + void update_sys(const QRect &rect); + void update_sys(const QRegion &rgn); + void setGeometry_sys_helper(int, int, int, int, bool); + void setWindowModified_sys(bool b); + void updateMaximizeButton_sys(); + void setWindowFilePath_sys(const QString &filePath); + void createWindow_sys(); + void recreateMacWindow(); +#ifndef QT_MAC_USE_COCOA + void initWindowPtr(); + void finishCreateWindow_sys_Carbon(OSWindowRef windowRef); #else - void setWSGeometry(bool dontShow=false); + void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef); + void syncCocoaMask(); + void finishCocoaMaskSetup(); #endif + void determineWindowClass(); + void transferChildren(); + bool qt_mac_dnd_event(uint, DragRef); + void toggleDrawers(bool); + //mac event functions + static bool qt_create_root_win(); + static void qt_clean_root_win(); + static bool qt_mac_update_sizer(QWidget *, int up = 0); + static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *); + static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *); + static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool); +#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS + void setMaxWindowState_helper(); + void setFullScreenSize_helper(); + void moveSurface(QWindowSurface *surface, const QPoint &offset); + QRegion localRequestedRegion() const; + QRegion localAllocatedRegion() const; - inline QPoint mapToWS(const QPoint &p) const - { return p - data.wrect.topLeft(); } - - inline QPoint mapFromWS(const QPoint &p) const - { return p + data.wrect.topLeft(); } - - inline QRect mapToWS(const QRect &r) const - { QRect rr(r); rr.translate(-data.wrect.topLeft()); return rr; } - - inline QRect mapFromWS(const QRect &r) const - { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; } + friend class QWSManager; + friend class QWSManagerPrivate; + friend class QDecoration; +#ifndef QT_NO_CURSOR + void updateCursor() const; #endif - - QPaintEngine *extraPaintEngine; - - mutable const QMetaObject *polished; - - void setModal_sys(); - QSizePolicy size_policy; - QLocale locale; - -#ifdef Q_WS_X11 - static QWidget *mouseGrabber; - static QWidget *keyboardGrabber; + QScreen* getScreen() const; #endif - QPaintDevice *redirectDev; - QPoint redirectOffset; - - inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) - { - Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); - redirectDev = replacement; - redirectOffset = offset; - } - - inline QPaintDevice *redirected(QPoint *offset) const - { - if (offset) - *offset = redirectDev ? redirectOffset : QPoint(); - return redirectDev; - } - - inline void restoreRedirected() - { redirectDev = 0; } - - inline void enforceNativeChildren() - { - if (!extra) - createExtra(); - - if (extra->nativeChildrenForced) - return; - extra->nativeChildrenForced = 1; - - for (int i = 0; i < children.size(); ++i) { - if (QWidget *child = qobject_cast<QWidget *>(children.at(i))) - child->setAttribute(Qt::WA_NativeWindow); - } - } - - inline bool nativeChildrenForced() const - { - return extra ? extra->nativeChildrenForced : false; - } - - QSize adjustedSize() const; }; inline QWExtra *QWidgetPrivate::extraData() const diff --git a/src/gui/kernel/qwidget_qws.cpp b/src/gui/kernel/qwidget_qws.cpp index 1445f57..94bdb85 100644 --- a/src/gui/kernel/qwidget_qws.cpp +++ b/src/gui/kernel/qwidget_qws.cpp @@ -565,20 +565,6 @@ void QWidget::activateWindow() } } -/* - Should we require that q is a toplevel window ??? - - Used by QWSManager - */ -void QWidgetPrivate::blitToScreen(const QRegion &globalrgn) -{ - Q_Q(QWidget); - QWidget *win = q->window(); - QBrush bgBrush = win->palette().brush(win->backgroundRole()); - bool opaque = bgBrush.style() == Qt::NoBrush || bgBrush.isOpaque(); - QWidget::qwsDisplay()->repaintRegion(win->data->winid, win->windowFlags(), opaque, globalrgn); -} - void QWidgetPrivate::show_sys() { Q_Q(QWidget); @@ -1037,6 +1023,9 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { +#ifndef QT_NO_QWS_MANAGER + extra->topextra->qwsManager = 0; +#endif } void QWidgetPrivate::deleteTLSysExtra() diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index cfdabaf..0f341fd 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -1025,13 +1025,13 @@ void QWidget::setWindowState(Qt::WindowStates newstate) if (newstate & Qt::WindowFullScreen) { if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized)) d->topData()->normalGeometry = geometry(); - d->topData()->savedFlags = GetWindowLongA(internalWinId(), GWL_STYLE); + d->topData()->savedFlags = Qt::WindowFlags(GetWindowLongA(internalWinId(), GWL_STYLE)); #ifndef Q_FLATTEN_EXPOSE UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; #else UINT style = WS_POPUP; #endif - if (d->topData()->savedFlags & WS_SYSMENU) + if (ulong(d->topData()->savedFlags) & WS_SYSMENU) style |= WS_SYSMENU; if (isVisible()) style |= WS_VISIBLE; @@ -1234,7 +1234,7 @@ void QWidgetPrivate::stackUnder_sys(QWidget* w) (In all comments below: s/X/Windows/g) */ -void QWidgetPrivate::setWSGeometry(bool dontShow) +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); @@ -1704,7 +1704,6 @@ int QWidget::metric(PaintDeviceMetric m) const return val; } -#ifndef Q_WS_WINCE void QWidgetPrivate::createSysExtra() { #ifndef QT_NO_DRAGANDDROP @@ -1712,6 +1711,7 @@ void QWidgetPrivate::createSysExtra() #endif } +#ifndef Q_WS_WINCE void QWidgetPrivate::deleteSysExtra() { } @@ -1719,8 +1719,9 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { - extra->topextra->winIconSmall = 0; + extra->topextra->savedFlags = 0; extra->topextra->winIconBig = 0; + extra->topextra->winIconSmall = 0; } void QWidgetPrivate::deleteTLSysExtra() diff --git a/src/gui/kernel/qwidget_wince.cpp b/src/gui/kernel/qwidget_wince.cpp index cca928e..435fd31 100644 --- a/src/gui/kernel/qwidget_wince.cpp +++ b/src/gui/kernel/qwidget_wince.cpp @@ -535,7 +535,7 @@ void QWidget::setWindowState(Qt::WindowStates newstate) if (newstate & Qt::WindowFullScreen) { if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized)) d->topData()->normalGeometry = geometry(); - d->topData()->savedFlags = GetWindowLongA(internalWinId(), GWL_STYLE); + d->topData()->savedFlags = (Qt::WindowFlags) GetWindowLongA(internalWinId(), GWL_STYLE); UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; if (isVisible()) style |= WS_VISIBLE; @@ -598,13 +598,6 @@ void QWidget::setWindowState(Qt::WindowStates newstate) QApplication::sendEvent(this, &e); } - -void QWidgetPrivate::createSysExtra() { -#ifndef QT_NO_DRAGANDDROP - extra->dropTarget = 0; -#endif -} - void QWidgetPrivate::deleteSysExtra() { Q_Q(QWidget); diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index 6202b35..b35740a 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -906,6 +906,44 @@ void QWidgetPrivate::x11UpdateIsOpaque() #endif } +/* + Returns true if the background is inherited; otherwise returns + false. + + Mainly used in the paintOnScreen case. +*/ +bool QWidgetPrivate::isBackgroundInherited() const +{ + Q_Q(const QWidget); + + // windows do not inherit their background + if (q->isWindow() || q->windowType() == Qt::SubWindow) + return false; + + if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent)) + return false; + + const QPalette &pal = q->palette(); + QPalette::ColorRole bg = q->backgroundRole(); + QBrush brush = pal.brush(bg); + + // non opaque brushes leaves us no choice, we must inherit + if (!q->autoFillBackground() || !brush.isOpaque()) + return true; + + if (brush.style() == Qt::SolidPattern) { + // the background is just a solid color. If there is no + // propagated contents, then we claim as performance + // optimization that it was not inheritet. This is the normal + // case in standard Windows or Motif style. + const QWidget *w = q->parentWidget(); + if (!w->d_func()->isBackgroundInherited()) + return false; + } + + return true; +} + void QWidget::destroy(bool destroyWindow, bool destroySubWindows) { Q_D(QWidget); @@ -2152,7 +2190,7 @@ static void do_size_hints(QWidget* widget, QWExtra *x) parentWRect is the geometry of the parent's X rect, measured in parent's coord sys */ -void QWidgetPrivate::setWSGeometry(bool dontShow) +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); @@ -2610,8 +2648,8 @@ int QWidget::metric(PaintDeviceMetric m) const void QWidgetPrivate::createSysExtra() { - extra->xDndProxy = 0; extra->compress_events = true; + extra->xDndProxy = 0; } void QWidgetPrivate::deleteSysExtra() @@ -2620,8 +2658,11 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { + extra->topextra->spont_unmapped = 0; + extra->topextra->dnd = 0; extra->topextra->validWMState = 0; extra->topextra->waitingForMapNotify = 0; + extra->topextra->parentWinId = 0; extra->topextra->userTimeWindow = 0; } diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 24d167e..534a425 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -1369,7 +1369,7 @@ QColor QColor::toRgb() const */ QColor QColor::toHsv() const { - if (!isValid()) + if (!isValid() || cspec == Hsv) return *this; if (cspec != Rgb) @@ -1421,7 +1421,7 @@ QColor QColor::toHsv() const */ QColor QColor::toCmyk() const { - if (!isValid()) + if (!isValid() || cspec == Cmyk) return *this; if (cspec != Rgb) return toRgb().toCmyk(); diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp index 3397c45..175f1ab 100644 --- a/src/gui/painting/qemulationpaintengine.cpp +++ b/src/gui/painting/qemulationpaintengine.cpp @@ -123,14 +123,30 @@ void QEmulationPaintEngine::stroke(const QVectorPath &path, const QPen &pen) real_engine->stroke(path, bgPen); } - QBrush brush = pen.brush(); + QPen copy = pen; Qt::BrushStyle style = qbrush_style(brush); if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { const QGradient *g = brush.gradient(); + if (g->coordinateMode() > QGradient::LogicalMode) { - QPaintEngineEx::stroke(path, pen); - return; + if (g->coordinateMode() == QGradient::StretchToDeviceMode) { + QTransform mat = brush.transform(); + mat.scale(real_engine->painter()->device()->width(), real_engine->painter()->device()->height()); + brush.setTransform(mat); + copy.setBrush(brush); + real_engine->stroke(path, copy); + return; + } else if (g->coordinateMode() == QGradient::ObjectBoundingMode) { + QTransform mat = brush.transform(); + QRealRect r = path.controlPointRect(); + mat.translate(r.x1, r.y1); + mat.scale(r.x2 - r.x1, r.y2 - r.y1); + brush.setTransform(mat); + copy.setBrush(brush); + real_engine->stroke(path, copy); + return; + } } } diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 1ea40ba..3fd1ffb 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -88,11 +88,12 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, ti.ascent.toReal(), ti.descent.toReal()); #endif - int glyph_width = metrics.width.ceil().toInt() + margin * 2; - int glyph_height = metrics.height.ceil().toInt() + margin * 2; + int glyph_width = metrics.width.ceil().toInt(); + int glyph_height = metrics.height.ceil().toInt(); if (glyph_height == 0 || glyph_width == 0) continue; - + glyph_width += margin * 2 + 2; + glyph_height += margin * 2 + 2; // align to 8-bit boundary if (m_type == QFontEngineGlyphCache::Raster_Mono) glyph_width = (glyph_width+7)&~7; @@ -188,11 +189,7 @@ void QImageTextureGlyphCache::createTextureData(int width, int height) int QImageTextureGlyphCache::glyphMargin() const { -#ifdef Q_WS_MAC return 2; -#else - return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; -#endif } void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g) diff --git a/src/gui/statemachine/qbasickeyeventtransition.cpp b/src/gui/statemachine/qbasickeyeventtransition.cpp index 7821feb..7f515cd 100644 --- a/src/gui/statemachine/qbasickeyeventtransition.cpp +++ b/src/gui/statemachine/qbasickeyeventtransition.cpp @@ -25,6 +25,8 @@ QT_BEGIN_NAMESPACE /*! \internal \class QBasicKeyEventTransition + \since 4.6 + \ingroup statemachine \brief The QBasicKeyEventTransition class provides a transition for Qt key events. */ @@ -156,7 +158,7 @@ void QBasicKeyEventTransition::setModifiersMask(Qt::KeyboardModifiers modifiersM /*! \reimp */ -bool QBasicKeyEventTransition::eventTest(QEvent *event) const +bool QBasicKeyEventTransition::eventTest(QEvent *event) { Q_D(const QBasicKeyEventTransition); if (event->type() == d->eventType) { diff --git a/src/gui/statemachine/qbasickeyeventtransition_p.h b/src/gui/statemachine/qbasickeyeventtransition_p.h index 0d08da0..7506747 100644 --- a/src/gui/statemachine/qbasickeyeventtransition_p.h +++ b/src/gui/statemachine/qbasickeyeventtransition_p.h @@ -55,7 +55,7 @@ public: void setModifiersMask(Qt::KeyboardModifiers modifiers); protected: - bool eventTest(QEvent *event) const; + bool eventTest(QEvent *event); void onTransition(QEvent *); private: diff --git a/src/gui/statemachine/qbasicmouseeventtransition.cpp b/src/gui/statemachine/qbasicmouseeventtransition.cpp index 0cb727e..42b7580 100644 --- a/src/gui/statemachine/qbasicmouseeventtransition.cpp +++ b/src/gui/statemachine/qbasicmouseeventtransition.cpp @@ -25,6 +25,8 @@ QT_BEGIN_NAMESPACE /*! \internal \class QBasicMouseEventTransition + \since 4.6 + \ingroup statemachine \brief The QBasicMouseEventTransition class provides a transition for Qt mouse events. */ @@ -159,7 +161,7 @@ void QBasicMouseEventTransition::setPath(const QPainterPath &path) /*! \reimp */ -bool QBasicMouseEventTransition::eventTest(QEvent *event) const +bool QBasicMouseEventTransition::eventTest(QEvent *event) { Q_D(const QBasicMouseEventTransition); if (event->type() == d->eventType) { diff --git a/src/gui/statemachine/qbasicmouseeventtransition_p.h b/src/gui/statemachine/qbasicmouseeventtransition_p.h index 20c7f8f..57f83c6 100644 --- a/src/gui/statemachine/qbasicmouseeventtransition_p.h +++ b/src/gui/statemachine/qbasicmouseeventtransition_p.h @@ -58,7 +58,7 @@ public: void setPath(const QPainterPath &path); protected: - bool eventTest(QEvent *event) const; + bool eventTest(QEvent *event); void onTransition(QEvent *); private: diff --git a/src/gui/statemachine/qguistatemachine.cpp b/src/gui/statemachine/qguistatemachine.cpp index d30265a..b7563d7 100644 --- a/src/gui/statemachine/qguistatemachine.cpp +++ b/src/gui/statemachine/qguistatemachine.cpp @@ -9,13 +9,8 @@ ** ****************************************************************************/ -#ifdef QT_STATEMACHINE_SOLUTION -#include "qstatemachine.h" -#include "qstatemachine_p.h" -#else #include <QtCore/qstatemachine.h> #include <private/qstatemachine_p.h> -#endif #include <QtGui/qevent.h> #include <QtGui/qgraphicssceneevent.h> diff --git a/src/gui/statemachine/qkeyeventtransition.cpp b/src/gui/statemachine/qkeyeventtransition.cpp index e6ab11b..3cf51a3 100644 --- a/src/gui/statemachine/qkeyeventtransition.cpp +++ b/src/gui/statemachine/qkeyeventtransition.cpp @@ -140,7 +140,7 @@ void QKeyEventTransition::setModifiersMask(Qt::KeyboardModifiers modifiersMask) /*! \reimp */ -bool QKeyEventTransition::eventTest(QEvent *event) const +bool QKeyEventTransition::eventTest(QEvent *event) { Q_D(const QKeyEventTransition); if (!QEventTransition::eventTest(event)) diff --git a/src/gui/statemachine/qkeyeventtransition.h b/src/gui/statemachine/qkeyeventtransition.h index 3f797f1..08595e8 100644 --- a/src/gui/statemachine/qkeyeventtransition.h +++ b/src/gui/statemachine/qkeyeventtransition.h @@ -46,7 +46,7 @@ public: protected: void onTransition(QEvent *event); - bool eventTest(QEvent *event) const; + bool eventTest(QEvent *event); private: Q_DISABLE_COPY(QKeyEventTransition) diff --git a/src/gui/statemachine/qmouseeventtransition.cpp b/src/gui/statemachine/qmouseeventtransition.cpp index 3191a2f..5ffdab0 100644 --- a/src/gui/statemachine/qmouseeventtransition.cpp +++ b/src/gui/statemachine/qmouseeventtransition.cpp @@ -170,7 +170,7 @@ void QMouseEventTransition::setPath(const QPainterPath &path) /*! \reimp */ -bool QMouseEventTransition::eventTest(QEvent *event) const +bool QMouseEventTransition::eventTest(QEvent *event) { Q_D(const QMouseEventTransition); if (!QEventTransition::eventTest(event)) diff --git a/src/gui/statemachine/qmouseeventtransition.h b/src/gui/statemachine/qmouseeventtransition.h index eee971e..e878a58 100644 --- a/src/gui/statemachine/qmouseeventtransition.h +++ b/src/gui/statemachine/qmouseeventtransition.h @@ -52,7 +52,7 @@ public: protected: void onTransition(QEvent *event); - bool eventTest(QEvent *event) const; + bool eventTest(QEvent *event); private: Q_DISABLE_COPY(QMouseEventTransition) diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index c0899f8..6972803 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -1664,6 +1664,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (!styleHint(SH_UnderlineShortcut, opt, widget)) alignment |= Qt::TextHideMnemonic; rect.translate(shiftX, shiftY); + p->setFont(toolbutton->font); drawItemText(p, rect, alignment, toolbutton->palette, opt->state & State_Enabled, toolbutton->text, QPalette::ButtonText); diff --git a/src/gui/styles/qmotifstyle.cpp b/src/gui/styles/qmotifstyle.cpp index 7d4fab8..be0e3eb 100644 --- a/src/gui/styles/qmotifstyle.cpp +++ b/src/gui/styles/qmotifstyle.cpp @@ -2026,10 +2026,6 @@ QMotifStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, QSize sz(contentsSize); switch(ct) { - case CT_Splitter: - sz = QSize(10, 10); - break; - case CT_RadioButton: case CT_CheckBox: sz = QCommonStyle::sizeFromContents(ct, opt, contentsSize, widget); diff --git a/src/gui/styles/qstyle.cpp b/src/gui/styles/qstyle.cpp index 7ccac85..de4b5a3 100644 --- a/src/gui/styles/qstyle.cpp +++ b/src/gui/styles/qstyle.cpp @@ -1333,7 +1333,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value PM_LayoutVerticalSpacing Default \l{QLayout::spacing}{vertical spacing} for a QLayout. \value PM_MaximumDragDistance The maximum allowed distance between - the mouse and a slider when dragging. Exceeding the specified + the mouse and a scrollbar when dragging. Exceeding the specified distance will cause the slider to jump back to the original position; a value of -1 disables this behavior. diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index dcc11b8..cd44bfd 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -3030,6 +3030,7 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC if (const QStyleOptionToolButton *tool = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) { QStyleOptionToolButton toolOpt(*tool); rule.configurePalette(&toolOpt.palette, QPalette::ButtonText, QPalette::Button); + toolOpt.font = rule.font.resolve(toolOpt.font); toolOpt.rect = rule.borderRect(opt->rect); bool customArrow = (tool->features & (QStyleOptionToolButton::HasMenu | QStyleOptionToolButton::MenuButtonPopup)); bool customDropDown = tool->features & QStyleOptionToolButton::MenuButtonPopup; diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp index 639eff0..3dac9f5 100644 --- a/src/gui/styles/qwindowsxpstyle.cpp +++ b/src/gui/styles/qwindowsxpstyle.cpp @@ -1792,7 +1792,12 @@ case PE_Frame: return; case PE_IndicatorToolBarSeparator: - + if (option->rect.height() < 3) { + // XP style requires a few pixels for the separator + // to be visible. + QWindowsStyle::drawPrimitive(pe, option, p, widget); + return; + } name = QLatin1String("TOOLBAR"); partId = TP_SEPARATOR; diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 7a236fd..6f5ee1f 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -613,7 +613,7 @@ QFontEngineFT::QFontEngineFT(const QFontDef &fd) subpixelType = Subpixel_None; lcdFilterType = 0; #if defined(FT_LCD_FILTER_H) - lcdFilterType = (int) FT_LCD_FILTER_DEFAULT; + lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT); #endif defaultFormat = Format_None; canUploadGlyphsToServer = false; diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp index 6551e87..feea1f2 100644 --- a/src/gui/text/qfontengine_win.cpp +++ b/src/gui/text/qfontengine_win.cpp @@ -1406,8 +1406,8 @@ QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin #endif #endif - QNativeImage *ni = new QNativeImage(iw + 2 * margin, - ih + 2 * margin, + QNativeImage *ni = new QNativeImage(iw + 2 * margin + 2, + ih + 2 * margin + 2, QNativeImage::systemFormat(), true); ni->image.fill(0xffffffff); @@ -1449,7 +1449,7 @@ QImage QFontEngineWin::alphaMapForGlyph(glyph_t glyph, const QTransform &xform) font = CreateFontIndirectW(&lf); } - QNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform); + QNativeImage *mask = drawGDIGlyph(font, glyph, 2, xform); if (mask == 0) return QImage(); diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index 9886969..0d8b4de 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -873,21 +873,22 @@ bool QAbstractScrollArea::event(QEvent *e) case QEvent::Resize: d->layoutChildren(); break; - case QEvent::Paint: + case QEvent::Paint: { + QStyleOption option; + option.initFrom(this); if (d->cornerPaintingRect.isValid()) { - QStyleOption option; option.rect = d->cornerPaintingRect; QPainter p(this); style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this); } #ifdef Q_WS_MAC if (d->reverseCornerPaintingRect.isValid()) { - QStyleOption option; option.rect = d->reverseCornerPaintingRect; QPainter p(this); style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this); } #endif + } QFrame::paintEvent((QPaintEvent*)e); break; #ifndef QT_NO_CONTEXTMENU diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp index 347f89a..d640c70 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -193,6 +193,7 @@ void QAbstractSpinBox::setButtonSymbols(ButtonSymbols buttonSymbols) Q_D(QAbstractSpinBox); if (d->buttonSymbols != buttonSymbols) { d->buttonSymbols = buttonSymbols; + d->updateEditFieldGeometry(); update(); } } diff --git a/src/gui/widgets/qmenu_wince.cpp b/src/gui/widgets/qmenu_wince.cpp index 0befa6d..2ce89f9 100644 --- a/src/gui/widgets/qmenu_wince.cpp +++ b/src/gui/widgets/qmenu_wince.cpp @@ -214,7 +214,7 @@ static HWND qt_wce_create_menubar(HWND parentHandle, HINSTANCE resourceHandle, i mbi.nToolBarId = toolbarID; if (ptrCreateMenuBar(&mbi)) { -#ifdef Q_WS_WINCE_WM +#ifdef Q_OS_WINCE_WM // Tell the menu bar that we want to override hot key behaviour. LPARAM lparam = MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY); diff --git a/src/gui/widgets/qslider.cpp b/src/gui/widgets/qslider.cpp index 32b9021..5b9c8a4 100644 --- a/src/gui/widgets/qslider.cpp +++ b/src/gui/widgets/qslider.cpp @@ -62,7 +62,6 @@ public: int tickInterval; QSlider::TickPosition tickPosition; int clickOffset; - int snapBackPosition; void init(); void resetLayoutItemMargins(); int pixelPosToRangeValue(int pos) const; @@ -493,7 +492,6 @@ void QSlider::mousePressEvent(QMouseEvent *ev) setRepeatAction(SliderNoAction); QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); d->clickOffset = d->pick(ev->pos() - sr.topLeft()); - d->snapBackPosition = d->position; update(sr); setSliderDown(true); } @@ -513,14 +511,6 @@ void QSlider::mouseMoveEvent(QMouseEvent *ev) int newPosition = d->pixelPosToRangeValue(d->pick(ev->pos()) - d->clickOffset); QStyleOptionSlider opt; initStyleOption(&opt); - int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this); - if (m >= 0) { - QRect r = rect(); - r.adjust(-m, -m, m, m); - if (!r.contains(ev->pos())) { - newPosition = d->snapBackPosition; - } - } setSliderPosition(newPosition); } diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 5940fba..d4bf008 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qhttpnetworkconnection_p.h" +#include "private/qnoncontiguousbytedevice_p.h" #include <private/qnetworkrequest_p.h> #include <private/qobject_p.h> #include <private/qauthenticator_p.h> @@ -71,6 +72,7 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) #endif + { } @@ -205,12 +207,19 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair) // add missing fields for the request QByteArray value; // check if Content-Length is provided - QIODevice *data = request.data(); - if (data && request.contentLength() == -1) { - if (!data->isSequential()) - request.setContentLength(data->size()); - else - bufferData(messagePair); // ### or do chunked upload + QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice(); + if (uploadByteDevice) { + if (request.contentLength() != -1 && uploadByteDevice->size() != -1) { + // both values known, take the smaller one. + request.setContentLength(qMin(uploadByteDevice->size(), request.contentLength())); + } else if (request.contentLength() == -1 && uploadByteDevice->size() != -1) { + // content length not supplied by user, but the upload device knows it + request.setContentLength(uploadByteDevice->size()); + } else if (request.contentLength() != -1 && uploadByteDevice->size() == -1) { + // everything OK, the user supplied us the contentLength + } else if (request.contentLength() == -1 && uploadByteDevice->size() == -1) { + qFatal("QHttpNetworkConnectionPrivate: Neither content-length nor upload device size were given"); + } } // set the Connection/Proxy-Connection: Keep-Alive headers #ifndef QT_NO_NETWORKPROXY @@ -361,18 +370,12 @@ bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket) false); #endif socket->write(header); - QIODevice *data = channels[i].request.d->data; - QHttpNetworkReply *reply = channels[i].reply; - if (reply && reply->d_func()->requestDataBuffer.size()) - data = &channels[i].reply->d_func()->requestDataBuffer; - if (data && (data->isOpen() || data->open(QIODevice::ReadOnly))) { - if (data->isSequential()) { - channels[i].bytesTotal = -1; - QObject::connect(data, SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadNoBuffer())); - QObject::connect(data, SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadNoBuffer())); - } else { - channels[i].bytesTotal = data->size(); - } + QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice(); + if (uploadByteDevice) { + // connect the signals so this function gets called again + QObject::connect(uploadByteDevice, SIGNAL(readyRead()), q, SLOT(_q_uploadDataReadyRead())); + + channels[i].bytesTotal = channels[i].request.contentLength(); } else { channels[i].state = WaitingState; break; @@ -380,30 +383,81 @@ bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket) // write the initial chunk together with the headers // fall through } - case WritingState: { // write the data - QIODevice *data = channels[i].request.d->data; - if (channels[i].reply->d_func()->requestDataBuffer.size()) - data = &channels[i].reply->d_func()->requestDataBuffer; - if (!data || channels[i].bytesTotal == channels[i].written) { + case WritingState: + { + // write the data + QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice(); + if (!uploadByteDevice || channels[i].bytesTotal == channels[i].written) { + if (uploadByteDevice) + emit channels[i].reply->dataSendProgress(channels[i].written, channels[i].bytesTotal); channels[i].state = WaitingState; // now wait for response + sendRequest(socket); break; } - QByteArray chunk; - chunk.resize(ChunkSize); - qint64 readSize = data->read(chunk.data(), ChunkSize); - if (readSize == -1) { - // source has reached EOF - channels[i].state = WaitingState; // now wait for response - } else if (readSize > 0) { - // source gave us something useful - channels[i].written += socket->write(chunk.data(), readSize); - if (channels[i].reply) - emit channels[i].reply->dataSendProgress(channels[i].written, channels[i].bytesTotal); + // only feed the QTcpSocket buffer when there is less than 32 kB in it + const qint64 socketBufferFill = 32*1024; + const qint64 socketWriteMaxSize = 16*1024; + + +#ifndef QT_NO_OPENSSL + QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket); + while ((sslSocket->encryptedBytesToWrite() + sslSocket->bytesToWrite()) <= socketBufferFill + && channels[i].bytesTotal != channels[i].written) +#else + while (socket->bytesToWrite() <= socketBufferFill + && channels[i].bytesTotal != channels[i].written) +#endif + { + // get pointer to upload data + qint64 currentReadSize; + qint64 desiredReadSize = qMin(socketWriteMaxSize, channels[i].bytesTotal - channels[i].written); + const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize); + + if (currentReadSize == -1) { + // premature eof happened + emitReplyError(socket, channels[i].reply, QNetworkReply::UnknownNetworkError); + return false; + break; + } else if (readPointer == 0 || currentReadSize == 0) { + // nothing to read currently, break the loop + break; + } else { + qint64 currentWriteSize = socket->write(readPointer, currentReadSize); + if (currentWriteSize == -1 || currentWriteSize != currentReadSize) { + // socket broke down + emitReplyError(socket, channels[i].reply, QNetworkReply::UnknownNetworkError); + return false; + } else { + channels[i].written += currentWriteSize; + uploadByteDevice->advanceReadPointer(currentWriteSize); + + emit channels[i].reply->dataSendProgress(channels[i].written, channels[i].bytesTotal); + + if (channels[i].written == channels[i].bytesTotal) { + // make sure this function is called once again + channels[i].state = WaitingState; + sendRequest(socket); + break; + } + } + } } break; } + case WaitingState: + { + QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice(); + if (uploadByteDevice) { + QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), q, SLOT(_q_uploadDataReadyRead())); + } + // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called + // this is needed if the sends an reply before we have finished sending the request. In that + // case receiveReply had been called before but ignored the server reply + receiveReply(socket, channels[i].reply); + break; + } case ReadingState: case Wait4AuthState: // ignore _q_bytesWritten in these states @@ -479,6 +533,9 @@ bool QHttpNetworkConnectionPrivate::expand(QAbstractSocket *socket, QHttpNetwork // make sure that the reply is valid if (channels[i].reply != reply) return true; + // emit dataReadProgress signal (signal is currently not connected + // to the rest of QNAM) since readProgress of the + // QNonContiguousByteDevice is used emit reply->dataReadProgress(reply->d_func()->totalProgress, 0); // make sure that the reply is valid if (channels[i].reply != reply) @@ -529,10 +586,20 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN QHttpNetworkReplyPrivate::ReplyState state = reply ? reply->d_func()->state : QHttpNetworkReplyPrivate::AllDoneState; switch (state) { case QHttpNetworkReplyPrivate::NothingDoneState: - case QHttpNetworkReplyPrivate::ReadingStatusState: - bytes += reply->d_func()->readStatus(socket); + case QHttpNetworkReplyPrivate::ReadingStatusState: { + qint64 statusBytes = reply->d_func()->readStatus(socket); + if (statusBytes == -1) { + // error reading the status, close the socket and emit error + socket->close(); + reply->d_func()->errorString = errorDetail(QNetworkReply::ProtocolFailure, socket); + emit reply->finishedWithError(QNetworkReply::ProtocolFailure, reply->d_func()->errorString); + QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + break; + } + bytes += statusBytes; channels[i].lastStatus = reply->d_func()->statusCode; break; + } case QHttpNetworkReplyPrivate::ReadingHeaderState: bytes += reply->d_func()->readHeader(socket); if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) { @@ -569,6 +636,9 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN // make sure that the reply is valid if (channels[i].reply != reply) return; + // emit dataReadProgress signal (signal is currently not connected + // to the rest of QNAM) since readProgress of the + // QNonContiguousByteDevice is used emit reply->dataReadProgress(reply->d_func()->totalProgress, reply->d_func()->bodyLength); // make sure that the reply is valid if (channels[i].reply != reply) @@ -635,8 +705,25 @@ void QHttpNetworkConnectionPrivate::handleStatus(QAbstractSocket *socket, QHttpN case 407: handleAuthenticateChallenge(socket, reply, (statusCode == 407), resend); if (resend) { + int i = indexOf(socket); + + QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice(); + if (uploadByteDevice) { + if (uploadByteDevice->reset()) { + channels[i].written = 0; + } else { + emitReplyError(socket, reply, QNetworkReply::ContentReSendError); + break; + } + } + eraseData(reply); - sendRequest(socket); + + // also use async _q_startNextRequest so we dont break with closed + // proxy or server connections.. + channels[i].resendCurrent = true; + QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + } break; default: @@ -970,6 +1057,7 @@ void QHttpNetworkConnectionPrivate::_q_bytesWritten(qint64 bytes) QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender()); if (!socket) return; // ### error + // bytes have been written to the socket. write even more of them :) if (isSocketWriting(socket)) sendRequest(socket); // otherwise we do nothing @@ -1128,80 +1216,21 @@ void QHttpNetworkConnectionPrivate::_q_proxyAuthenticationRequired(const QNetwor } #endif -void QHttpNetworkConnectionPrivate::_q_dataReadyReadNoBuffer() +void QHttpNetworkConnectionPrivate::_q_uploadDataReadyRead() { Q_Q(QHttpNetworkConnection); - // data emitted either readyRead() + // upload data emitted readyRead() // find out which channel it is for - QIODevice *sender = qobject_cast<QIODevice *>(q->sender()); + QObject *sender = q->sender(); - // won't match anything if the qobject_cast above failed for (int i = 0; i < channelCount; ++i) { - if (sender == channels[i].request.data()) { + if (sender == channels[i].request.uploadByteDevice()) { sendRequest(channels[i].socket); break; } } } -void QHttpNetworkConnectionPrivate::_q_dataReadyReadBuffer() -{ - Q_Q(QHttpNetworkConnection); - QIODevice *sender = qobject_cast<QIODevice *>(q->sender()); - HttpMessagePair *thePair = 0; - for (int i = 0; !thePair && i < lowPriorityQueue.size(); ++i) - if (lowPriorityQueue.at(i).first.data() == sender) - thePair = &lowPriorityQueue[i]; - - for (int i = 0; !thePair && i < highPriorityQueue.size(); ++i) - if (highPriorityQueue.at(i).first.data() == sender) - thePair = &highPriorityQueue[i]; - - if (thePair) { - bufferData(*thePair); - - // are we finished buffering? - if (!thePair->second->d_func()->requestIsBuffering) - _q_startNextRequest(); - } -} - -void QHttpNetworkConnectionPrivate::bufferData(HttpMessagePair &messagePair) -{ - Q_Q(QHttpNetworkConnection); - QHttpNetworkRequest &request = messagePair.first; - QHttpNetworkReply *reply = messagePair.second; - Q_ASSERT(request.data()); - if (!reply->d_func()->requestIsBuffering) { // first time - QObject::connect(request.data(), SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadBuffer())); - QObject::connect(request.data(), SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadBuffer())); - reply->d_func()->requestIsBuffering = true; - reply->d_func()->requestDataBuffer.open(QIODevice::ReadWrite); - } - - // always try to read at least one byte - // ### FIXME! use a QRingBuffer - qint64 bytesToRead = qMax<qint64>(1, request.data()->bytesAvailable()); - QByteArray newData; - newData.resize(bytesToRead); - qint64 bytesActuallyRead = request.data()->read(newData.data(), bytesToRead); - - if (bytesActuallyRead > 0) { - // we read something - newData.chop(bytesToRead - bytesActuallyRead); - reply->d_func()->requestDataBuffer.write(newData); - } else if (bytesActuallyRead == -1) { // last time - QObject::disconnect(request.data(), SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadBuffer())); - QObject::disconnect(request.data(), SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadBuffer())); - - request.setContentLength(reply->d_func()->requestDataBuffer.size()); - reply->d_func()->requestDataBuffer.seek(0); - reply->d_func()->requestIsBuffering = false; - } -} - -// QHttpNetworkConnection - QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent) : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent) { diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 09bd459..9b127dd 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -146,8 +146,7 @@ private: #ifndef QT_NO_NETWORKPROXY Q_PRIVATE_SLOT(d_func(), void _q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)) #endif - Q_PRIVATE_SLOT(d_func(), void _q_dataReadyReadBuffer()) - Q_PRIVATE_SLOT(d_func(), void _q_dataReadyReadNoBuffer()) + Q_PRIVATE_SLOT(d_func(), void _q_uploadDataReadyRead()) #ifndef QT_NO_OPENSSL Q_PRIVATE_SLOT(d_func(), void _q_encrypted()) @@ -209,8 +208,8 @@ public: #ifndef QT_NO_NETWORKPROXY void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); // from transparent proxy #endif - void _q_dataReadyReadNoBuffer(); - void _q_dataReadyReadBuffer(); + + void _q_uploadDataReadyRead(); void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request); bool ensureConnection(QAbstractSocket *socket); @@ -219,7 +218,6 @@ public: #ifndef QT_NO_COMPRESS bool expand(QAbstractSocket *socket, QHttpNetworkReply *reply, bool dataComplete); #endif - void bufferData(HttpMessagePair &request); void removeReply(QHttpNetworkReply *reply); QString hostName; diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index fe3f6af..310994c 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -409,39 +409,62 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) if (fragment.endsWith('\r')) { fragment.truncate(fragment.length()-1); } - parseStatus(fragment); + bool ok = parseStatus(fragment); state = ReadingHeaderState; fragment.clear(); // next fragment + + if (!ok) + return -1; break; } else { c = 0; bytes += socket->read(&c, 1); fragment.append(c); } + + // is this a valid reply? + if (fragment.length() >= 5 && !fragment.startsWith("HTTP/")) + return -1; + } + return bytes; } -void QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status) +bool QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status) { - const QByteArrayMatcher sp(" "); - int i = sp.indexIn(status); - const QByteArray version = status.mid(0, i); - int j = sp.indexIn(status, i + 1); + // from RFC 2616: + // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF + // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT + // that makes: 'HTTP/n.n xxx Message' + // byte count: 0123456789012 + + static const int minLength = 11; + static const int dotPos = 6; + static const int spacePos = 8; + static const char httpMagic[] = "HTTP/"; + + if (status.length() < minLength + || !status.startsWith(httpMagic) + || status.at(dotPos) != '.' + || status.at(spacePos) != ' ') { + // I don't know how to parse this status line + return false; + } + + // optimize for the valid case: defer checking until the end + majorVersion = status.at(dotPos - 1) - '0'; + minorVersion = status.at(dotPos + 1) - '0'; + + int i = spacePos; + int j = status.indexOf(' ', i + 1); // j == -1 || at(j) == ' ' so j+1 == 0 && j+1 <= length() const QByteArray code = status.mid(i + 1, j - i - 1); - const QByteArray reason = status.mid(j + 1, status.count() - j); - const QByteArrayMatcher slash("/"); - int k = slash.indexIn(version); - const QByteArrayMatcher dot("."); - int l = dot.indexIn(version, k); - const QByteArray major = version.mid(k + 1, l - k - 1); - const QByteArray minor = version.mid(l + 1, version.count() - l); + bool ok; + statusCode = code.toInt(&ok); + reasonPhrase = QString::fromLatin1(status.constData() + j + 1); - majorVersion = QString::fromAscii(major.constData()).toInt(); - minorVersion = QString::fromAscii(minor.constData()).toInt(); - statusCode = QString::fromAscii(code.constData()).toInt(); - reasonPhrase = QString::fromAscii(reason.constData()); + return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9; } qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket) @@ -521,13 +544,13 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *ou { qint64 bytes = 0; if (isChunked()) { - bytes += transferChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6) + bytes += readReplyBodyChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6) } else if (bodyLength > 0) { // we have a Content-Length - bytes += transferRaw(socket, out, bodyLength - contentRead); + bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead); if (contentRead + bytes == bodyLength) state = AllDoneState; } else { - bytes += transferRaw(socket, out, socket->bytesAvailable()); + bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable()); } if (state == AllDoneState) socket->readAll(); // Read the rest to clean (CRLF) @@ -535,7 +558,7 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *ou return bytes; } -qint64 QHttpNetworkReplyPrivate::transferRaw(QIODevice *in, QIODevice *out, qint64 size) +qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QIODevice *out, qint64 size) { qint64 bytes = 0; Q_ASSERT(in); @@ -561,7 +584,7 @@ qint64 QHttpNetworkReplyPrivate::transferRaw(QIODevice *in, QIODevice *out, qint } -qint64 QHttpNetworkReplyPrivate::transferChunked(QIODevice *in, QIODevice *out) +qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QIODevice *out) { qint64 bytes = 0; while (in->bytesAvailable()) { // while we can read from input @@ -660,4 +683,4 @@ void QHttpNetworkReply::ignoreSslErrors() QT_END_NAMESPACE -#endif // QT_NO_HTTP
\ No newline at end of file +#endif // QT_NO_HTTP diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index c17c65c..cc5cce8 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -139,7 +139,7 @@ Q_SIGNALS: void finishedWithError(QNetworkReply::NetworkError errorCode, const QString &detail = QString()); void headerChanged(); void dataReadProgress(int done, int total); - void dataSendProgress(int done, int total); + void dataSendProgress(qint64 done, qint64 total); private: Q_DECLARE_PRIVATE(QHttpNetworkReply) @@ -154,7 +154,7 @@ public: QHttpNetworkReplyPrivate(const QUrl &newUrl = QUrl()); ~QHttpNetworkReplyPrivate(); qint64 readStatus(QAbstractSocket *socket); - void parseStatus(const QByteArray &status); + bool parseStatus(const QByteArray &status); qint64 readHeader(QAbstractSocket *socket); void parseHeader(const QByteArray &header); qint64 readBody(QAbstractSocket *socket, QIODevice *out); @@ -162,8 +162,8 @@ public: QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const; void clear(); - qint64 transferRaw(QIODevice *in, QIODevice *out, qint64 size); - qint64 transferChunked(QIODevice *in, QIODevice *out); + qint64 readReplyBodyRaw(QIODevice *in, QIODevice *out, qint64 size); + qint64 readReplyBodyChunked(QIODevice *in, QIODevice *out); qint64 getChunkSize(QIODevice *in, qint64 *chunkSize); qint64 bytesAvailable() const; @@ -206,7 +206,6 @@ public: QByteArray responseData; // uncompressed body QByteArray compressedData; // compressed body (temporary) - QBuffer requestDataBuffer; bool requestIsBuffering; bool requestIsPrepared; }; diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 420cb69..7df68fc 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -40,12 +40,13 @@ ****************************************************************************/ #include "qhttpnetworkrequest_p.h" +#include "private/qnoncontiguousbytedevice_p.h" QT_BEGIN_NAMESPACE QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, QHttpNetworkRequest::Priority pri, const QUrl &newUrl) - : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), data(0), + : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0), autoDecompress(false) { } @@ -55,7 +56,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest { operation = other.operation; priority = other.priority; - data = other.data; + uploadByteDevice = other.uploadByteDevice; autoDecompress = other.autoDecompress; } @@ -67,7 +68,7 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot { return QHttpNetworkHeaderPrivate::operator==(other) && (operation == other.operation) - && (data == other.data); + && (uploadByteDevice == other.uploadByteDevice); } QByteArray QHttpNetworkRequestPrivate::methodName() const @@ -109,7 +110,7 @@ QByteArray QHttpNetworkRequestPrivate::uri(bool throughProxy) const QUrl::FormattingOptions format(QUrl::RemoveFragment); // for POST, query data is send as content - if (operation == QHttpNetworkRequest::Post && !data) + if (operation == QHttpNetworkRequest::Post && !uploadByteDevice) format |= QUrl::RemoveQuery; // for requests through proxy, the Request-URI contains full url if (throughProxy) @@ -140,7 +141,7 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request // add content type, if not set in the request if (request.headerField("content-type").isEmpty()) ba += "Content-Type: application/x-www-form-urlencoded\r\n"; - if (!request.d->data && request.d->url.hasQuery()) { + if (!request.d->uploadByteDevice && request.d->url.hasQuery()) { QByteArray query = request.d->url.encodedQuery(); ba += "Content-Length: "+ QByteArray::number(query.size()) + "\r\n"; ba += "\r\n"; @@ -236,14 +237,14 @@ void QHttpNetworkRequest::setPriority(Priority priority) d->priority = priority; } -QIODevice *QHttpNetworkRequest::data() const +void QHttpNetworkRequest::setUploadByteDevice(QNonContiguousByteDevice *bd) { - return d->data; + d->uploadByteDevice = bd; } -void QHttpNetworkRequest::setData(QIODevice *data) +QNonContiguousByteDevice* QHttpNetworkRequest::uploadByteDevice() const { - d->data = data; + return d->uploadByteDevice; } int QHttpNetworkRequest::majorVersion() const diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index d18e116..ed4325a 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -58,6 +58,8 @@ QT_BEGIN_NAMESPACE +class QNonContiguousByteDevice; + class QHttpNetworkRequestPrivate; class Q_AUTOTEST_EXPORT QHttpNetworkRequest: public QHttpNetworkHeader { @@ -104,8 +106,8 @@ public: Priority priority() const; void setPriority(Priority priority); - QIODevice *data() const; - void setData(QIODevice *data); + void setUploadByteDevice(QNonContiguousByteDevice *bd); + QNonContiguousByteDevice* uploadByteDevice() const; private: QSharedDataPointer<QHttpNetworkRequestPrivate> d; @@ -113,7 +115,6 @@ private: friend class QHttpNetworkConnectionPrivate; }; - class QHttpNetworkRequestPrivate : public QHttpNetworkHeaderPrivate { public: @@ -129,7 +130,7 @@ public: QHttpNetworkRequest::Operation operation; QHttpNetworkRequest::Priority priority; - mutable QIODevice *data; + mutable QNonContiguousByteDevice* uploadByteDevice; bool autoDecompress; }; diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index df468b8..b9d1b85 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -50,6 +50,8 @@ #include "qnetworkaccesscachebackend_p.h" #include "qabstractnetworkcache.h" +#include "private/qnoncontiguousbytedevice_p.h" + QT_BEGIN_NAMESPACE static bool factoryDataShutdown = false; @@ -109,17 +111,43 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM return 0; } -QNetworkAccessBackend::QNetworkAccessBackend() + +QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice() { + QNonContiguousByteDevice* device = 0; + + if (reply->outgoingDataBuffer) + device = QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer); + else + device = QNonContiguousByteDeviceFactory::create(reply->outgoingData); + + bool bufferDisallowed = + reply->request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, + QVariant(false)) == QVariant(true); + if (bufferDisallowed) + device->disableReset(); + + // make sure we delete this later + device->setParent(this); + + connect(device, SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64))); + + return device; } -QNetworkAccessBackend::~QNetworkAccessBackend() +// need to have this function since the reply is a private member variable +// and the special backends need to access this. +void QNetworkAccessBackend::emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal) { + reply->emitUploadProgress(bytesSent, bytesTotal); } -void QNetworkAccessBackend::upstreamReadyRead() +QNetworkAccessBackend::QNetworkAccessBackend() +{ +} + +QNetworkAccessBackend::~QNetworkAccessBackend() { - // do nothing } void QNetworkAccessBackend::downstreamReadyWrite() @@ -184,23 +212,6 @@ bool QNetworkAccessBackend::isCachingEnabled() const return reply->isCachingEnabled(); } -qint64 QNetworkAccessBackend::upstreamBytesAvailable() const -{ - return reply->writeBuffer.size(); -} - -void QNetworkAccessBackend::upstreamBytesConsumed(qint64 count) -{ - // remove count bytes from the write buffer - reply->consume(count); -} - -QByteArray QNetworkAccessBackend::readUpstream() -{ - // ### this is expensive. Consider making QRingBuffer::peekAll keep the buffer it returns - return reply->writeBuffer.peek(upstreamBytesAvailable()); -} - qint64 QNetworkAccessBackend::nextDownstreamBlockSize() const { return reply->nextDownstreamBlockSize(); @@ -213,12 +224,12 @@ qint64 QNetworkAccessBackend::downstreamBytesToConsume() const void QNetworkAccessBackend::writeDownstreamData(const QByteArray &data) { - reply->feed(data); + reply->appendDownstreamData(data); } void QNetworkAccessBackend::writeDownstreamData(QIODevice *data) { - reply->feed(data); + reply->appendDownstreamData(data); } QVariant QNetworkAccessBackend::header(QNetworkRequest::KnownHeaders header) const diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index 9012396..6035f3a 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -70,6 +70,8 @@ class QNetworkAccessManagerPrivate; class QNetworkReplyImplPrivate; class QAbstractNetworkCache; class QNetworkCacheMetaData; +class QNetworkAccessBackendUploadIODevice; +class QNonContiguousByteDevice; // Should support direct file upload from disk or download to disk. // @@ -86,14 +88,13 @@ public: // have different names. The Connection has two streams: // // - Upstream: - // Upstream is data that is being written into this connection, - // from the user. Upstream operates in a "pull" mechanism: the - // connection will be notified that there is more data available - // by a call to "upstreamReadyRead". The number of bytes - // available is given by upstreamBytesAvailable(). A call to - // readUpstream() always yields the entire upstream buffer. When - // the connection has processed a certain amount of bytes from - // that buffer, it should call upstreamBytesConsumed(). + // The upstream uses a QNonContiguousByteDevice provided + // by the backend. This device emits the usual readyRead() + // signal when the backend has data available for the connection + // to write. The different backends can listen on this signal + // and then pull upload data from the QNonContiguousByteDevice and + // deal with it. + // // // - Downstream: // Downstream is the data that is being read from this @@ -111,12 +112,9 @@ public: virtual void open() = 0; virtual void closeDownstreamChannel() = 0; - virtual void closeUpstreamChannel() = 0; virtual bool waitForDownstreamReadyRead(int msecs) = 0; - virtual bool waitForUpstreamBytesWritten(int msecs) = 0; // slot-like: - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); virtual void copyFinished(QIODevice *); virtual void ignoreSslErrors(); @@ -155,18 +153,24 @@ public: QVariant attribute(QNetworkRequest::Attribute code) const; void setAttribute(QNetworkRequest::Attribute code, const QVariant &value); + // return true if the QNonContiguousByteDevice of the upload + // data needs to support reset(). Currently needed for HTTP. + // This will possibly enable buffering of the upload data. + virtual bool needsResetableUploadData() {return false;}; + protected: - // these functions control the upstream mechanism - // that is, data coming into the backend and out via the connection - qint64 upstreamBytesAvailable() const; - void upstreamBytesConsumed(qint64 count); - QByteArray readUpstream(); + // Create the device used for reading the upload data + QNonContiguousByteDevice* createUploadByteDevice(); + // these functions control the downstream mechanism // that is, data that has come via the connection and is going out the backend qint64 nextDownstreamBlockSize() const; qint64 downstreamBytesToConsume() const; void writeDownstreamData(const QByteArray &data); + +public slots: + // for task 251801, needs to be a slot to be called asynchronously void writeDownstreamData(QIODevice *data); protected slots: @@ -179,10 +183,12 @@ protected slots: void metaDataChanged(); void redirectionRequested(const QUrl &destination); void sslErrors(const QList<QSslError> &errors); + void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); private: friend class QNetworkAccessManager; friend class QNetworkAccessManagerPrivate; + friend class QNetworkAccessBackendUploadIODevice; QNetworkAccessManagerPrivate *manager; QNetworkReplyImplPrivate *reply; }; diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp index 2e5f1b1..d4bda9a 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend.cpp +++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp @@ -41,6 +41,8 @@ #include "qnetworkaccessdebugpipebackend_p.h" #include "QtCore/qdatastream.h" +#include <QCoreApplication> +#include "private/qnoncontiguousbytedevice_p.h" QT_BEGIN_NAMESPACE @@ -51,12 +53,6 @@ enum { WriteBufferSize = ReadBufferSize }; -struct QNetworkAccessDebugPipeBackend::DataPacket -{ - QList<QPair<QByteArray, QByteArray> > headers; - QByteArray data; -}; - QNetworkAccessBackend * QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const @@ -79,12 +75,14 @@ QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation o } QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend() - : incomingPacketSize(0), bareProtocol(false) + : bareProtocol(false), hasUploadFinished(false), hasDownloadFinished(false), + hasEverythingFinished(false), bytesDownloaded(0), bytesUploaded(0) { } QNetworkAccessDebugPipeBackend::~QNetworkAccessDebugPipeBackend() { + // this is signals disconnect, not network! socket.disconnect(this); // we're not interested in the signals at this point } @@ -92,160 +90,150 @@ void QNetworkAccessDebugPipeBackend::open() { socket.connectToHost(url().host(), url().port(12345)); socket.setReadBufferSize(ReadBufferSize); + + // socket ready read -> we can push from socket to downstream connect(&socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); - connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError())); connect(&socket, SIGNAL(disconnected()), SLOT(socketDisconnected())); + connect(&socket, SIGNAL(connected()), SLOT(socketConnected())); + // socket bytes written -> we can push more from upstream to socket + connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); bareProtocol = url().queryItemValue(QLatin1String("bare")) == QLatin1String("1"); - if (!bareProtocol) { - // "Handshake": - // send outgoing metadata and the URL being requested - DataPacket packet; - //packet.metaData = request().metaData(); - packet.data = url().toEncoded(); - send(packet); + if (operation() == QNetworkAccessManager::PutOperation) { + uploadByteDevice = createUploadByteDevice(); + QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot())); + QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection); } } -void QNetworkAccessDebugPipeBackend::closeDownstreamChannel() +void QNetworkAccessDebugPipeBackend::socketReadyRead() { - if (operation() == QNetworkAccessManager::GetOperation) - socket.disconnectFromHost(); + pushFromSocketToDownstream(); } -void QNetworkAccessDebugPipeBackend::closeUpstreamChannel() +void QNetworkAccessDebugPipeBackend::downstreamReadyWrite() { - if (operation() == QNetworkAccessManager::PutOperation) - socket.disconnectFromHost(); - else if (operation() == QNetworkAccessManager::PostOperation) { - send(DataPacket()); - } + pushFromSocketToDownstream(); } -bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms) +void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64) { - readyReadEmitted = false; - if (socket.bytesAvailable()) { - socketReadyRead(); - if (readyReadEmitted) - return true; - } - socket.waitForReadyRead(ms); - return readyReadEmitted; + pushFromUpstreamToSocket(); } -bool QNetworkAccessDebugPipeBackend::waitForUpstreamBytesWritten(int ms) +void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot() { - bytesWrittenEmitted = false; - upstreamReadyRead(); - if (bytesWrittenEmitted) - return true; - - socket.waitForBytesWritten(ms); - return bytesWrittenEmitted; + pushFromUpstreamToSocket(); } -void QNetworkAccessDebugPipeBackend::upstreamReadyRead() +void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream() { - int maxWrite = WriteBufferSize - socket.bytesToWrite(); - if (maxWrite <= 0) - return; // can't write yet, wait for the socket to write - - if (bareProtocol) { - QByteArray data = readUpstream(); - if (data.isEmpty()) - return; + QByteArray buffer; - socket.write(data); - upstreamBytesConsumed(data.size()); - bytesWrittenEmitted = true; + if (socket.state() == QAbstractSocket::ConnectingState) { return; } - DataPacket packet; - packet.data = readUpstream(); - if (packet.data.isEmpty()) - return; // we'll be called again when there's data - if (packet.data.size() > maxWrite) - packet.data.truncate(maxWrite); - - if (!send(packet)) { - QString msg = QObject::tr("Write error writing to %1: %2") - .arg(url().toString(), socket.errorString()); - error(QNetworkReply::ProtocolFailure, msg); + forever { + if (hasDownloadFinished) + return; - finished(); - return; + buffer.resize(ReadBufferSize); + qint64 haveRead = socket.read(buffer.data(), ReadBufferSize); + + if (haveRead == -1) { + hasDownloadFinished = true; + // this ensures a good last downloadProgress is emitted + setHeader(QNetworkRequest::ContentLengthHeader, QVariant()); + possiblyFinish(); + break; + } else if (haveRead == 0) { + break; + } else { + // have read something + buffer.resize(haveRead); + bytesDownloaded += haveRead; + writeDownstreamData(buffer); + } } - upstreamBytesConsumed(packet.data.size()); - bytesWrittenEmitted = true; } -void QNetworkAccessDebugPipeBackend::downstreamReadyWrite() +void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket() { - socketReadyRead(); -} + // FIXME + if (operation() == QNetworkAccessManager::PutOperation) { + if (hasUploadFinished) + return; -void QNetworkAccessDebugPipeBackend::socketReadyRead() -{ - if (bareProtocol) { - qint64 bytesToRead = socket.bytesAvailable(); - if (bytesToRead) { - QByteArray buffer; - buffer.resize(bytesToRead); - qint64 bytesRead = socket.read(buffer.data(), bytesToRead); - if (bytesRead < bytesToRead) - buffer.truncate(bytesRead); - writeDownstreamData(buffer); - readyReadEmitted = true; + forever { + if (socket.bytesToWrite() >= WriteBufferSize) + return; + + qint64 haveRead; + const char *readPointer = uploadByteDevice->readPointer(WriteBufferSize, haveRead); + if (haveRead == -1) { + // EOF + hasUploadFinished = true; + emitReplyUploadProgress(bytesUploaded, bytesUploaded); + possiblyFinish(); + break; + } else if (haveRead == 0 || readPointer == 0) { + // nothing to read right now, we will be called again later + break; + } else { + qint64 haveWritten; + haveWritten = socket.write(readPointer, haveRead); + + if (haveWritten < 0) { + // write error! + QString msg = QCoreApplication::translate("QNetworkAccessDebugPipeBackend", "Write error writing to %1: %2") + .arg(url().toString(), socket.errorString()); + error(QNetworkReply::ProtocolFailure, msg); + finished(); + return; + } else { + uploadByteDevice->advanceReadPointer(haveWritten); + bytesUploaded += haveWritten; + emitReplyUploadProgress(bytesUploaded, -1); + } + + //QCoreApplication::processEvents(); + + } } - return; } +} - while (canReceive() && - (socket.state() == QAbstractSocket::UnconnectedState || nextDownstreamBlockSize())) { - DataPacket packet; - if (receive(packet)) { - if (!packet.headers.isEmpty()) { - QList<QPair<QByteArray, QByteArray> >::ConstIterator - it = packet.headers.constBegin(), - end = packet.headers.constEnd(); - for ( ; it != end; ++it) - setRawHeader(it->first, it->second); - metaDataChanged(); - } +void QNetworkAccessDebugPipeBackend::possiblyFinish() +{ + if (hasEverythingFinished) + return; + hasEverythingFinished = true; - if (!packet.data.isEmpty()) { - writeDownstreamData(packet.data); - readyReadEmitted = true; - } + if ((operation() == QNetworkAccessManager::GetOperation) && hasDownloadFinished) { + socket.close(); + finished(); + } else if ((operation() == QNetworkAccessManager::PutOperation) && hasUploadFinished) { + socket.close(); + finished(); + } - if (packet.headers.isEmpty() && packet.data.isEmpty()) { - // it's an eof - socket.close(); - readyReadEmitted = true; - } - } else { - // got an error - QString msg = QObject::tr("Read error reading from %1: %2") - .arg(url().toString(), socket.errorString()); - error(QNetworkReply::ProtocolFailure, msg); - finished(); - return; - } - } } -void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64) +void QNetworkAccessDebugPipeBackend::closeDownstreamChannel() { - upstreamReadyRead(); + qWarning() << "QNetworkAccessDebugPipeBackend::closeDownstreamChannel()" << operation(); + //if (operation() == QNetworkAccessManager::GetOperation) + // socket.disconnectFromHost(); } + void QNetworkAccessDebugPipeBackend::socketError() { + qWarning() << "QNetworkAccessDebugPipeBackend::socketError()" << socket.error(); QNetworkReply::NetworkError code; switch (socket.error()) { case QAbstractSocket::RemoteHostClosedError: @@ -269,76 +257,27 @@ void QNetworkAccessDebugPipeBackend::socketError() void QNetworkAccessDebugPipeBackend::socketDisconnected() { - socketReadyRead(); - if (incomingPacketSize == 0 && socket.bytesToWrite() == 0) { + pushFromSocketToDownstream(); + + if (socket.bytesToWrite() == 0) { // normal close - finished(); } else { // abnormal close QString msg = QObject::tr("Remote host closed the connection prematurely on %1") .arg(url().toString()); error(QNetworkReply::RemoteHostClosedError, msg); - finished(); } } -bool QNetworkAccessDebugPipeBackend::send(const DataPacket &packet) -{ - QByteArray ba; - { - QDataStream stream(&ba, QIODevice::WriteOnly); - stream.setVersion(QDataStream::Qt_4_4); - - stream << packet.headers << packet.data; - } - - qint32 outgoingPacketSize = ba.size(); - qint64 written = socket.write((const char*)&outgoingPacketSize, sizeof outgoingPacketSize); - written += socket.write(ba); - return quint64(written) == (outgoingPacketSize + sizeof outgoingPacketSize); -} - -bool QNetworkAccessDebugPipeBackend::receive(DataPacket &packet) +void QNetworkAccessDebugPipeBackend::socketConnected() { - if (!canReceive()) - return false; - - // canReceive() does the setting up for us - Q_ASSERT(socket.bytesAvailable() >= incomingPacketSize); - QByteArray incomingPacket = socket.read(incomingPacketSize); - QDataStream stream(&incomingPacket, QIODevice::ReadOnly); - stream.setVersion(QDataStream::Qt_4_4); - stream >> packet.headers >> packet.data; - - // reset for next packet: - incomingPacketSize = 0; - socket.setReadBufferSize(ReadBufferSize); - return true; } -bool QNetworkAccessDebugPipeBackend::canReceive() +bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms) { - if (incomingPacketSize == 0) { - // read the packet size - if (quint64(socket.bytesAvailable()) >= sizeof incomingPacketSize) - socket.read((char*)&incomingPacketSize, sizeof incomingPacketSize); - else - return false; - } - - if (incomingPacketSize == 0) { - QString msg = QObject::tr("Protocol error: packet of size 0 received"); - error(QNetworkReply::ProtocolFailure, msg); - finished(); - - socket.blockSignals(true); - socket.abort(); - socket.blockSignals(false); - return false; - } - - return socket.bytesAvailable() >= incomingPacketSize; + qCritical("QNetworkAccess: Debug pipe backend does not support waitForReadyRead()"); + return false; } #endif diff --git a/src/network/access/qnetworkaccessdebugpipebackend_p.h b/src/network/access/qnetworkaccessdebugpipebackend_p.h index 73a35cf..a13edc4 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend_p.h +++ b/src/network/access/qnetworkaccessdebugpipebackend_p.h @@ -66,35 +66,38 @@ class QNetworkAccessDebugPipeBackend: public QNetworkAccessBackend { Q_OBJECT public: - struct DataPacket; QNetworkAccessDebugPipeBackend(); virtual ~QNetworkAccessDebugPipeBackend(); virtual void open(); virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); +protected: + void pushFromSocketToDownstream(); + void pushFromUpstreamToSocket(); + void possiblyFinish(); + QNonContiguousByteDevice *uploadByteDevice; + private slots: + void uploadReadyReadSlot(); void socketReadyRead(); void socketBytesWritten(qint64 bytes); void socketError(); void socketDisconnected(); + void socketConnected(); private: QTcpSocket socket; - qint32 incomingPacketSize; - bool readyReadEmitted; - bool bytesWrittenEmitted; bool bareProtocol; + bool hasUploadFinished; + bool hasDownloadFinished; + bool hasEverythingFinished; - bool send(const DataPacket &packet); - bool canReceive(); - bool receive(DataPacket &packet); + qint64 bytesDownloaded; + qint64 bytesUploaded; }; class QNetworkAccessDebugPipeBackendFactory: public QNetworkAccessBackendFactory diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp index 8a5a665..6374fde 100644 --- a/src/network/access/qnetworkaccessfilebackend.cpp +++ b/src/network/access/qnetworkaccessfilebackend.cpp @@ -43,6 +43,7 @@ #include "qfileinfo.h" #include "qurlinfo.h" #include "qdir.h" +#include "private/qnoncontiguousbytedevice_p.h" #include <QtCore/QCoreApplication> @@ -77,7 +78,7 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op, } QNetworkAccessFileBackend::QNetworkAccessFileBackend() - : totalBytes(0) + : uploadByteDevice(0), totalBytes(0), hasUploadFinished(false) { } @@ -126,6 +127,9 @@ void QNetworkAccessFileBackend::open() break; case QNetworkAccessManager::PutOperation: mode = QIODevice::WriteOnly | QIODevice::Truncate; + uploadByteDevice = createUploadByteDevice(); + QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot())); + QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection); break; default: Q_ASSERT_X(false, "QNetworkAccessFileBackend::open", @@ -152,19 +156,50 @@ void QNetworkAccessFileBackend::open() } } -void QNetworkAccessFileBackend::closeDownstreamChannel() +void QNetworkAccessFileBackend::uploadReadyReadSlot() { - if (operation() == QNetworkAccessManager::GetOperation) { - file.close(); - //downstreamChannelClosed(); + if (hasUploadFinished) + return; + + forever { + qint64 haveRead; + const char *readPointer = uploadByteDevice->readPointer(-1, haveRead); + if (haveRead == -1) { + // EOF + hasUploadFinished = true; + file.flush(); + file.close(); + finished(); + break; + } else if (haveRead == 0 || readPointer == 0) { + // nothing to read right now, we will be called again later + break; + } else { + qint64 haveWritten; + haveWritten = file.write(readPointer, haveRead); + + if (haveWritten < 0) { + // write error! + QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Write error writing to %1: %2") + .arg(url().toString(), file.errorString()); + error(QNetworkReply::ProtocolFailure, msg); + + finished(); + return; + } else { + uploadByteDevice->advanceReadPointer(haveWritten); + } + + + file.flush(); + } } } -void QNetworkAccessFileBackend::closeUpstreamChannel() +void QNetworkAccessFileBackend::closeDownstreamChannel() { - if (operation() == QNetworkAccessManager::PutOperation) { + if (operation() == QNetworkAccessManager::GetOperation) { file.close(); - finished(); } } @@ -174,40 +209,6 @@ bool QNetworkAccessFileBackend::waitForDownstreamReadyRead(int) return readMoreFromFile(); } -bool QNetworkAccessFileBackend::waitForUpstreamBytesWritten(int) -{ - Q_ASSERT_X(false, "QNetworkAccessFileBackend::waitForUpstreamBytesWritten", - "This function should never have been called, since there is never anything " - "left to be written!"); - return false; -} - -void QNetworkAccessFileBackend::upstreamReadyRead() -{ - Q_ASSERT_X(operation() == QNetworkAccessManager::PutOperation, "QNetworkAccessFileBackend", - "We're being told to upload data but operation isn't PUT!"); - - // there's more data to be written to the file - while (upstreamBytesAvailable()) { - // write everything and let QFile handle it - int written = file.write(readUpstream()); - - if (written < 0) { - // write error! - QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Write error writing to %1: %2") - .arg(url().toString(), file.errorString()); - error(QNetworkReply::ProtocolFailure, msg); - - finished(); - return; - } - - // successful write - file.flush(); - upstreamBytesConsumed(written); - } -} - void QNetworkAccessFileBackend::downstreamReadyWrite() { Q_ASSERT_X(operation() == QNetworkAccessManager::GetOperation, "QNetworkAccessFileBackend", diff --git a/src/network/access/qnetworkaccessfilebackend_p.h b/src/network/access/qnetworkaccessfilebackend_p.h index ce7d351..4615c5f 100644 --- a/src/network/access/qnetworkaccessfilebackend_p.h +++ b/src/network/access/qnetworkaccessfilebackend_p.h @@ -62,22 +62,25 @@ QT_BEGIN_NAMESPACE class QNetworkAccessFileBackend: public QNetworkAccessBackend { + Q_OBJECT public: QNetworkAccessFileBackend(); virtual ~QNetworkAccessFileBackend(); virtual void open(); virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); +public slots: + void uploadReadyReadSlot(); +protected: + QNonContiguousByteDevice *uploadByteDevice; private: QFile file; qint64 totalBytes; + bool hasUploadFinished; bool loadFileInfo(); bool readMoreFromFile(); diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index ea39dec..ad55b85 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -42,6 +42,7 @@ #include "qnetworkaccessftpbackend_p.h" #include "qnetworkaccessmanager_p.h" #include "QtNetwork/qauthenticator.h" +#include "private/qnoncontiguousbytedevice_p.h" #ifndef QT_NO_FTP @@ -81,41 +82,6 @@ QNetworkAccessFtpBackendFactory::create(QNetworkAccessManager::Operation op, return 0; } -class QNetworkAccessFtpIODevice: public QIODevice -{ - //Q_OBJECT -public: - QNetworkAccessFtpBackend *backend; - bool eof; - - inline QNetworkAccessFtpIODevice(QNetworkAccessFtpBackend *parent) - : QIODevice(parent), backend(parent), eof(false) - { open(ReadOnly); } - - bool isSequential() const { return true; } - bool atEnd() const { return backend->upstreamBytesAvailable() == 0; } - - qint64 bytesAvailable() const { return backend->upstreamBytesAvailable(); } - qint64 bytesToWrite() const { return backend->downstreamBytesToConsume(); } -protected: - qint64 readData(char *data, qint64 maxlen) - { - const QByteArray toSend = backend->readUpstream(); - maxlen = qMin<qint64>(maxlen, toSend.size()); - if (!maxlen) - return eof ? -1 : 0; - - backend->upstreamBytesConsumed(maxlen); - memcpy(data, toSend.constData(), maxlen); - return maxlen; - } - - qint64 writeData(const char *, qint64) - { return -1; } - - friend class QNetworkAccessFtpBackend; -}; - class QNetworkAccessFtpFtp: public QFtp, public QNetworkAccessCache::CacheableObject { // Q_OBJECT @@ -198,7 +164,11 @@ void QNetworkAccessFtpBackend::open() ftpConnectionReady(ftp); } - uploadDevice = new QNetworkAccessFtpIODevice(this); + // Put operation + if (operation() == QNetworkAccessManager::PutOperation) { + uploadDevice = QNonContiguousByteDeviceFactory::wrap(createUploadByteDevice()); + uploadDevice->setParent(this); + } } void QNetworkAccessFtpBackend::closeDownstreamChannel() @@ -212,16 +182,6 @@ void QNetworkAccessFtpBackend::closeDownstreamChannel() #endif } -void QNetworkAccessFtpBackend::closeUpstreamChannel() -{ - if (operation() == QNetworkAccessManager::PutOperation) { - Q_ASSERT(uploadDevice); - uploadDevice->eof = true; - if (!upstreamBytesAvailable()) - emit uploadDevice->readyRead(); - } -} - bool QNetworkAccessFtpBackend::waitForDownstreamReadyRead(int ms) { if (!ftp) @@ -239,18 +199,6 @@ bool QNetworkAccessFtpBackend::waitForDownstreamReadyRead(int ms) return false; } -bool QNetworkAccessFtpBackend::waitForUpstreamBytesWritten(int ms) -{ - Q_UNUSED(ms); - qCritical("QNetworkAccess: FTP backend does not support waitForBytesWritten()"); - return false; -} - -void QNetworkAccessFtpBackend::upstreamReadyRead() -{ - // uh... how does QFtp operate? -} - void QNetworkAccessFtpBackend::downstreamReadyWrite() { if (state == Transferring && ftp && ftp->bytesAvailable()) diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h index 9ec2dd8..1bb7ff2 100644 --- a/src/network/access/qnetworkaccessftpbackend_p.h +++ b/src/network/access/qnetworkaccessftpbackend_p.h @@ -87,11 +87,8 @@ public: virtual void open(); virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); void disconnectFromFtp(); @@ -105,7 +102,7 @@ public slots: private: friend class QNetworkAccessFtpIODevice; QPointer<QNetworkAccessFtpFtp> ftp; - QNetworkAccessFtpIODevice *uploadDevice; + QIODevice *uploadDevice; qint64 totalBytes; int helpId, sizeId, mdtmId; bool supportsSize, supportsMdtm; diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index a52b5a0..bd364cb 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -286,37 +286,6 @@ public: } }; -class QNetworkAccessHttpBackendIODevice: public QIODevice -{ - // Q_OBJECT -public: - bool eof; - QNetworkAccessHttpBackendIODevice(QNetworkAccessHttpBackend *parent) - : QIODevice(parent), eof(false) - { - setOpenMode(ReadOnly); - } - bool isSequential() const { return true; } - qint64 bytesAvailable() const - { return static_cast<QNetworkAccessHttpBackend *>(parent())->upstreamBytesAvailable(); } - -protected: - virtual qint64 readData(char *buffer, qint64 maxlen) - { - qint64 ret = static_cast<QNetworkAccessHttpBackend *>(parent())->deviceReadData(buffer, maxlen); - if (!ret && eof) - return -1; - return ret; - } - - virtual qint64 writeData(const char *, qint64) - { - return -1; // cannot write - } - - friend class QNetworkAccessHttpBackend; -}; - QNetworkAccessHttpBackend::QNetworkAccessHttpBackend() : QNetworkAccessBackend(), httpReply(0), http(0), uploadDevice(0) #ifndef QT_NO_OPENSSL @@ -507,20 +476,19 @@ void QNetworkAccessHttpBackend::postRequest() case QNetworkAccessManager::PostOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Post); - uploadDevice = new QNetworkAccessHttpBackendIODevice(this); + httpRequest.setUploadByteDevice(createUploadByteDevice()); break; case QNetworkAccessManager::PutOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Put); - uploadDevice = new QNetworkAccessHttpBackendIODevice(this); + httpRequest.setUploadByteDevice(createUploadByteDevice()); break; default: break; // can't happen } - httpRequest.setData(uploadDevice); httpRequest.setUrl(url()); QList<QByteArray> headers = request().rawHeaderList(); @@ -528,7 +496,9 @@ void QNetworkAccessHttpBackend::postRequest() httpRequest.setHeaderField(header, request().rawHeader(header)); if (loadedFromCache) { - QNetworkAccessBackend::finished(); + // commented this out since it will be called later anyway + // by copyFinished() + //QNetworkAccessBackend::finished(); return; // no need to send the request! :) } @@ -624,14 +594,6 @@ void QNetworkAccessHttpBackend::closeDownstreamChannel() // this indicates that the user closed the stream while the reply isn't finished yet } -void QNetworkAccessHttpBackend::closeUpstreamChannel() -{ - // this indicates that the user finished uploading the data for POST - Q_ASSERT(uploadDevice); - uploadDevice->eof = true; - emit uploadDevice->readChannelFinished(); -} - bool QNetworkAccessHttpBackend::waitForDownstreamReadyRead(int msecs) { Q_ASSERT(http); @@ -651,38 +613,6 @@ bool QNetworkAccessHttpBackend::waitForDownstreamReadyRead(int msecs) return false; } -bool QNetworkAccessHttpBackend::waitForUpstreamBytesWritten(int msecs) -{ - - // ### FIXME: not implemented in QHttpNetworkAccess - Q_UNUSED(msecs); - qCritical("QNetworkAccess: HTTP backend does not support waitForBytesWritten()"); - return false; -} - -void QNetworkAccessHttpBackend::upstreamReadyRead() -{ - // There is more data available from the user to be uploaded - // QHttpNetworkAccess implements the upload rate control: - // we simply tell QHttpNetworkAccess that there is more data available - // it'll pull from us when it can (through uploadDevice) - - Q_ASSERT(uploadDevice); - emit uploadDevice->readyRead(); -} - -qint64 QNetworkAccessHttpBackend::deviceReadData(char *buffer, qint64 maxlen) -{ - QByteArray toBeUploaded = readUpstream(); - if (toBeUploaded.isEmpty()) - return 0; // nothing to be uploaded - - maxlen = qMin<qint64>(maxlen, toBeUploaded.length()); - - memcpy(buffer, toBeUploaded.constData(), maxlen); - upstreamBytesConsumed(maxlen); - return maxlen; -} void QNetworkAccessHttpBackend::downstreamReadyWrite() { @@ -904,7 +834,14 @@ bool QNetworkAccessHttpBackend::sendCacheContents(const QNetworkCacheMetaData &m checkForRedirect(status); - writeDownstreamData(contents); + emit metaDataChanged(); + + // invoke this asynchronously, else Arora/QtDemoBrowser don't like cached downloads + // see task 250221 / 251801 + qRegisterMetaType<QIODevice*>("QIODevice*"); + QMetaObject::invokeMethod(this, "writeDownstreamData", Qt::QueuedConnection, Q_ARG(QIODevice*, contents)); + + #if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) qDebug() << "Successfully sent cache:" << url() << contents->size() << "bytes"; #endif @@ -1036,21 +973,39 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo if (it != cacheHeaders.rawHeaders.constEnd()) metaData.setLastModified(QNetworkHeadersPrivate::fromHttpDate(it->second)); - bool canDiskCache = true; // Everything defaults to being cacheable on disk + bool canDiskCache; + // only cache GET replies by default, all other replies (POST, PUT, DELETE) + // are not cacheable by default (according to RFC 2616 section 9) + if (httpReply->request().operation() == QHttpNetworkRequest::Get) { + + canDiskCache = true; + // 14.32 + // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client + // had sent "Cache-Control: no-cache". + it = cacheHeaders.findRawHeader("pragma"); + if (it != cacheHeaders.rawHeaders.constEnd() + && it->second == "no-cache") + canDiskCache = false; + + // HTTP/1.1. Check the Cache-Control header + if (cacheControl.contains("no-cache")) + canDiskCache = false; + else if (cacheControl.contains("no-store")) + canDiskCache = false; + + // responses to POST might be cacheable + } else if (httpReply->request().operation() == QHttpNetworkRequest::Post) { - // 14.32 - // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client - // had sent "Cache-Control: no-cache". - it = cacheHeaders.findRawHeader("pragma"); - if (it != cacheHeaders.rawHeaders.constEnd() - && it->second == "no-cache") canDiskCache = false; + // some pages contain "expires:" and "cache-control: no-cache" field, + // so we only might cache POST requests if we get "cache-control: max-age ..." + if (cacheControl.contains("max-age")) + canDiskCache = true; - // HTTP/1.1. Check the Cache-Control header - if (cacheControl.contains("no-cache")) - canDiskCache = false; - else if (cacheControl.contains("no-store")) + // responses to PUT and DELETE are not cacheable + } else { canDiskCache = false; + } metaData.setSaveToDisk(canDiskCache); int statusCode = httpReply->statusCode(); diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h index 02915e7..225f944 100644 --- a/src/network/access/qnetworkaccesshttpbackend_p.h +++ b/src/network/access/qnetworkaccesshttpbackend_p.h @@ -79,11 +79,8 @@ public: virtual void open(); virtual void closeDownstreamChannel(); - virtual void closeUpstreamChannel(); virtual bool waitForDownstreamReadyRead(int msecs); - virtual bool waitForUpstreamBytesWritten(int msecs); - virtual void upstreamReadyRead(); virtual void downstreamReadyWrite(); virtual void copyFinished(QIODevice *); #ifndef QT_NO_OPENSSL @@ -96,6 +93,9 @@ public: qint64 deviceReadData(char *buffer, qint64 maxlen); + // we return true since HTTP needs to send PUT/POST data again after having authenticated + bool needsResetableUploadData() {return true;}; + private slots: void replyReadyRead(); void replyFinished(); @@ -108,7 +108,8 @@ private: QHttpNetworkReply *httpReply; QPointer<QNetworkAccessHttpBackendCache> http; QByteArray cacheKey; - QNetworkAccessHttpBackendIODevice *uploadDevice; + QNetworkAccessBackendUploadIODevice *uploadDevice; + #ifndef QT_NO_OPENSSL QSslConfiguration *pendingSslConfiguration; bool pendingIgnoreSslErrors; @@ -122,8 +123,6 @@ private: void postRequest(); void readFromHttp(); void checkForRedirect(const int statusCode); - - friend class QNetworkAccessHttpBackendIODevice; }; class QNetworkAccessHttpBackendFactory : public QNetworkAccessBackendFactory diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index bcbeef1..bf06ede 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -686,7 +686,10 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera priv->urlForLastAuthentication = url; } - // third step: setup the reply + // third step: find a backend + priv->backend = d->findBackend(op, request); + + // fourth step: setup the reply priv->setup(op, request, outgoingData); if (request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt() != QNetworkRequest::AlwaysNetwork) @@ -695,9 +698,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url())); priv->proxyList = proxyList; #endif - - // fourth step: find a backend - priv->backend = d->findBackend(op, request); if (priv->backend) { priv->backend->setParent(reply); priv->backend->reply = priv; diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index f4dad3c..0990b17 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -151,6 +151,10 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() authentication to serve the content but the credentials provided were not accepted (if any) + \value ContentReSendError the request needed to be sent + again, but this failed for example because the upload data + could not be read a second time. + \value ProtocolUnknownError the Network Access API cannot honor the request because the protocol is not known diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index 6f763b3..2f864fe 100644 --- a/src/network/access/qnetworkreply.h +++ b/src/network/access/qnetworkreply.h @@ -92,6 +92,7 @@ public: ContentOperationNotPermittedError, ContentNotFoundError, AuthenticationRequiredError, + ContentReSendError, UnknownContentError = 299, // protocol errors diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 79c3d1a..749a462 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -46,13 +46,15 @@ #include "QtCore/qcoreapplication.h" #include "QtCore/qdatetime.h" #include "QtNetwork/qsslconfiguration.h" +#include "qnetworkaccesshttpbackend_p.h" #include <QtCore/QCoreApplication> QT_BEGIN_NAMESPACE inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() - : copyDevice(0), networkCache(0), + : backend(0), outgoingData(0), outgoingDataBuffer(0), + copyDevice(0), networkCache(0), cacheEnabled(false), cacheSaveDevice(0), bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), state(Idle) @@ -61,8 +63,13 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() void QNetworkReplyImplPrivate::_q_startOperation() { - // This function is called exactly once + // ensure this function is only being called once + if (state == Working) { + qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); + return; + } state = Working; + if (!backend) { error(QNetworkReplyImpl::ProtocolUnknownError, QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!; @@ -74,57 +81,11 @@ void QNetworkReplyImplPrivate::_q_startOperation() if (state != Finished) { if (operation == QNetworkAccessManager::GetOperation) pendingNotifications.append(NotifyDownstreamReadyWrite); - if (outgoingData) { - _q_sourceReadyRead(); -#if 0 // ### FIXME - if (outgoingData->atEndOfStream() && writeBuffer.isEmpty()) - // empty upload - emit q->uploadProgress(0, 0); -#endif - } handleNotifications(); } } -void QNetworkReplyImplPrivate::_q_sourceReadyRead() -{ - // read data from the outgoingData QIODevice into our internal buffer - enum { DesiredBufferSize = 32 * 1024 }; - - if (writeBuffer.size() >= DesiredBufferSize) - return; // don't grow the buffer too much - - // read as many bytes are available or up until we fill up the buffer - // but always read at least one byte - qint64 bytesToRead = qBound<qint64>(1, outgoingData->bytesAvailable(), - DesiredBufferSize - writeBuffer.size()); - char *ptr = writeBuffer.reserve(bytesToRead); - qint64 bytesActuallyRead = outgoingData->read(ptr, bytesToRead); - if (bytesActuallyRead == -1) { - // EOF - writeBuffer.chop(bytesToRead); - backendNotify(NotifyCloseUpstreamChannel); - return; - } - - if (bytesActuallyRead < bytesToRead) - writeBuffer.chop(bytesToRead - bytesActuallyRead); - - // if we did read anything, let the backend know and handle it - if (bytesActuallyRead) - backendNotify(NotifyUpstreamReadyRead); - - // check for EOF again - if (!outgoingData->isSequential() && outgoingData->atEnd()) - backendNotify(NotifyCloseUpstreamChannel); -} - -void QNetworkReplyImplPrivate::_q_sourceReadChannelFinished() -{ - _q_sourceReadyRead(); -} - void QNetworkReplyImplPrivate::_q_copyReadyRead() { Q_Q(QNetworkReplyImpl); @@ -143,7 +104,7 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead() if (bytesActuallyRead == -1) { readBuffer.chop(bytesToRead); backendNotify(NotifyCopyFinished); - return; + break; } if (bytesActuallyRead != bytesToRead) @@ -151,6 +112,7 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead() if (!copyDevice->isSequential() && copyDevice->atEnd()) { backendNotify(NotifyCopyFinished); + bytesDownloaded += bytesActuallyRead; break; } @@ -174,6 +136,67 @@ void QNetworkReplyImplPrivate::_q_copyReadChannelFinished() _q_copyReadyRead(); } +void QNetworkReplyImplPrivate::_q_bufferOutgoingDataFinished() +{ + Q_Q(QNetworkReplyImpl); + + // make sure this is only called once, ever. + //_q_bufferOutgoingData may call it or the readChannelFinished emission + if (state != Buffering) + return; + + // disconnect signals + QObject::disconnect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); + QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); + + // finally, start the request + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); +} + +void QNetworkReplyImplPrivate::_q_bufferOutgoingData() +{ + Q_Q(QNetworkReplyImpl); + + if (!outgoingDataBuffer) { + // first call, create our buffer + outgoingDataBuffer = new QRingBuffer(); + + QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); + QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); + } + + qint64 bytesBuffered = 0; + qint64 bytesToBuffer = 0; + + // read data into our buffer + forever { + bytesToBuffer = outgoingData->bytesAvailable(); + // unknown? just try 2 kB, this also ensures we always try to read the EOF + if (bytesToBuffer <= 0) + bytesToBuffer = 2*1024; + + char *dst = outgoingDataBuffer->reserve(bytesToBuffer); + bytesBuffered = outgoingData->read(dst, bytesToBuffer); + + if (bytesBuffered == -1) { + // EOF has been reached. + outgoingDataBuffer->chop(bytesToBuffer); + + _q_bufferOutgoingDataFinished(); + break; + } else if (bytesBuffered == 0) { + // nothing read right now, just wait until we get called again + outgoingDataBuffer->chop(bytesToBuffer); + + break; + } else { + // don't break, try to read() again + outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered); + } + } +} + + void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *data) { @@ -184,13 +207,42 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const url = request.url(); operation = op; - if (outgoingData) { - q->connect(outgoingData, SIGNAL(readyRead()), SLOT(_q_sourceReadyRead())); - q->connect(outgoingData, SIGNAL(readChannelFinished()), SLOT(_q_sourceReadChannelFinished())); + if (outgoingData && backend) { + // there is data to be uploaded, e.g. HTTP POST. + + if (!backend->needsResetableUploadData() || !outgoingData->isSequential()) { + // backend does not need upload buffering or + // fixed size non-sequential + // just start the operation + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); + } else { + bool bufferingDisallowed = + req.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, + false).toBool(); + + if (bufferingDisallowed) { + // if a valid content-length header for the request was supplied, we can disable buffering + // if not, we will buffer anyway + if (req.header(QNetworkRequest::ContentLengthHeader).isValid()) { + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); + } else { + state = Buffering; + QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection); + } + } else { + // _q_startOperation will be called when the buffering has finished. + state = Buffering; + QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection); + } + } + } else { + // No outgoing data (e.g. HTTP GET request) + // or no backend + // if no backend, _q_startOperation will handle the error of this + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); } q->QIODevice::open(QIODevice::ReadOnly); - QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); } void QNetworkReplyImplPrivate::setNetworkCache(QAbstractNetworkCache *nc) @@ -226,18 +278,10 @@ void QNetworkReplyImplPrivate::handleNotifications() backend->downstreamReadyWrite(); break; - case NotifyUpstreamReadyRead: - backend->upstreamReadyRead(); - break; - case NotifyCloseDownstreamChannel: backend->closeDownstreamChannel(); break; - case NotifyCloseUpstreamChannel: - backend->closeUpstreamChannel(); - break; - case NotifyCopyFinished: { QIODevice *dev = copyDevice; copyDevice = 0; @@ -299,29 +343,14 @@ void QNetworkReplyImplPrivate::completeCacheSave() cacheEnabled = false; } -void QNetworkReplyImplPrivate::consume(qint64 count) +void QNetworkReplyImplPrivate::emitUploadProgress(qint64 bytesSent, qint64 bytesTotal) { Q_Q(QNetworkReplyImpl); - if (count <= 0) { - qWarning("QNetworkConnection: backend signalled that it consumed %ld bytes", long(count)); - return; - } - - if (outgoingData) - // schedule another read from the source - QMetaObject::invokeMethod(q_func(), "_q_sourceReadyRead", Qt::QueuedConnection); - - writeBuffer.skip(count); - if (bytesUploaded == -1) - bytesUploaded = count; - else - bytesUploaded += count; - - QVariant totalSize = request.header(QNetworkRequest::ContentLengthHeader); - emit q->uploadProgress(bytesUploaded, - totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); + bytesUploaded = bytesSent; + emit q->uploadProgress(bytesSent, bytesTotal); } + qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const { enum { DesiredBufferSize = 32 * 1024 }; @@ -331,7 +360,9 @@ qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const return qMax<qint64>(0, readBufferMaxSize - readBuffer.size()); } -void QNetworkReplyImplPrivate::feed(const QByteArray &data) +// we received downstream data and send this to the cache +// and to our readBuffer (which in turn gets read by the user of QNetworkReply) +void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data) { Q_Q(QNetworkReplyImpl); if (!q->isOpen()) @@ -379,7 +410,8 @@ void QNetworkReplyImplPrivate::feed(const QByteArray &data) } } -void QNetworkReplyImplPrivate::feed(QIODevice *data) +// this is used when it was fetched from the cache, right? +void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data) { Q_Q(QNetworkReplyImpl); Q_ASSERT(q->isOpen()); @@ -409,9 +441,11 @@ void QNetworkReplyImplPrivate::finished() pendingNotifications.clear(); QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); - if (bytesDownloaded != lastBytesDownloaded || totalSize.isNull()) + if (totalSize.isNull() || totalSize == -1) { emit q->downloadProgress(bytesDownloaded, bytesDownloaded); - if (bytesUploaded == -1 && outgoingData) + } + + if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer)) emit q->uploadProgress(0, 0); completeCacheSave(); diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index ad06f78..8d3c90e 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -59,6 +59,7 @@ #include "qnetworkproxy.h" #include "QtCore/qmap.h" #include "QtCore/qqueue.h" +#include "QtCore/qbuffer.h" #include "private/qringbuffer_p.h" QT_BEGIN_NAMESPACE @@ -91,10 +92,10 @@ public: Q_DECLARE_PRIVATE(QNetworkReplyImpl) Q_PRIVATE_SLOT(d_func(), void _q_startOperation()) - Q_PRIVATE_SLOT(d_func(), void _q_sourceReadyRead()) - Q_PRIVATE_SLOT(d_func(), void _q_sourceReadChannelFinished()) Q_PRIVATE_SLOT(d_func(), void _q_copyReadyRead()) Q_PRIVATE_SLOT(d_func(), void _q_copyReadChannelFinished()) + Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingData()) + Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingDataFinished()) }; class QNetworkReplyImplPrivate: public QNetworkReplyPrivate @@ -102,15 +103,13 @@ class QNetworkReplyImplPrivate: public QNetworkReplyPrivate public: enum InternalNotifications { NotifyDownstreamReadyWrite, - NotifyUpstreamReadyRead, NotifyCloseDownstreamChannel, - NotifyCloseUpstreamChannel, NotifyCopyFinished }; enum State { Idle, - Opening, + Buffering, Working, Finished, Aborted @@ -125,6 +124,8 @@ public: void _q_sourceReadChannelFinished(); void _q_copyReadyRead(); void _q_copyReadChannelFinished(); + void _q_bufferOutgoingData(); + void _q_bufferOutgoingDataFinished(); void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData); @@ -138,9 +139,10 @@ public: void setCachingEnabled(bool enable); bool isCachingEnabled() const; void consume(qint64 count); + void emitUploadProgress(qint64 bytesSent, qint64 bytesTotal); qint64 nextDownstreamBlockSize() const; - void feed(const QByteArray &data); - void feed(QIODevice *data); + void appendDownstreamData(const QByteArray &data); + void appendDownstreamData(QIODevice *data); void finished(); void error(QNetworkReply::NetworkError code, const QString &errorString); void metaDataChanged(); @@ -149,6 +151,7 @@ public: QNetworkAccessBackend *backend; QIODevice *outgoingData; + QRingBuffer *outgoingDataBuffer; QIODevice *copyDevice; QAbstractNetworkCache *networkCache; diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 56b793d..8b1afba 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -162,6 +162,13 @@ QT_BEGIN_NAMESPACE Indicates whether the data was obtained from cache or not. + \value DoNotBufferUploadDataAttribute + Requests only, type: QVariant::Bool (default: false) + Indicates whether the QNetworkAccessManager code is + allowed to buffer the upload data, e.g. when doing a HTTP POST. + When using this flag with sequential upload data, the ContentLengthHeader + header must be set. + \value User Special type. Additional information can be passed in QVariants with types ranging from User to UserMax. The default diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 6f34bce..5dea1df 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -75,6 +75,7 @@ public: CacheLoadControlAttribute, CacheSaveControlAttribute, SourceIsFromCacheAttribute, + DoNotBufferUploadDataAttribute, User = 1000, UserMax = 32767 diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 0bfed12..83e6717 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -172,7 +172,7 @@ QGLPixmapColorizeFilter::QGLPixmapColorizeFilter() m_program.addShader(QGLShader::FragmentShader, qt_gl_colorize_filter); m_program.link(); m_program.enable(); - m_program.setUniformValue(m_program.uniformLocation("texture"),GLint(0)); // GL_TEXTURE_0 + m_program.setUniformValue(m_program.uniformLocation("texture"), GLint(0)); // GL_TEXTURE_0 m_colorUniform = m_program.uniformLocation("color"); } diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h index d4552e3..d1fd0da 100644 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -115,6 +115,7 @@ public: class QAccessibleLineEdit : public QAccessibleWidgetEx, public QAccessibleTextInterface, public QAccessibleSimpleEditableTextInterface { + Q_ACCESSIBLE_OBJECT public: explicit QAccessibleLineEdit(QWidget *o, const QString &name = QString()); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index 91a60e7..989a37a 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -275,7 +275,6 @@ private: int lastLockedHeight; IDirectFB *fb; - DFBSurfaceDescription fbDescription; int fbWidth; int fbHeight; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index 7297a99..c9b676a 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -271,7 +271,7 @@ void QDirectFBPixmapData::fill(const QColor &color) forceRaster = false; setSerialNumber(++global_ser_no); if (!dfbSurface) { - qWarning("QDirecttFBPixmapData::fill()"); + qWarning("QDirectFBPixmapData::fill()"); invalidate(); return; } diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp index f571d1b..98e32ed 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -205,6 +205,7 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size, SurfaceCreationOptions options) { DFBSurfaceDescription desc; + memset(&desc, 0, sizeof(DFBSurfaceDescription)); desc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH|DSDESC_HEIGHT); if (!QDirectFBScreen::initSurfaceDescriptionPixelFormat(&desc, format)) return 0; @@ -213,7 +214,6 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size, return createDFBSurface(desc, options); } - IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, SurfaceCreationOptions options) { DFBResult result = DFB_OK; @@ -247,6 +247,7 @@ IDirectFBSurface *QDirectFBScreen::createDFBSurface(DFBSurfaceDescription desc, } desc.caps = DFBSurfaceCapabilities(desc.caps & ~DSCAPS_VIDEOONLY); } + if (d_ptr->directFBFlags & SystemOnly) desc.caps = DFBSurfaceCapabilities(desc.caps | DSCAPS_SYSTEMONLY); @@ -293,14 +294,14 @@ IDirectFBSurface *QDirectFBScreen::copyToDFBSurface(const QImage &img, IDirectFBSurface *dfbSurface = createDFBSurface(image.size(), pixmapFormat, options); if (!dfbSurface) { - qWarning("QDirectFBPixmapData::fromImage() Couldn't create surface"); + qWarning("QDirectFBScreen::copyToDFBSurface() Couldn't create surface"); return 0; } #ifndef QT_NO_DIRECTFB_PREALLOCATED IDirectFBSurface *imgSurface = createDFBSurface(image, DontTrackSurface); if (!imgSurface) { - qWarning("QDirectFBPixmapData::fromImage()"); + qWarning("QDirectFBScreen::copyToDFBSurface()"); QDirectFBScreen::releaseDFBSurface(dfbSurface); return 0; } @@ -315,7 +316,7 @@ IDirectFBSurface *QDirectFBScreen::copyToDFBSurface(const QImage &img, dfbSurface->SetBlittingFlags(dfbSurface, flags); DFBResult result = dfbSurface->Blit(dfbSurface, imgSurface, 0, 0, 0); if (result != DFB_OK) - DirectFBError("QDirectFBPixmapData::fromImage()", result); + DirectFBError("QDirectFBScreen::copyToDFBSurface()", result); dfbSurface->ReleaseSource(dfbSurface); imgSurface->Release(imgSurface); #else // QT_NO_DIRECTFB_PREALLOCATED @@ -445,6 +446,7 @@ QImage::Format QDirectFBScreen::getImageFormat(IDirectFBSurface *surface) DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const QImage &image) { DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); const DFBSurfacePixelFormat format = getSurfacePixelFormat(image.format()); @@ -479,6 +481,7 @@ DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const uint *buffer, int length) { DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS | DSDESC_WIDTH @@ -917,6 +920,8 @@ bool QDirectFBScreen::connect(const QString &displaySpec) d_ptr->dfb->SetCooperativeLevel(d_ptr->dfb, DFSCL_FULLSCREEN); DFBSurfaceDescription description; + memset(&description, 0, sizeof(DFBSurfaceDescription)); + description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS); if (::setIntOption(displayArgs, QLatin1String("width"), &description.width)) description.flags = DFBSurfaceDescriptionFlags(description.flags | DSDESC_WIDTH); diff --git a/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp b/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp index c7249d3..3273513 100644 --- a/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp +++ b/src/plugins/iconengines/svgiconengine/qsvgiconengine.cpp @@ -122,16 +122,10 @@ QSize QSvgIconEngine::actualSize(const QSize &size, QIcon::Mode mode, return size; } - QSvgRenderer renderer; - d->loadDataForModeAndState(&renderer, mode, state); - if (renderer.isValid()) { - QSize defaultSize = renderer.defaultSize(); - if (!defaultSize.isNull()) - defaultSize.scale(size, Qt::KeepAspectRatio); - return defaultSize; - } else { + QPixmap pm = pixmap(size, mode, state); + if (pm.isNull()) return QSize(); - } + return pm.size(); } void QSvgIconEnginePrivate::loadDataForModeAndState(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state) diff --git a/src/sql/drivers/ibase/qsql_ibase.cpp b/src/sql/drivers/ibase/qsql_ibase.cpp index 6834d9a..4f3d79d 100644 --- a/src/sql/drivers/ibase/qsql_ibase.cpp +++ b/src/sql/drivers/ibase/qsql_ibase.cpp @@ -66,8 +66,11 @@ QT_BEGIN_NAMESPACE enum { QIBaseChunkSize = SHRT_MAX / 2 }; -static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, - QTextCodec *tc) +#if defined(FB_API_VER) && FB_API_VER >= 20 +static bool getIBaseError(QString& msg, const ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc) +#else +static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc) +#endif { if (status[0] != 1 || status[1] <= 0) return false; @@ -75,7 +78,11 @@ static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, msg.clear(); sqlcode = isc_sqlcode(status); char buf[512]; +#if defined(FB_API_VER) && FB_API_VER >= 20 + while(fb_interpret(buf, 512, &status)) { +#else while(isc_interprete(buf, &status)) { +#endif if(!msg.isEmpty()) msg += QLatin1String(" - "); if (tc) diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp index 1f54db7..fbefa0c 100644 --- a/src/sql/drivers/mysql/qsql_mysql.cpp +++ b/src/sql/drivers/mysql/qsql_mysql.cpp @@ -163,18 +163,21 @@ static inline QVariant qDateTimeFromString(QString &val) #endif } -class QMYSQLResultPrivate +class QMYSQLResultPrivate : public QObject { + Q_OBJECT public: - QMYSQLResultPrivate(QMYSQLDriverPrivate* dp) : d(dp), result(0), + QMYSQLResultPrivate(const QMYSQLDriver* dp) : driver(dp), result(0), rowsAffected(0), hasBlobs(false) #if MYSQL_VERSION_ID >= 40108 , stmt(0), meta(0), inBinds(0), outBinds(0) #endif , precisionPolicy(QSql::HighPrecision) - {} + { + connect(dp, SIGNAL(destroyed()), this, SLOT(driverDestroyed())); + } - QMYSQLDriverPrivate* d; + const QMYSQLDriver* driver; MYSQL_RES *result; MYSQL_ROW row; @@ -207,6 +210,8 @@ public: MYSQL_BIND *outBinds; #endif QSql::NumericalPrecisionPolicy precisionPolicy; +private Q_SLOTS: + void driverDestroyed() { driver = NULL; } }; #ifndef QT_NO_TEXTCODEC @@ -379,7 +384,7 @@ bool QMYSQLResultPrivate::bindInValues() QMYSQLResult::QMYSQLResult(const QMYSQLDriver* db) : QSqlResult(db) { - d = new QMYSQLResultPrivate(db->d); + d = new QMYSQLResultPrivate(db); } QMYSQLResult::~QMYSQLResult() @@ -391,7 +396,7 @@ QMYSQLResult::~QMYSQLResult() QVariant QMYSQLResult::handle() const { #if MYSQL_VERSION_ID >= 40108 - if(d->d->preparedQuerys) + if(d->driver && d->driver->d->preparedQuerys) return d->meta ? qVariantFromValue(d->meta) : qVariantFromValue(d->stmt); else #endif @@ -406,8 +411,8 @@ void QMYSQLResult::cleanup() // must iterate trough leftover result sets from multi-selects or stored procedures // if this isn't done subsequent queries will fail with "Commands out of sync" #if MYSQL_VERSION_ID >= 40100 - while (d->d->mysql && mysql_next_result(d->d->mysql) == 0) { - MYSQL_RES *res = mysql_store_result(d->d->mysql); + while (d->driver && d->driver->d->mysql && mysql_next_result(d->driver->d->mysql) == 0) { + MYSQL_RES *res = mysql_store_result(d->driver->d->mysql); if (res) mysql_free_result(res); } @@ -447,11 +452,14 @@ void QMYSQLResult::cleanup() setAt(-1); setActive(false); - d->d->preparedQuerys = d->d->preparedQuerysEnabled; + if(d->driver) + d->driver->d->preparedQuerys = d->driver->d->preparedQuerysEnabled; } bool QMYSQLResult::fetch(int i) { + if(!d->driver) + return false; if (isForwardOnly()) { // fake a forward seek if (at() < i) { int x = i - at(); @@ -463,7 +471,7 @@ bool QMYSQLResult::fetch(int i) } if (at() == i) return true; - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { #if MYSQL_VERSION_ID >= 40108 mysql_stmt_data_seek(d->stmt, i); @@ -494,7 +502,9 @@ bool QMYSQLResult::fetch(int i) bool QMYSQLResult::fetchNext() { - if (d->d->preparedQuerys) { + if(!d->driver) + return false; + if (d->driver->d->preparedQuerys) { #if MYSQL_VERSION_ID >= 40108 if (mysql_stmt_fetch(d->stmt)) return false; @@ -512,6 +522,8 @@ bool QMYSQLResult::fetchNext() bool QMYSQLResult::fetchLast() { + if(!d->driver) + return false; if (isForwardOnly()) { // fake this since MySQL can't seek on forward only queries bool success = fetchNext(); // did we move at all? while (fetchNext()) {}; @@ -519,7 +531,7 @@ bool QMYSQLResult::fetchLast() } my_ulonglong numRows; - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { #if MYSQL_VERSION_ID >= 40108 numRows = mysql_stmt_num_rows(d->stmt); #else @@ -553,15 +565,18 @@ QVariant QMYSQLResult::data(int field) return QVariant(); } + if (!d->driver) + return QVariant(); + int fieldLength = 0; const QMYSQLResultPrivate::QMyField &f = d->fields.at(field); QString val; - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { if (f.nullIndicator) return QVariant(f.type); if (f.type != QVariant::ByteArray) - val = toUnicode(d->d->tc, f.outField, f.bufLength); + val = toUnicode(d->driver->d->tc, f.outField, f.bufLength); } else { if (d->row[field] == NULL) { // NULL value @@ -569,7 +584,7 @@ QVariant QMYSQLResult::data(int field) } fieldLength = mysql_fetch_lengths(d->result)[field]; if (f.type != QVariant::ByteArray) - val = toUnicode(d->d->tc, d->row[field], fieldLength); + val = toUnicode(d->driver->d->tc, d->row[field], fieldLength); } switch(f.type) { @@ -614,7 +629,7 @@ QVariant QMYSQLResult::data(int field) case QVariant::ByteArray: { QByteArray ba; - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { ba = QByteArray(f.outField, f.bufLength); } else { ba = QByteArray(d->row[field], fieldLength); @@ -631,7 +646,7 @@ QVariant QMYSQLResult::data(int field) bool QMYSQLResult::isNull(int field) { - if (d->d->preparedQuerys) + if (d->driver->d->preparedQuerys) return d->fields.at(field).nullIndicator; else return d->row[field] == NULL; @@ -639,31 +654,31 @@ bool QMYSQLResult::isNull(int field) bool QMYSQLResult::reset (const QString& query) { - if (!driver() || !driver()->isOpen() || driver()->isOpenError()) + if (!driver() || !driver()->isOpen() || driver()->isOpenError() || !d->driver) return false; - if(d->d->preparedQuerysEnabled && prepare(query)) { - d->d->preparedQuerys = true; + if(d->driver->d->preparedQuerysEnabled && prepare(query)) { + d->driver->d->preparedQuerys = true; return exec(); } - d->d->preparedQuerys = false; + d->driver->d->preparedQuerys = false; - const QByteArray encQuery(fromUnicode(d->d->tc, query)); - if (mysql_real_query(d->d->mysql, encQuery.data(), encQuery.length())) { + const QByteArray encQuery(fromUnicode(d->driver->d->tc, query)); + if (mysql_real_query(d->driver->d->mysql, encQuery.data(), encQuery.length())) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } - d->result = mysql_store_result(d->d->mysql); - if (!d->result && mysql_field_count(d->d->mysql) > 0) { + d->result = mysql_store_result(d->driver->d->mysql); + if (!d->result && mysql_field_count(d->driver->d->mysql) > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } - int numFields = mysql_field_count(d->d->mysql); + int numFields = mysql_field_count(d->driver->d->mysql); setSelect(numFields != 0); d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->d->mysql); + d->rowsAffected = mysql_affected_rows(d->driver->d->mysql); if (isSelect()) { for(int i = 0; i < numFields; i++) { MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i); @@ -677,8 +692,8 @@ bool QMYSQLResult::reset (const QString& query) int QMYSQLResult::size() { - if (isSelect()) - if (d->d->preparedQuerys) + if (d->driver && isSelect()) + if (d->driver->d->preparedQuerys) #if MYSQL_VERSION_ID >= 40108 return mysql_stmt_num_rows(d->stmt); #else @@ -697,17 +712,17 @@ int QMYSQLResult::numRowsAffected() QVariant QMYSQLResult::lastInsertId() const { - if (!isActive()) + if (!isActive() || !d->driver) return QVariant(); - if (d->d->preparedQuerys) { + if (d->driver->d->preparedQuerys) { #if MYSQL_VERSION_ID >= 40108 quint64 id = mysql_stmt_insert_id(d->stmt); if (id) return QVariant(id); #endif } else { - quint64 id = mysql_insert_id(d->d->mysql); + quint64 id = mysql_insert_id(d->driver->d->mysql); if (id) return QVariant(id); } @@ -718,20 +733,20 @@ QSqlRecord QMYSQLResult::record() const { QSqlRecord info; MYSQL_RES *res; - if (!isActive() || !isSelect()) + if (!isActive() || !isSelect() || !d->driver) return info; #if MYSQL_VERSION_ID >= 40108 - res = d->d->preparedQuerys ? d->meta : d->result; + res = d->driver->d->preparedQuerys ? d->meta : d->result; #else res = d->result; #endif - if (!mysql_errno(d->d->mysql)) { + if (!mysql_errno(d->driver->d->mysql)) { mysql_field_seek(res, 0); MYSQL_FIELD* field = mysql_fetch_field(res); while(field) { - info.append(qToField(field, d->d->tc)); + info.append(qToField(field, d->driver->d->tc)); field = mysql_fetch_field(res); } } @@ -741,6 +756,8 @@ QSqlRecord QMYSQLResult::record() const bool QMYSQLResult::nextResult() { + if(!d->driver) + return false; #if MYSQL_VERSION_ID >= 40100 setAt(-1); setActive(false); @@ -754,26 +771,26 @@ bool QMYSQLResult::nextResult() delete[] d->fields[i].outField; d->fields.clear(); - int status = mysql_next_result(d->d->mysql); + int status = mysql_next_result(d->driver->d->mysql); if (status > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } else if (status == -1) { return false; // No more result sets } - d->result = mysql_store_result(d->d->mysql); - int numFields = mysql_field_count(d->d->mysql); + d->result = mysql_store_result(d->driver->d->mysql); + int numFields = mysql_field_count(d->driver->d->mysql); if (!d->result && numFields > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } setSelect(numFields > 0); d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->d->mysql); + d->rowsAffected = mysql_affected_rows(d->driver->d->mysql); if (isSelect()) { for (int i = 0; i < numFields; i++) { @@ -833,9 +850,11 @@ static MYSQL_TIME *toMySqlDate(QDate date, QTime time, QVariant::Type type) bool QMYSQLResult::prepare(const QString& query) { + if(!d->driver) + return false; #if MYSQL_VERSION_ID >= 40108 cleanup(); - if (!d->d->preparedQuerys) + if (!d->driver->d->preparedQuerys) return QSqlResult::prepare(query); int r; @@ -844,14 +863,14 @@ bool QMYSQLResult::prepare(const QString& query) return false; if (!d->stmt) - d->stmt = mysql_stmt_init(d->d->mysql); + d->stmt = mysql_stmt_init(d->driver->d->mysql); if (!d->stmt) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"), - QSqlError::StatementError, d->d)); + QSqlError::StatementError, d->driver->d)); return false; } - const QByteArray encQuery(fromUnicode(d->d->tc, query)); + const QByteArray encQuery(fromUnicode(d->driver->d->tc, query)); r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length()); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", @@ -873,7 +892,9 @@ bool QMYSQLResult::prepare(const QString& query) bool QMYSQLResult::exec() { - if (!d->d->preparedQuerys) + if (!d->driver) + return false; + if (!d->driver->d->preparedQuerys) return QSqlResult::exec(); if (!d->stmt) return false; @@ -963,7 +984,7 @@ bool QMYSQLResult::exec() break; case QVariant::String: default: { - QByteArray ba = fromUnicode(d->d->tc, val.toString()); + QByteArray ba = fromUnicode(d->driver->d->tc, val.toString()); stringVector.append(ba); currBind->buffer_type = MYSQL_TYPE_STRING; currBind->buffer = const_cast<char *>(ba.constData()); @@ -1459,3 +1480,5 @@ bool QMYSQLDriver::isIdentifierEscapedImplementation(const QString &identifier, } QT_END_NAMESPACE + +#include "qsql_mysql.moc"
\ No newline at end of file diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 6232452..a270c0e 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -378,7 +378,7 @@ void QSqlDatabasePrivate::disable() the connection name argument, if you don't pass the connection name argument, the default connection is assumed. The following snippet shows how to create and open a default connection to a - MySQL database: + PostgreSQL database: \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 0 diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 8c76c5d..041f2db 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1465,8 +1465,12 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) #if !defined(QT_NO_PROCESS) || !defined(QT_NO_SETTINGS) if (QBenchmarkGlobalData::current->createChart) { - QString chartLocation = QLibraryInfo::location(QLibraryInfo::BinariesPath) - + QLatin1String("/../tools/qtestlib/chart/chart"); + QString chartLocation = QLibraryInfo::location(QLibraryInfo::BinariesPath); +#ifdef Q_OS_WIN + chartLocation += QLatin1String("/../tools/qtestlib/chart/release/chart.exe"); +#else + chartLocation += QLatin1String("/../tools/qtestlib/chart/chart"); +#endif if (QFile::exists(chartLocation)) { QProcess p; p.setProcessChannelMode(QProcess::ForwardedChannels); diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 869f1c4..331546d 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -212,6 +212,7 @@ SUBDIRS += bic \ qnumeric \ qobject \ qobjectrace \ + qcontiguouscache \ qpaintengine \ qpainter \ qpainterpath \ @@ -243,6 +244,7 @@ SUBDIRS += bic \ qregexpvalidator \ qregion \ qresourceengine \ + qringbuffer \ qscriptable \ qscriptclass \ qscriptcontext \ diff --git a/tests/auto/declarative/anchors/data/anchors.qml b/tests/auto/declarative/anchors/data/anchors.qml new file mode 100644 index 0000000..6a87390 --- /dev/null +++ b/tests/auto/declarative/anchors/data/anchors.qml @@ -0,0 +1,115 @@ +Rect { + color: "white" + width: 240 + height: 320 + Rect { id: MasterRect; x: 26; width: 96; height: 20; color: "red" } + Rect { + id: Rect1 + y: 20; width: 10; height: 10 + anchors.left: MasterRect.left + } + Rect { + id: Rect2 + y: 20; width: 10; height: 10 + anchors.left: MasterRect.right + } + Rect { + id: Rect3 + y: 20; width: 10; height: 10 + anchors.left: MasterRect.horizontalCenter + } + Rect { + id: Rect4 + y: 30; width: 10; height: 10 + anchors.right: MasterRect.left + } + Rect { + id: Rect5 + y: 30; width: 10; height: 10 + anchors.right: MasterRect.right + } + Rect { + id: Rect6 + y: 30; width: 10; height: 10 + anchors.right: MasterRect.horizontalCenter + } + Rect { + id: Rect7 + y: 50; width: 10; height: 10 + anchors.left: parent.left + } + Rect { + id: Rect8 + y: 50; width: 10; height: 10 + anchors.left: parent.right + } + Rect { + id: Rect9 + y: 50; width: 10; height: 10 + anchors.left: parent.horizontalCenter + } + Rect { + id: Rect10 + y: 60; width: 10; height: 10 + anchors.right: parent.left + } + Rect { + id: Rect11 + y: 60; width: 10; height: 10 + anchors.right: parent.right + } + Rect { + id: Rect12 + y: 60; width: 10; height: 10 + anchors.right: parent.horizontalCenter + } + Rect { + id: Rect13 + x: 200; width: 10; height: 10 + anchors.top: MasterRect.bottom + } + Rect { + id: Rect14 + width: 10; height: 10; color: "steelblue" + anchors.verticalCenter: parent.verticalCenter + } + Rect { + id: Rect15 + y: 200; height: 10 + anchors.left: MasterRect.left + anchors.right: MasterRect.right + } + Rect { + id: Rect16 + y: 220; height: 10 + anchors.left: MasterRect.left + anchors.horizontalCenter: MasterRect.right + } + Rect { + id: Rect17 + y: 240; height: 10 + anchors.right: MasterRect.right + anchors.horizontalCenter: MasterRect.left + } + Rect { + id: Rect18 + x: 180; width: 10 + anchors.top: MasterRect.bottom + anchors.bottom: Rect12.top + } + Rect { + id: Rect19 + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.horizontalCenter + } + Rect { + id: Rect20 + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.right + } + Rect { + id: Rect21 + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.left + } +} diff --git a/tests/auto/declarative/anchors/tst_anchors.cpp b/tests/auto/declarative/anchors/tst_anchors.cpp index 683a7b9..8087d6e 100644 --- a/tests/auto/declarative/anchors/tst_anchors.cpp +++ b/tests/auto/declarative/anchors/tst_anchors.cpp @@ -2,8 +2,7 @@ #include <QtDeclarative/qmlengine.h> #include <QtDeclarative/qmlcomponent.h> #include <QtDeclarative/qfxview.h> -#include <QtDeclarative/qfximage.h> -#include <QtDeclarative/qfxtext.h> +#include <QtDeclarative/qfxrect.h> class tst_anchors : public QObject { @@ -11,10 +10,82 @@ class tst_anchors : public QObject public: tst_anchors() {} + template<typename T> + T *findItem(QFxItem *parent, const QString &id); + private slots: + void basicAnchors(); void loops(); }; +/* + Find an item with the specified id. +*/ +template<typename T> +T *tst_anchors::findItem(QFxItem *parent, const QString &id) +{ + const QMetaObject &mo = T::staticMetaObject; + for (int i = 0; i < parent->QSimpleCanvasItem::children().count(); ++i) { + QFxItem *item = qobject_cast<QFxItem*>(parent->QSimpleCanvasItem::children().at(i)); + if (mo.cast(item) && (id.isEmpty() || item->id() == id)) { + return static_cast<T*>(item); + } + item = findItem<T>(item, id); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + +void tst_anchors::basicAnchors() +{ + QFxView *view = new QFxView; + view->setUrl(QUrl("file://" SRCDIR "/data/anchors.qml")); + + view->execute(); + qApp->processEvents(); + + //sibling horizontal + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect1"))->x(), 26.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect2"))->x(), 122.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect3"))->x(), 74.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect4"))->x(), 16.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect5"))->x(), 112.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect6"))->x(), 64.0); + + //parent horizontal + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect7"))->x(), 0.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect8"))->x(), 240.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect9"))->x(), 120.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect10"))->x(), -10.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect11"))->x(), 230.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect12"))->x(), 110.0); + + //vertical + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect13"))->y(), 20.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect14"))->y(), 155.0); + + //stretch + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect15"))->x(), 26.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect15"))->width(), 96.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect16"))->x(), 26.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect16"))->width(), 192.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect17"))->x(), -70.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect17"))->width(), 192.0); + + //vertical stretch + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect18"))->y(), 20.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect18"))->height(), 40.0); + + //more parent horizontal + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect19"))->x(), 115.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect20"))->x(), 235.0); + QCOMPARE(findItem<QFxRect>(view->root(), QLatin1String("Rect21"))->x(), -5.0); + + delete view; +} + // mostly testing that we don't crash void tst_anchors::loops() { diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index b6e3584..14d8c24 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -14,7 +14,8 @@ SUBDIRS += datetimeformatter \ qmlmetaproperty \ qmllist \ qmllistaccessor \ - visual + visual\ + qmlengine # Tests which should run in Pulse PULSE_TESTS = $$SUBDIRS diff --git a/tests/auto/declarative/qmlbindengine/idShortcutInvalidates.1.txt b/tests/auto/declarative/qmlbindengine/idShortcutInvalidates.1.txt new file mode 100644 index 0000000..2687465 --- /dev/null +++ b/tests/auto/declarative/qmlbindengine/idShortcutInvalidates.1.txt @@ -0,0 +1,10 @@ +MyQmlObject { + objectProperty: if(1) OtherObject + + property var obj + + obj: Object { + id: OtherObject + } +} + diff --git a/tests/auto/declarative/qmlbindengine/idShortcutInvalidates.txt b/tests/auto/declarative/qmlbindengine/idShortcutInvalidates.txt new file mode 100644 index 0000000..4aa20ae --- /dev/null +++ b/tests/auto/declarative/qmlbindengine/idShortcutInvalidates.txt @@ -0,0 +1,9 @@ +MyQmlObject { + objectProperty: OtherObject + + property var obj + + obj: Object { + id: OtherObject + } +} diff --git a/tests/auto/declarative/qmlbindengine/qmlbindengine.pro b/tests/auto/declarative/qmlbindengine/qmlbindengine.pro index 800d9a0..4a38ac9 100644 --- a/tests/auto/declarative/qmlbindengine/qmlbindengine.pro +++ b/tests/auto/declarative/qmlbindengine/qmlbindengine.pro @@ -1,7 +1,9 @@ load(qttest_p4) contains(QT_CONFIG,declarative): QT += declarative macx:CONFIG -= app_bundle -SOURCES += tst_qmlbindengine.cpp +SOURCES += tst_qmlbindengine.cpp \ + testtypes.cpp +HEADERS += testtypes.h # QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage # LIBS += -lgcov diff --git a/tests/auto/declarative/qmlbindengine/testtypes.cpp b/tests/auto/declarative/qmlbindengine/testtypes.cpp new file mode 100644 index 0000000..4bb0dc8 --- /dev/null +++ b/tests/auto/declarative/qmlbindengine/testtypes.cpp @@ -0,0 +1,4 @@ +#include "testtypes.h" + +QML_DEFINE_TYPE(MyQmlObject,MyQmlObject); +QML_DEFINE_TYPE(MyQmlContainer,MyQmlContainer); diff --git a/tests/auto/declarative/qmlbindengine/testtypes.h b/tests/auto/declarative/qmlbindengine/testtypes.h new file mode 100644 index 0000000..6a4bda6 --- /dev/null +++ b/tests/auto/declarative/qmlbindengine/testtypes.h @@ -0,0 +1,127 @@ +#ifndef TESTTYPES_H +#define TESTTYPES_H + +#include <QtCore/qobject.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlexpression.h> + +class MyQmlObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool trueProperty READ trueProperty) + Q_PROPERTY(bool falseProperty READ falseProperty) + Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged) + Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged); +public: + MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false), m_object(0) {} + + bool trueProperty() const { return true; } + bool falseProperty() const { return false; } + + QString stringProperty() const { return m_string; } + void setStringProperty(const QString &s) + { + if (s == m_string) + return; + m_string = s; + emit stringChanged(); + } + + QObject *objectProperty() const { return m_object; } + void setObjectProperty(QObject *obj) { + if (obj == m_object) + return; + m_object = obj; + emit objectChanged(); + } + + bool methodCalled() const { return m_methodCalled; } + bool methodIntCalled() const { return m_methodIntCalled; } + + QString string() const { return m_string; } +signals: + void basicSignal(); + void argumentSignal(int a, QString b, qreal c); + void stringChanged(); + void objectChanged(); + +public slots: + void method() { m_methodCalled = true; } + void method(int a) { if(a == 163) m_methodIntCalled = true; } + void setString(const QString &s) { m_string = s; } + +private: + friend class tst_qmlbindengine; + bool m_methodCalled; + bool m_methodIntCalled; + + QObject *m_object; + QString m_string; +}; + +QML_DECLARE_TYPE(MyQmlObject); + +class MyQmlContainer : public QObject +{ + Q_OBJECT + Q_PROPERTY(QList<MyQmlContainer*>* children READ children) +public: + MyQmlContainer() {} + + QList<MyQmlContainer*> *children() { return &m_children; } + +private: + QList<MyQmlContainer*> m_children; +}; + +QML_DECLARE_TYPE(MyQmlContainer); + +class MyExpression : public QmlExpression +{ +public: + MyExpression(QmlContext *ctxt, const QString &expr) + : QmlExpression(ctxt, expr, 0), changed(false) + { + } + + virtual void valueChanged() { + changed = true; + } + bool changed; +}; + + +class MyDefaultObject1 : public QObject +{ + Q_OBJECT + Q_PROPERTY(int horseLegs READ horseLegs); + Q_PROPERTY(int antLegs READ antLegs); +public: + int horseLegs() const { return 4; } + int antLegs() const { return 6; } +}; + +class MyDefaultObject2 : public QObject +{ + Q_OBJECT + Q_PROPERTY(int antLegs READ antLegs); + Q_PROPERTY(int emuLegs READ emuLegs); +public: + int antLegs() const { return 5; } // Had an accident + int emuLegs() const { return 2; } +}; + +class MyDefaultObject3 : public QObject +{ + Q_OBJECT + Q_PROPERTY(int antLegs READ antLegs); + Q_PROPERTY(int humanLegs READ humanLegs); +public: + int antLegs() const { return 7; } // Mutant + int humanLegs() const { return 2; } + int millipedeLegs() const { return 1000; } +}; + + +#endif // TESTTYPES_H + diff --git a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp index 72c8953..a1efc5f 100644 --- a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp +++ b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp @@ -3,71 +3,21 @@ #include <QtDeclarative/qmlengine.h> #include <QtDeclarative/qmlexpression.h> #include <QtDeclarative/qmlcontext.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qdebug.h> +#include <QtCore/qdir.h> +#include "testtypes.h" -class MyQmlObject : public QObject +inline QUrl TEST_FILE(const QString &filename) { - Q_OBJECT - Q_PROPERTY(bool trueProperty READ trueProperty) - Q_PROPERTY(bool falseProperty READ falseProperty) - Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged) -public: - MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false) {} - - bool trueProperty() const { return true; } - bool falseProperty() const { return false; } - - QString stringProperty() const { return m_string; } - void setStringProperty(const QString &s) - { - if (s == m_string) - return; - m_string = s; - emit stringChanged(); - } - - bool methodCalled() const { return m_methodCalled; } - bool methodIntCalled() const { return m_methodIntCalled; } - - QString string() const { return m_string; } -signals: - void basicSignal(); - void argumentSignal(int a, QString b, qreal c); - void stringChanged(); - -public slots: - void method() { m_methodCalled = true; } - void method(int a) { if(a == 163) m_methodIntCalled = true; } - void setString(const QString &s) { m_string = s; } - -private: - friend class tst_qmlbindengine; - bool m_methodCalled; - bool m_methodIntCalled; - - QString m_string; -}; - -QML_DECLARE_TYPE(MyQmlObject); -QML_DEFINE_TYPE(MyQmlObject,MyQmlObject); + QFileInfo fileInfo(__FILE__); + return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath(filename)); +} -class MyQmlContainer : public QObject +inline QUrl TEST_FILE(const char *filename) { - Q_OBJECT - Q_PROPERTY(QList<MyQmlContainer*>* children READ children) -public: - MyQmlContainer() {} - - QList<MyQmlContainer*> *children() { return &m_children; } - -private: - QList<MyQmlContainer*> m_children; -}; - -QML_DECLARE_TYPE(MyQmlContainer); -QML_DEFINE_TYPE(MyQmlContainer,MyQmlContainer); - -#define TEST_FILE(filename) \ - QUrl::fromLocalFile(QApplication::applicationDirPath() + "/" + filename) + return TEST_FILE(QLatin1String(filename)); +} class tst_qmlbindengine : public QObject { @@ -76,18 +26,42 @@ public: tst_qmlbindengine() {} private slots: + void idShortcutInvalidates(); void boolPropertiesEvaluateAsBool(); void methods(); void signalAssignment(); void bindingLoop(); void basicExpressions(); void basicExpressions_data(); + void arrayExpressions(); void contextPropertiesTriggerReeval(); + void objectPropertiesTriggerReeval(); private: QmlEngine engine; }; +void tst_qmlbindengine::idShortcutInvalidates() +{ + { + QmlComponent component(&engine, TEST_FILE("idShortcutInvalidates.txt")); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QVERIFY(object->objectProperty() != 0); + delete object->objectProperty(); + QVERIFY(object->objectProperty() == 0); + } + + { + QmlComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.txt")); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QVERIFY(object->objectProperty() != 0); + delete object->objectProperty(); + QVERIFY(object->objectProperty() == 0); + } +} + void tst_qmlbindengine::boolPropertiesEvaluateAsBool() { { @@ -158,52 +132,6 @@ void tst_qmlbindengine::bindingLoop() QVERIFY(object != 0); } -class MyExpression : public QmlExpression -{ -public: - MyExpression(QmlContext *ctxt, const QString &expr) - : QmlExpression(ctxt, expr, 0), changed(false) - { - } - - virtual void valueChanged() { - changed = true; - } - bool changed; -}; - - -class MyDefaultObject1 : public QObject -{ - Q_OBJECT - Q_PROPERTY(int horseLegs READ horseLegs); - Q_PROPERTY(int antLegs READ antLegs); -public: - int horseLegs() const { return 4; } - int antLegs() const { return 6; } -}; - -class MyDefaultObject2 : public QObject -{ - Q_OBJECT - Q_PROPERTY(int antLegs READ antLegs); - Q_PROPERTY(int emuLegs READ emuLegs); -public: - int antLegs() const { return 5; } // Had an accident - int emuLegs() const { return 2; } -}; - -class MyDefaultObject3 : public QObject -{ - Q_OBJECT - Q_PROPERTY(int antLegs READ antLegs); - Q_PROPERTY(int humanLegs READ humanLegs); -public: - int antLegs() const { return 7; } // Mutant - int humanLegs() const { return 2; } - int millipedeLegs() const { return 1000; } -}; - void tst_qmlbindengine::basicExpressions_data() { QTest::addColumn<QString>("expression"); @@ -264,18 +192,43 @@ void tst_qmlbindengine::basicExpressions() QCOMPARE(expr.value(), result); } +Q_DECLARE_METATYPE(QList<QObject *>); +void tst_qmlbindengine::arrayExpressions() +{ + QObject obj1; + QObject obj2; + QObject obj3; + + QmlContext context(engine.rootContext()); + context.setContextProperty("a", &obj1); + context.setContextProperty("b", &obj2); + context.setContextProperty("c", &obj3); + + MyExpression expr(&context, "[a, b, c, 10]"); + QVariant result = expr.value(); + QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >()); + QList<QObject *> list = qvariant_cast<QList<QObject *> >(result); + QCOMPARE(list.count(), 4); + QCOMPARE(list.at(0), &obj1); + QCOMPARE(list.at(1), &obj2); + QCOMPARE(list.at(2), &obj3); + QCOMPARE(list.at(3), (QObject *)0); +} + // Tests that modifying a context property will reevaluate expressions void tst_qmlbindengine::contextPropertiesTriggerReeval() { QmlContext context(engine.rootContext()); MyQmlObject object1; MyQmlObject object2; + MyQmlObject *object3 = new MyQmlObject; object1.setStringProperty("Hello"); object2.setStringProperty("World"); context.setContextProperty("testProp", QVariant(1)); context.setContextProperty("testObj", &object1); + context.setContextProperty("testObj2", object3); { MyExpression expr(&context, "testProp + 1"); @@ -316,6 +269,72 @@ void tst_qmlbindengine::contextPropertiesTriggerReeval() QCOMPARE(expr.changed, true); QCOMPARE(expr.value(), QVariant("Hello")); } + + { + MyExpression expr(&context, "testObj2"); + QCOMPARE(expr.changed, false); + QCOMPARE(expr.value(), QVariant::fromValue((QObject *)object3)); + + delete object3; + + QCOMPARE(expr.changed, true); + QCOMPARE(expr.value(), QVariant()); + } + +} + +void tst_qmlbindengine::objectPropertiesTriggerReeval() +{ + QmlContext context(engine.rootContext()); + MyQmlObject object1; + MyQmlObject object2; + MyQmlObject object3; + context.setContextProperty("testObj", &object1); + + object1.setStringProperty(QLatin1String("Hello")); + object2.setStringProperty(QLatin1String("Dog")); + object3.setStringProperty(QLatin1String("Cat")); + + { + MyExpression expr(&context, "testObj.stringProperty"); + QCOMPARE(expr.changed, false); + QCOMPARE(expr.value(), QVariant("Hello")); + + object1.setStringProperty(QLatin1String("World")); + QCOMPARE(expr.changed, true); + QCOMPARE(expr.value(), QVariant("World")); + } + + { + MyExpression expr(&context, "testObj.objectProperty.stringProperty"); + QCOMPARE(expr.changed, false); + QCOMPARE(expr.value(), QVariant()); + + object1.setObjectProperty(&object2); + QCOMPARE(expr.changed, true); + expr.changed = false; + QCOMPARE(expr.value(), QVariant("Dog")); + + object1.setObjectProperty(&object3); + QCOMPARE(expr.changed, true); + expr.changed = false; + QCOMPARE(expr.value(), QVariant("Cat")); + + object1.setObjectProperty(0); + QCOMPARE(expr.changed, true); + expr.changed = false; + QCOMPARE(expr.value(), QVariant()); + + object1.setObjectProperty(&object3); + QCOMPARE(expr.changed, true); + expr.changed = false; + QCOMPARE(expr.value(), QVariant("Cat")); + + object3.setStringProperty("Donkey"); + QCOMPARE(expr.changed, true); + expr.changed = false; + QCOMPARE(expr.value(), QVariant("Donkey")); + } } QTEST_MAIN(tst_qmlbindengine) diff --git a/tests/auto/declarative/qmlengine/qmlengine.pro b/tests/auto/declarative/qmlengine/qmlengine.pro new file mode 100644 index 0000000..4ac81e9 --- /dev/null +++ b/tests/auto/declarative/qmlengine/qmlengine.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qmlengine.cpp + +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/qmlengine/tst_qmlengine.cpp b/tests/auto/declarative/qmlengine/tst_qmlengine.cpp new file mode 100644 index 0000000..9a04c61 --- /dev/null +++ b/tests/auto/declarative/qmlengine/tst_qmlengine.cpp @@ -0,0 +1,43 @@ +#include <qtest.h> +#include <QtDeclarative/QmlEngine> + +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QUrl> + +class tst_qmlengine : public QObject +{ + Q_OBJECT +public: + tst_qmlengine() {} + +private slots: + void componentSearchPath(); +}; + + +void tst_qmlengine::componentSearchPath() +{ + QFile file(SRCDIR "/imports.qml"); + QVERIFY(file.open(QIODevice::ReadOnly)); + + QmlEngine engine; + + QList<QUrl> searchPath = engine.componentSearchPath(file.readAll(), + QUrl::fromLocalFile(file.fileName())); + + QList<QUrl> expected; + expected << QUrl::fromLocalFile(SRCDIR); + expected << QUrl::fromLocalFile(file.fileName()).resolved(QUrl("import1")); + expected << QUrl::fromLocalFile(file.fileName()).resolved(QUrl("import2")); + + QCOMPARE(searchPath.size(), expected.size()); + for (int i = 0; i < expected.size(); ++i) { + QCOMPARE(searchPath.at(i).toString(QUrl::StripTrailingSlash), + expected.at(i).toString(QUrl::StripTrailingSlash)); + } +} + +QTEST_MAIN(tst_qmlengine) + +#include "tst_qmlengine.moc" diff --git a/tests/auto/declarative/qmlparser/empty.errors.txt b/tests/auto/declarative/qmlparser/empty.errors.txt index 101b6a2..e0ed268 100644 --- a/tests/auto/declarative/qmlparser/empty.errors.txt +++ b/tests/auto/declarative/qmlparser/empty.errors.txt @@ -1 +1 @@ -0:0:Syntax error +0:0:Expected token `identifier' diff --git a/tests/auto/declarative/qmlparser/missingSignal.errors.txt b/tests/auto/declarative/qmlparser/missingSignal.errors.txt index 9815b99..5c612cc 100644 --- a/tests/auto/declarative/qmlparser/missingSignal.errors.txt +++ b/tests/auto/declarative/qmlparser/missingSignal.errors.txt @@ -1 +1 @@ -2:-1:Unknown property "onClicked" +2:5:Cannot assign binding to non-existant property "onClicked" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt index 406ad83..e8f1a91 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt @@ -1 +1 @@ -1:-1:Unknown property "something" +1:15:Cannot assign value to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt index b371a0f..c154f91 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt @@ -1 +1 @@ -2:-1:Unknown property "something" +2:5:Cannot assign value to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt index b371a0f..a254d7d 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt @@ -1 +1 @@ -2:-1:Unknown property "something" +2:5:Cannot assign binding to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt index b371a0f..a254d7d 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt @@ -1 +1 @@ -2:-1:Unknown property "something" +2:5:Cannot assign binding to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/testtypes.h b/tests/auto/declarative/qmlparser/testtypes.h index 0dc91b2..c1f85b9 100644 --- a/tests/auto/declarative/qmlparser/testtypes.h +++ b/tests/auto/declarative/qmlparser/testtypes.h @@ -7,6 +7,7 @@ #include <QtGui/qmatrix.h> #include <QtGui/qcolor.h> #include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlcomponent.h> #include <QtDeclarative/qmlparserstatus.h> #include <QtDeclarative/qmlpropertyvaluesource.h> diff --git a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp index 65ee5e2..91433ba 100644 --- a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp +++ b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp @@ -3,6 +3,8 @@ #include <QtDeclarative/qmlcomponent.h> #include <QtCore/qfile.h> #include <QtCore/qdebug.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qdir.h> #include "testtypes.h" class tst_qmlparser : public QObject @@ -73,8 +75,16 @@ private: QCOMPARE(expected, actual); \ } -#define TEST_FILE(filename) \ - QUrl::fromLocalFile(QApplication::applicationDirPath() + "/" + filename) +inline QUrl TEST_FILE(const QString &filename) +{ + QFileInfo fileInfo(__FILE__); + return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath(filename)); +} + +inline QUrl TEST_FILE(const char *filename) +{ + return TEST_FILE(QLatin1String(filename)); +} void tst_qmlparser::errors_data() { @@ -82,10 +92,10 @@ void tst_qmlparser::errors_data() QTest::addColumn<QString>("errorFile"); QTest::addColumn<bool>("create"); - QTest::newRow("nonExistantProperty.1") << "nonexistantProperty.1.txt" << "nonexistantProperty.1.errors.txt" << true; - QTest::newRow("nonExistantProperty.2") << "nonexistantProperty.2.txt" << "nonexistantProperty.2.errors.txt" << true; - QTest::newRow("nonExistantProperty.3") << "nonexistantProperty.3.txt" << "nonexistantProperty.3.errors.txt" << true; - QTest::newRow("nonExistantProperty.4") << "nonexistantProperty.4.txt" << "nonexistantProperty.4.errors.txt" << true; + QTest::newRow("nonExistantProperty.1") << "nonexistantProperty.1.txt" << "nonexistantProperty.1.errors.txt" << false; + QTest::newRow("nonExistantProperty.2") << "nonexistantProperty.2.txt" << "nonexistantProperty.2.errors.txt" << false; + QTest::newRow("nonExistantProperty.3") << "nonexistantProperty.3.txt" << "nonexistantProperty.3.errors.txt" << false; + QTest::newRow("nonExistantProperty.4") << "nonexistantProperty.4.txt" << "nonexistantProperty.4.errors.txt" << false; QTest::newRow("nonExistantProperty.5") << "nonexistantProperty.5.txt" << "nonexistantProperty.5.errors.txt" << false; QTest::newRow("nonExistantProperty.6") << "nonexistantProperty.6.txt" << "nonexistantProperty.6.errors.txt" << true; @@ -117,7 +127,7 @@ void tst_qmlparser::errors_data() QTest::newRow("invalidID.3") << "invalidID.3.txt" << "invalidID.3.errors.txt" << false; QTest::newRow("invalidID.4") << "invalidID.4.txt" << "invalidID.4.errors.txt" << false; - QTest::newRow("unsupportedProperty") << "unsupportedProperty.txt" << "unsupportedProperty.errors.txt" << true; + QTest::newRow("unsupportedProperty") << "unsupportedProperty.txt" << "unsupportedProperty.errors.txt" << false; QTest::newRow("nullDotProperty") << "nullDotProperty.txt" << "nullDotProperty.errors.txt" << true; QTest::newRow("fakeDotProperty") << "fakeDotProperty.txt" << "fakeDotProperty.errors.txt" << true; QTest::newRow("duplicateIDs") << "duplicateIDs.txt" << "duplicateIDs.errors.txt" << false; @@ -125,7 +135,7 @@ void tst_qmlparser::errors_data() QTest::newRow("empty") << "empty.txt" << "empty.errors.txt" << false; QTest::newRow("missingObject") << "missingObject.txt" << "missingObject.errors.txt" << false; QTest::newRow("failingComponent") << "failingComponent.txt" << "failingComponent.errors.txt" << true; - QTest::newRow("missingSignal") << "missingSignal.txt" << "missingSignal.errors.txt" << true; + QTest::newRow("missingSignal") << "missingSignal.txt" << "missingSignal.errors.txt" << false; } void tst_qmlparser::errors() diff --git a/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt b/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt index f396e7e..a067ecb 100644 --- a/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt +++ b/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt @@ -1 +1 @@ -2:-1:Property matrix is of an unknown type +2:5:Cannot assign value to property matrix of unknown type diff --git a/tests/auto/qcolor/tst_qcolor.cpp b/tests/auto/qcolor/tst_qcolor.cpp index 7608a15..684d5b5 100644 --- a/tests/auto/qcolor/tst_qcolor.cpp +++ b/tests/auto/qcolor/tst_qcolor.cpp @@ -111,12 +111,15 @@ private slots: void toRgb_data(); void toRgb(); + void toRgbNonDestructive(); void toHsv_data(); void toHsv(); + void toHsvNonDestructive(); void toCmyk_data(); void toCmyk(); + void toCmykNonDestructive(); void convertTo(); @@ -1124,6 +1127,12 @@ void tst_QColor::toHsv_data() << QColor::fromCmykF(0., 1., 1., 0.); } +void tst_QColor::toRgbNonDestructive() +{ + QColor aColor = QColor::fromRgbF(0.11, 0.22, 0.33, 0.44); + QCOMPARE(aColor, aColor.toRgb()); +} + void tst_QColor::toHsv() { // invalid should remain invalid @@ -1136,6 +1145,12 @@ void tst_QColor::toHsv() QCOMPARE(cmykColor.toHsv(), expectedColor); } +void tst_QColor::toHsvNonDestructive() +{ + QColor aColor = QColor::fromHsvF(0.11, 0.22, 0.33, 0.44); + QCOMPARE(aColor, aColor.toHsv()); +} + void tst_QColor::toCmyk_data() { QTest::addColumn<QColor>("expectedColor"); @@ -1165,6 +1180,12 @@ void tst_QColor::toCmyk() QCOMPARE(hsvColor.toCmyk(), expectedColor); } +void tst_QColor::toCmykNonDestructive() +{ + QColor aColor = QColor::fromCmykF(0.11, 0.22, 0.33, 0.44); + QCOMPARE(aColor, aColor.toCmyk()); +} + void tst_QColor::convertTo() { QColor color(Qt::black); diff --git a/tests/auto/qcontiguouscache/qcontiguouscache.pro b/tests/auto/qcontiguouscache/qcontiguouscache.pro new file mode 100644 index 0000000..618efed --- /dev/null +++ b/tests/auto/qcontiguouscache/qcontiguouscache.pro @@ -0,0 +1,8 @@ +load(qttest_p4) + +QT = core + +SOURCES += tst_qcontiguouscache.cpp + + + diff --git a/tests/auto/qcontiguouscache/tst_qcontiguouscache.cpp b/tests/auto/qcontiguouscache/tst_qcontiguouscache.cpp new file mode 100644 index 0000000..6d59390 --- /dev/null +++ b/tests/auto/qcontiguouscache/tst_qcontiguouscache.cpp @@ -0,0 +1,479 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite 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 <QObject> +#include <QTest> +#include <QCache> +#include <QContiguousCache> + +#include <QDebug> +#include <stdio.h> + +class tst_QContiguousCache : public QObject +{ + Q_OBJECT +public: + tst_QContiguousCache() {} + virtual ~tst_QContiguousCache() {} +private slots: + void empty(); + void append_data(); + void append(); + + void prepend_data(); + void prepend(); + + void asScrollingList(); + + void complexType(); + + void operatorAt(); + + void cacheBenchmark(); + void contiguousCacheBenchmark(); + + void setCapacity(); +}; + +QTEST_MAIN(tst_QContiguousCache) + +void tst_QContiguousCache::empty() +{ + QContiguousCache<int> c(10); + QCOMPARE(c.capacity(), 10); + QCOMPARE(c.count(), 0); + QVERIFY(c.isEmpty()); + c.append(1); + QCOMPARE(c.count(), 1); + QVERIFY(!c.isEmpty()); + c.clear(); + QCOMPARE(c.capacity(), 10); + QCOMPARE(c.count(), 0); + QVERIFY(c.isEmpty()); + c.prepend(1); + QCOMPARE(c.count(), 1); + QVERIFY(!c.isEmpty()); + c.clear(); + QCOMPARE(c.count(), 0); + QVERIFY(c.isEmpty()); + QCOMPARE(c.capacity(), 10); +} + +void tst_QContiguousCache::append_data() +{ + QTest::addColumn<int>("start"); + QTest::addColumn<int>("count"); + QTest::addColumn<int>("cacheSize"); + QTest::addColumn<bool>("invalidIndexes"); + + QTest::newRow("0+30[10]") << 0 << 30 << 10 << false; + QTest::newRow("300+30[10]") << 300 << 30 << 10 << false; + QTest::newRow("MAX-10+30[10]") << INT_MAX-10 << 30 << 10 << true; +} + +void tst_QContiguousCache::append() +{ + QFETCH(int, start); + QFETCH(int, count); + QFETCH(int, cacheSize); + QFETCH(bool, invalidIndexes); + + int i, j; + QContiguousCache<int> c(cacheSize); + + i = 1; + QCOMPARE(c.available(), cacheSize); + if (start == 0) + c.append(i++); + else + c.insert(start, i++); + while (i < count) { + c.append(i); + QCOMPARE(c.available(), qMax(0, cacheSize - i)); + QCOMPARE(c.first(), qMax(1, i-cacheSize+1)); + QCOMPARE(c.last(), i); + QCOMPARE(c.count(), qMin(i, cacheSize)); + QCOMPARE(c.isFull(), i >= cacheSize); + i++; + } + + QCOMPARE(c.areIndexesValid(), !invalidIndexes); + if (invalidIndexes) + c.normalizeIndexes(); + QVERIFY(c.areIndexesValid()); + + // test taking from end until empty. + for (j = 0; j < cacheSize; j++, i--) { + QCOMPARE(c.takeLast(), i-1); + QCOMPARE(c.count(), cacheSize-j-1); + QCOMPARE(c.available(), j+1); + QVERIFY(!c.isFull()); + QCOMPARE(c.isEmpty(), j==cacheSize-1); + } + +} + +void tst_QContiguousCache::prepend_data() +{ + QTest::addColumn<int>("start"); + QTest::addColumn<int>("count"); + QTest::addColumn<int>("cacheSize"); + QTest::addColumn<bool>("invalidIndexes"); + + QTest::newRow("30-30[10]") << 30 << 30 << 10 << false; + QTest::newRow("300-30[10]") << 300 << 30 << 10 << false; + QTest::newRow("10-30[10]") << 10 << 30 << 10 << true; +} + +void tst_QContiguousCache::prepend() +{ + QFETCH(int, start); + QFETCH(int, count); + QFETCH(int, cacheSize); + QFETCH(bool, invalidIndexes); + + int i, j; + QContiguousCache<int> c(cacheSize); + + i = 1; + QCOMPARE(c.available(), cacheSize); + c.insert(start, i++); + while(i < count) { + c.prepend(i); + QCOMPARE(c.available(), qMax(0, cacheSize - i)); + QCOMPARE(c.last(), qMax(1, i-cacheSize+1)); + QCOMPARE(c.first(), i); + QCOMPARE(c.count(), qMin(i, cacheSize)); + QCOMPARE(c.isFull(), i >= cacheSize); + i++; + } + + QCOMPARE(c.areIndexesValid(), !invalidIndexes); + if (invalidIndexes) + c.normalizeIndexes(); + QVERIFY(c.areIndexesValid()); + + // test taking from start until empty. + for (j = 0; j < cacheSize; j++, i--) { + QCOMPARE(c.takeFirst(), i-1); + QCOMPARE(c.count(), cacheSize-j-1); + QCOMPARE(c.available(), j+1); + QVERIFY(!c.isFull()); + QCOMPARE(c.isEmpty(), j==cacheSize-1); + } +} + +void tst_QContiguousCache::asScrollingList() +{ + int i; + QContiguousCache<int> c(10); + + // Once allocated QContiguousCache should not + // allocate any additional memory for non + // complex data types. + QBENCHMARK { + // simulate scrolling in a list of items; + for(i = 0; i < 10; ++i) { + QCOMPARE(c.available(), 10-i); + c.append(i); + } + + QCOMPARE(c.firstIndex(), 0); + QCOMPARE(c.lastIndex(), 9); + QCOMPARE(c.first(), 0); + QCOMPARE(c.last(), 9); + QVERIFY(!c.containsIndex(-1)); + QVERIFY(!c.containsIndex(10)); + QCOMPARE(c.available(), 0); + + for (i = 0; i < 10; ++i) { + QVERIFY(c.containsIndex(i)); + QCOMPARE(c.at(i), i); + QCOMPARE(c[i], i); + QCOMPARE(((const QContiguousCache<int>)c)[i], i); + } + + for (i = 10; i < 30; ++i) + c.append(i); + + QCOMPARE(c.firstIndex(), 20); + QCOMPARE(c.lastIndex(), 29); + QCOMPARE(c.first(), 20); + QCOMPARE(c.last(), 29); + QVERIFY(!c.containsIndex(19)); + QVERIFY(!c.containsIndex(30)); + QCOMPARE(c.available(), 0); + + for (i = 20; i < 30; ++i) { + QVERIFY(c.containsIndex(i)); + QCOMPARE(c.at(i), i); + QCOMPARE(c[i], i); + QCOMPARE(((const QContiguousCache<int> )c)[i], i); + } + + for (i = 19; i >= 10; --i) + c.prepend(i); + + QCOMPARE(c.firstIndex(), 10); + QCOMPARE(c.lastIndex(), 19); + QCOMPARE(c.first(), 10); + QCOMPARE(c.last(), 19); + QVERIFY(!c.containsIndex(9)); + QVERIFY(!c.containsIndex(20)); + QCOMPARE(c.available(), 0); + + for (i = 10; i < 20; ++i) { + QVERIFY(c.containsIndex(i)); + QCOMPARE(c.at(i), i); + QCOMPARE(c[i], i); + QCOMPARE(((const QContiguousCache<int> )c)[i], i); + } + + for (i = 200; i < 220; ++i) + c.insert(i, i); + + QCOMPARE(c.firstIndex(), 210); + QCOMPARE(c.lastIndex(), 219); + QCOMPARE(c.first(), 210); + QCOMPARE(c.last(), 219); + QVERIFY(!c.containsIndex(209)); + QVERIFY(!c.containsIndex(300)); + QCOMPARE(c.available(), 0); + + for (i = 210; i < 220; ++i) { + QVERIFY(c.containsIndex(i)); + QCOMPARE(c.at(i), i); + QCOMPARE(c[i], i); + QCOMPARE(((const QContiguousCache<int> )c)[i], i); + } + c.clear(); // needed to reset benchmark + } + + // from a specific bug that was encountered. 100 to 299 cached, attempted to cache 250 - 205 via insert, failed. + // bug was that item at 150 would instead be item that should have been inserted at 250 + c.setCapacity(200); + for(i = 100; i < 300; ++i) + c.insert(i, i); + for (i = 250; i <= 306; ++i) + c.insert(i, 1000+i); + for (i = 107; i <= 306; ++i) { + QVERIFY(c.containsIndex(i)); + QCOMPARE(c.at(i), i < 250 ? i : 1000+i); + } +} + +struct RefCountingClassData +{ + QBasicAtomicInt ref; + static RefCountingClassData shared_null; +}; + +RefCountingClassData RefCountingClassData::shared_null = { + Q_BASIC_ATOMIC_INITIALIZER(1) +}; + +class RefCountingClass +{ +public: + RefCountingClass() : d(&RefCountingClassData::shared_null) { d->ref.ref(); } + + RefCountingClass(const RefCountingClass &other) + { + d = other.d; + d->ref.ref(); + } + + ~RefCountingClass() + { + if (!d->ref.deref()) + delete d; + } + + RefCountingClass &operator=(const RefCountingClass &other) + { + if (!d->ref.deref()) + delete d; + d = other.d; + d->ref.ref(); + return *this; + } + + int refCount() const { return d->ref; } +private: + RefCountingClassData *d; +}; + +void tst_QContiguousCache::complexType() +{ + RefCountingClass original; + + QContiguousCache<RefCountingClass> contiguousCache(10); + contiguousCache.append(original); + QCOMPARE(original.refCount(), 3); + contiguousCache.removeFirst(); + QCOMPARE(original.refCount(), 2); // shared null, 'original'. + contiguousCache.append(original); + QCOMPARE(original.refCount(), 3); + contiguousCache.clear(); + QCOMPARE(original.refCount(), 2); + + for(int i = 0; i < 100; ++i) + contiguousCache.insert(i, original); + + QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache. + + contiguousCache.clear(); + QCOMPARE(original.refCount(), 2); + for (int i = 0; i < 100; i++) + contiguousCache.append(original); + + QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache. + contiguousCache.clear(); + QCOMPARE(original.refCount(), 2); + + for (int i = 0; i < 100; i++) + contiguousCache.prepend(original); + + QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache. + contiguousCache.clear(); + QCOMPARE(original.refCount(), 2); + + for (int i = 0; i < 100; i++) + contiguousCache.append(original); + + contiguousCache.takeLast(); + QCOMPARE(original.refCount(), 11); + + contiguousCache.takeFirst(); + QCOMPARE(original.refCount(), 10); +} + +void tst_QContiguousCache::operatorAt() +{ + RefCountingClass original; + QContiguousCache<RefCountingClass> contiguousCache(10); + + for (int i = 25; i < 35; ++i) + contiguousCache[i] = original; + + QCOMPARE(original.refCount(), 12); // shared null, orig, items in cache + + // verify const access does not copy items. + const QContiguousCache<RefCountingClass> copy(contiguousCache); + for (int i = 25; i < 35; ++i) + QCOMPARE(copy[i].refCount(), 12); + + // verify modifying the original increments ref count (e.g. does a detach) + contiguousCache[25] = original; + QCOMPARE(original.refCount(), 22); +} + +/* + Benchmarks must be near identical in tasks to be fair. + QCache uses pointers to ints as its a requirement of QCache, + whereas QContiguousCache doesn't support pointers (won't free them). + Given the ability to use simple data types is a benefit, its + fair. Although this obviously must take into account we are + testing QContiguousCache use cases here, QCache has its own + areas where it is the more sensible class to use. +*/ +void tst_QContiguousCache::cacheBenchmark() +{ + QBENCHMARK { + QCache<int, int> cache; + cache.setMaxCost(100); + + for (int i = 0; i < 1000; i++) + cache.insert(i, new int(i)); + } +} + +void tst_QContiguousCache::contiguousCacheBenchmark() +{ + QBENCHMARK { + QContiguousCache<int> contiguousCache(100); + for (int i = 0; i < 1000; i++) + contiguousCache.insert(i, i); + } +} + +void tst_QContiguousCache::setCapacity() +{ + int i; + QContiguousCache<int> contiguousCache(100); + for (i = 280; i < 310; ++i) + contiguousCache.insert(i, i); + QCOMPARE(contiguousCache.capacity(), 100); + QCOMPARE(contiguousCache.count(), 30); + QCOMPARE(contiguousCache.firstIndex(), 280); + QCOMPARE(contiguousCache.lastIndex(), 309); + + for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) { + QVERIFY(contiguousCache.containsIndex(i)); + QCOMPARE(contiguousCache.at(i), i); + } + + contiguousCache.setCapacity(150); + + QCOMPARE(contiguousCache.capacity(), 150); + QCOMPARE(contiguousCache.count(), 30); + QCOMPARE(contiguousCache.firstIndex(), 280); + QCOMPARE(contiguousCache.lastIndex(), 309); + + for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) { + QVERIFY(contiguousCache.containsIndex(i)); + QCOMPARE(contiguousCache.at(i), i); + } + + contiguousCache.setCapacity(20); + + QCOMPARE(contiguousCache.capacity(), 20); + QCOMPARE(contiguousCache.count(), 20); + QCOMPARE(contiguousCache.firstIndex(), 290); + QCOMPARE(contiguousCache.lastIndex(), 309); + + for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) { + QVERIFY(contiguousCache.containsIndex(i)); + QCOMPARE(contiguousCache.at(i), i); + } +} + +#include "tst_qcontiguouscache.moc" diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 3b9895d..8602307 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -217,6 +217,8 @@ private slots: void tabChangesFocus_data(); void cacheMode(); void updateCachedItemAfterMove(); + void deviceTransform_data(); + void deviceTransform(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6271,5 +6273,113 @@ void tst_QGraphicsItem::updateCachedItemAfterMove() QCOMPARE(tester->repaints, 1); } +class Track : public QGraphicsRectItem +{ +public: + Track(const QRectF &rect) + : QGraphicsRectItem(rect) + { + setAcceptHoverEvents(true); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) + { + QGraphicsRectItem::paint(painter, option, widget); + painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1x%2\n%3x%4").arg(p.x()).arg(p.y()).arg(sp.x()).arg(sp.y())); + } + +protected: + void hoverMoveEvent(QGraphicsSceneHoverEvent *event) + { + p = event->pos(); + sp = event->widget()->mapFromGlobal(event->screenPos()); + update(); + } +private: + QPointF p; + QPoint sp; +}; + +void tst_QGraphicsItem::deviceTransform_data() +{ + QTest::addColumn<bool>("untransformable1"); + QTest::addColumn<bool>("untransformable2"); + QTest::addColumn<bool>("untransformable3"); + QTest::addColumn<qreal>("rotation1"); + QTest::addColumn<qreal>("rotation2"); + QTest::addColumn<qreal>("rotation3"); + QTest::addColumn<QTransform>("deviceX"); + QTest::addColumn<QPointF>("mapResult1"); + QTest::addColumn<QPointF>("mapResult2"); + QTest::addColumn<QPointF>("mapResult3"); + + QTest::newRow("nil") << false << false << false + << qreal(0.0) << qreal(0.0) << qreal(0.0) + << QTransform() + << QPointF(150, 150) << QPointF(250, 250) << QPointF(350, 350); + QTest::newRow("deviceX rot 90") << false << false << false + << qreal(0.0) << qreal(0.0) << qreal(0.0) + << QTransform().rotate(90) + << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-350, 350); + QTest::newRow("deviceX rot 90 100") << true << false << false + << qreal(0.0) << qreal(0.0) << qreal(0.0) + << QTransform().rotate(90) + << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350); + QTest::newRow("deviceX rot 90 010") << false << true << false + << qreal(0.0) << qreal(0.0) << qreal(0.0) + << QTransform().rotate(90) + << QPointF(-150, 150) << QPointF(-150, 250) << QPointF(-50, 350); + QTest::newRow("deviceX rot 90 001") << false << false << true + << qreal(0.0) << qreal(0.0) << qreal(0.0) + << QTransform().rotate(90) + << QPointF(-150, 150) << QPointF(-250, 250) << QPointF(-250, 350); + QTest::newRow("deviceX rot 90 111") << true << true << true + << qreal(0.0) << qreal(0.0) << qreal(0.0) + << QTransform().rotate(90) + << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350); + QTest::newRow("deviceX rot 90 101") << true << false << true + << qreal(0.0) << qreal(0.0) << qreal(0.0) + << QTransform().rotate(90) + << QPointF(-50, 150) << QPointF(50, 250) << QPointF(150, 350); +} + +void tst_QGraphicsItem::deviceTransform() +{ + QFETCH(bool, untransformable1); + QFETCH(bool, untransformable2); + QFETCH(bool, untransformable3); + QFETCH(qreal, rotation1); + QFETCH(qreal, rotation2); + QFETCH(qreal, rotation3); + QFETCH(QTransform, deviceX); + QFETCH(QPointF, mapResult1); + QFETCH(QPointF, mapResult2); + QFETCH(QPointF, mapResult3); + + QGraphicsScene scene; + Track *rect1 = new Track(QRectF(0, 0, 100, 100)); + Track *rect2 = new Track(QRectF(0, 0, 100, 100)); + Track *rect3 = new Track(QRectF(0, 0, 100, 100)); + rect2->setParentItem(rect1); + rect3->setParentItem(rect2); + rect1->setPos(100, 100); + rect2->setPos(100, 100); + rect3->setPos(100, 100); + rect1->rotate(rotation1); + rect2->rotate(rotation2); + rect3->rotate(rotation3); + rect1->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable1); + rect2->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable2); + rect3->setFlag(QGraphicsItem::ItemIgnoresTransformations, untransformable3); + rect1->setBrush(Qt::red); + rect2->setBrush(Qt::green); + rect3->setBrush(Qt::blue); + scene.addItem(rect1); + + QCOMPARE(rect1->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult1); + QCOMPARE(rect2->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult2); + QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index bb61f90..920cba7 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -204,6 +204,7 @@ private slots: void task239729_noViewUpdate(); void task239047_fitInViewSmallViewport(); void task245469_itemsAtPointWithClip(); + void task253415_reconnectUpdateSceneOnSceneChanged(); }; void tst_QGraphicsView::initTestCase() @@ -3200,5 +3201,28 @@ void tst_QGraphicsView::mouseTracking2() QCOMPARE(spy.count(), 1); } +void tst_QGraphicsView::task253415_reconnectUpdateSceneOnSceneChanged() +{ + QGraphicsView view; + QGraphicsView dummyView; + view.setWindowFlags(view.windowFlags() | Qt::WindowStaysOnTopHint); + view.resize(200, 200); + + QGraphicsScene scene1; + QObject::connect(&scene1, SIGNAL(changed(QList<QRectF>)), &dummyView, SLOT(updateScene(QList<QRectF>))); + view.setScene(&scene1); + + QTest::qWait(125); + + QGraphicsScene scene2; + QObject::connect(&scene2, SIGNAL(changed(QList<QRectF>)), &dummyView, SLOT(updateScene(QList<QRectF>))); + view.setScene(&scene2); + + QTest::qWait(125); + + bool wasConnected2 = QObject::disconnect(&scene2, SIGNAL(changed(QList<QRectF>)), &view, 0); + QVERIFY(wasConnected2); +} + QTEST_MAIN(tst_QGraphicsView) #include "tst_qgraphicsview.moc" diff --git a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp index 56737c3..a23ada9 100644 --- a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp @@ -50,6 +50,7 @@ #include <qcleanlooksstyle.h> #include <qlineedit.h> #include <qboxlayout.h> +#include <qaction.h> #include "../../shared/util.h" @@ -148,6 +149,7 @@ private slots: void defaultSize(); void explicitMouseGrabber(); void implicitMouseGrabber(); + void doubleClickAfterExplicitMouseGrab(); void popupMouseGrabber(); void windowFlags_data(); void windowFlags(); @@ -155,6 +157,7 @@ private slots: // Task fixes void task236127_bspTreeIndexFails(); void task243004_setStyleCrash(); + void task250119_shortcutContext(); }; @@ -1996,6 +1999,104 @@ void tst_QGraphicsWidget::implicitMouseGrabber() QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); } +class GrabOnPressItem : public QGraphicsRectItem +{ +public: + GrabOnPressItem(const QRectF &rect) + : QGraphicsRectItem(rect), + npress(0), nrelease(0), ndoubleClick(0), + ngrab(0), nungrab(0) + { + } + int npress; + int nrelease; + int ndoubleClick; + int ngrab; + int nungrab; +protected: + bool sceneEvent(QEvent *event) + { + switch (event->type()) { + case QEvent::GrabMouse: + ++ngrab; + break; + case QEvent::UngrabMouse: + ++nungrab; + break; + default: + break; + } + return QGraphicsRectItem::sceneEvent(event); + } + + void mousePressEvent(QGraphicsSceneMouseEvent *) + { + grabMouse(); + ++npress; + } + void mouseReleaseEvent(QGraphicsSceneMouseEvent *) + { + ungrabMouse(); + ++nrelease; + } + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) + { + ++ndoubleClick; + } +}; + +void tst_QGraphicsWidget::doubleClickAfterExplicitMouseGrab() +{ + QGraphicsScene scene; + GrabOnPressItem *item = new GrabOnPressItem(QRectF(0, 0, 100, 100)); + scene.addItem(item); + + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); + event.setButton(Qt::LeftButton); + event.setButtons(Qt::LeftButton); + event.ignore(); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item); + QCOMPARE(item->npress, 1); + QCOMPARE(item->ngrab, 1); + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); + event.setButton(Qt::LeftButton); + event.setButtons(0); + event.ignore(); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); + QCOMPARE(item->nrelease, 1); + QCOMPARE(item->nungrab, 1); + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseDoubleClick); + event.setButton(Qt::LeftButton); + event.setButtons(Qt::LeftButton); + event.ignore(); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)item); + QCOMPARE(item->ndoubleClick, 1); + QCOMPARE(item->ngrab, 2); + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); + event.setButton(Qt::LeftButton); + event.setButtons(0); + event.ignore(); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); + QCOMPARE(item->nrelease, 2); + QCOMPARE(item->nungrab, 2); +} + void tst_QGraphicsWidget::popupMouseGrabber() { QGraphicsScene scene; @@ -2212,6 +2313,89 @@ void tst_QGraphicsWidget::task243004_setStyleCrash() delete item2; } +class GraphicsWidget_task250119 : public QGraphicsWidget +{ +public: + GraphicsWidget_task250119() + : shortcutEvents(0) + { + setFocusPolicy(Qt::StrongFocus); + resize(100, 100); + } + + int shortcutEvents; + +private: + bool event(QEvent *event) + { + if (event->type() == QEvent::Shortcut) + shortcutEvents++; + return QGraphicsWidget::event(event); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) + { + if (hasFocus()) { + painter->setPen(QPen(Qt::black, 0, Qt::DashLine)); + painter->drawRect(rect()); + } + painter->setPen(QPen(Qt::black, 0, Qt::SolidLine)); + painter->fillRect(rect().adjusted(2, 2, -2, -2), Qt::yellow); + painter->drawRect(rect().adjusted(2, 2, -2, -2)); + } +}; + +void tst_QGraphicsWidget::task250119_shortcutContext() +{ + QGraphicsScene scene; + QGraphicsView view; + view.setScene(&scene); + view.show(); + QTest::qWait(100); + + + // *** Event: *** + + GraphicsWidget_task250119 w_event; + scene.addItem(&w_event); + + const int id = w_event.grabShortcut(Qt::Key_A, Qt::WidgetWithChildrenShortcut); + w_event.setShortcutEnabled(id, true); + + w_event.setFocus(); + QTest::keyPress(&view, Qt::Key_A); + QCOMPARE(w_event.shortcutEvents, 1); + + w_event.clearFocus(); + QTest::keyPress(&view, Qt::Key_A); + QCOMPARE(w_event.shortcutEvents, 1); + + scene.removeItem(&w_event); + + + // *** Signal: *** + + GraphicsWidget_task250119 w_signal; + scene.addItem(&w_signal); + + QAction action(0); + action.setShortcut(Qt::Key_B); + action.setShortcutContext(Qt::WidgetWithChildrenShortcut); + QSignalSpy spy(&action, SIGNAL(triggered())); + + w_signal.addAction(&action); + + w_signal.setFocus(); + QTest::keyPress(&view, Qt::Key_B); + QCOMPARE(spy.count(), 1); + + w_signal.clearFocus(); + QTest::keyPress(&view, Qt::Key_B); + QCOMPARE(spy.count(), 1); + + scene.removeItem(&w_signal); +} + QTEST_MAIN(tst_QGraphicsWidget) #include "tst_qgraphicswidget.moc" diff --git a/tests/auto/qlistview/tst_qlistview.cpp b/tests/auto/qlistview/tst_qlistview.cpp index 791a472..f70db14 100644 --- a/tests/auto/qlistview/tst_qlistview.cpp +++ b/tests/auto/qlistview/tst_qlistview.cpp @@ -106,6 +106,7 @@ private slots: void task228566_infiniteRelayout(); void task248430_crashWith0SizedItem(); void task250446_scrollChanged(); + void task196118_visualRegionForSelection(); void keyboardSearch(); }; @@ -1556,6 +1557,29 @@ void tst_QListView::task250446_scrollChanged() QCOMPARE(view.currentIndex(), index); } +void tst_QListView::task196118_visualRegionForSelection() +{ + class MyListView : public QListView + { + public: + QRegion visualRegionForSelection() const + { return QListView::visualRegionForSelection( selectionModel()->selection()); } + } view; + + QStandardItemModel model; + QStandardItem top1("top1"); + QStandardItem sub1("sub1"); + top1.appendRow(QList<QStandardItem*>() << &sub1); + model.appendColumn(QList<QStandardItem*>() << &top1); + view.setModel(&model); + view.setRootIndex(top1.index()); + + view.selectionModel()->select(top1.index(), QItemSelectionModel::Select); + + QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1); + QVERIFY(view.visualRegionForSelection().isEmpty()); +} + void tst_QListView::keyboardSearch() { QStringList items; diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 104b788..6c622f7 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -52,6 +52,7 @@ #include <QtNetwork/QTcpSocket> #include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalServer> +#include <QtNetwork/QHostInfo> #include <QtNetwork/QFtp> #include <QtNetwork/qauthenticator.h> #include <QtNetwork/qnetworkaccessmanager.h> @@ -91,6 +92,15 @@ class tst_QNetworkReply: public QObject { Q_OBJECT + struct ProxyData { + ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth) + : tag(t), proxy(p), requiresAuthentication(auth) + { } + QByteArray tag; + QNetworkProxy proxy; + bool requiresAuthentication; + }; + QEventLoop *loop; enum RunSimpleRequestReturn { Timeout = 0, Success, Failure }; int returnCode; @@ -99,6 +109,7 @@ class tst_QNetworkReply: public QObject QString wronlyFileName; #endif QString uniqueExtension; + QList<ProxyData> proxies; QNetworkAccessManager manager; MyCookieJar *cookieJar; #ifndef QT_NO_OPENSSL @@ -172,6 +183,8 @@ private Q_SLOTS: void ioGetFromHttpsWithIgnoreSslErrors(); void ioGetFromHttpsWithSslHandshakeError(); #endif + void ioGetFromHttpBrokenServer_data(); + void ioGetFromHttpBrokenServer(); void ioGetWithManyProxies_data(); void ioGetWithManyProxies(); @@ -190,11 +203,20 @@ private Q_SLOTS: void ioPutToHttpFromFile(); void ioPostToHttpFromFile_data(); void ioPostToHttpFromFile(); + void ioPostToHttpFromSocket_data(); + void ioPostToHttpFromSocket(); + void ioPostToHttpFromMiddleOfFileToEnd(); + void ioPostToHttpFromMiddleOfFileFiveBytes(); + void ioPostToHttpFromMiddleOfQBufferFiveBytes(); + void ioPostToHttpNoBufferFlag(); + void ioPostToHttpUploadProgress(); + void ioPostToHttpEmtpyUploadProgress(); void rateControl_data(); void rateControl(); void downloadPerformance(); void uploadPerformance(); + void httpUploadPerformance(); void performanceControlRate(); void downloadProgress_data(); @@ -364,6 +386,63 @@ public slots: } }; +class FixedSizeDataGenerator : public QIODevice +{ + Q_OBJECT + enum { Idle, Started, Stopped } state; +public: + FixedSizeDataGenerator(qint64 size) : state(Idle) + { open(ReadOnly | Unbuffered); + toBeGeneratedTotalCount = toBeGeneratedCount = size; + } + + virtual qint64 bytesAvailable() const + { + return state == Started ? toBeGeneratedCount + QIODevice::bytesAvailable() : 0; + } + + virtual bool isSequential() const{ + return false; + } + + virtual bool reset() const{ + return false; + } + + qint64 size() const { + return toBeGeneratedTotalCount; + } + +public slots: + void start() { state = Started; emit readyRead(); } + +protected: + virtual qint64 readData(char *data, qint64 maxlen) + { + memset(data, '@', maxlen); + + if (toBeGeneratedCount <= 0) { + return -1; + } + + qint64 n = qMin(maxlen, toBeGeneratedCount); + toBeGeneratedCount -= n; + + if (toBeGeneratedCount <= 0) { + // make sure this is a queued connection! + emit readChannelFinished(); + } + + return n; + } + virtual qint64 writeData(const char *, qint64) + { return -1; } + + qint64 toBeGeneratedCount; + qint64 toBeGeneratedTotalCount; +}; + + class DataGenerator: public QIODevice { Q_OBJECT @@ -384,6 +463,7 @@ protected: { if (state == Stopped) return -1; // EOF + // return as many bytes as are wanted memset(data, '@', maxlen); return maxlen; @@ -392,6 +472,8 @@ protected: { return -1; } }; + + class SocketPair: public QObject { Q_OBJECT @@ -629,7 +711,7 @@ protected: return; transferRate = totalBytes * 1000 / timer.elapsed(); - qDebug() << "receive rate:" << (transferRate / 1024) << "kB/s in" + qDebug() << "TimedSender::run" << "receive rate:" << (transferRate / 1024) << "kB/s in" << timer.elapsed() << "ms"; } @@ -643,12 +725,13 @@ protected: class ThreadedDataReader: public QThread { Q_OBJECT + // used to make the constructor only return after the tcp server started listening QSemaphore ready; QTcpSocket *client; int timeout; int port; public: - int transferRate; + qint64 transferRate; ThreadedDataReader() : port(-1), transferRate(-1) { @@ -676,12 +759,65 @@ protected: QTime timer; timer.start(); eventLoop.exec(); + qint64 elapsed = timer.elapsed(); - transferRate = reader.totalBytes * 1000 / timer.elapsed(); - qDebug() << "send rate:" << (transferRate / 1024) << "kB/s"; + transferRate = reader.totalBytes * 1000 / elapsed; + qDebug() << "ThreadedDataReader::run" << "send rate:" << (transferRate / 1024) << "kB/s in" << elapsed << "msec"; } }; +class ThreadedDataReaderHttpServer: public QThread +{ + Q_OBJECT + // used to make the constructor only return after the tcp server started listening + QSemaphore ready; + QTcpSocket *client; + int timeout; + int port; +public: + qint64 transferRate; + ThreadedDataReaderHttpServer() + : port(-1), transferRate(-1) + { + start(); + ready.acquire(); + } + + inline int serverPort() const { return port; } + +protected: + void run() + { + QTcpServer server; + server.listen(); + port = server.serverPort(); + ready.release(); + + server.waitForNewConnection(-1); + client = server.nextPendingConnection(); + client->write("HTTP/1.0 200 OK\r\n"); + client->write("Content-length: 0\r\n"); + client->write("\r\n"); + client->flush(); + + QCoreApplication::processEvents(); + + QEventLoop eventLoop; + DataReader reader(client, false); + QObject::connect(client, SIGNAL(disconnected()), &eventLoop, SLOT(quit())); + + QTime timer; + timer.start(); + eventLoop.exec(); + qint64 elapsed = timer.elapsed(); + + transferRate = reader.totalBytes * 1000 / elapsed; + qDebug() << "ThreadedDataReaderHttpServer::run" << "send rate:" << (transferRate / 1024) << "kB/s in" << elapsed << "msec"; + } +}; + + + tst_QNetworkReply::tst_QNetworkReply() { testFileName = QDir::currentPath() + "/testfile"; @@ -692,8 +828,28 @@ tst_QNetworkReply::tst_QNetworkReply() #endif cookieJar = new MyCookieJar; manager.setCookieJar(cookieJar); + + QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName()); + + proxies << ProxyData(QNetworkProxy::NoProxy, "", false); + + if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) { + QString proxyserver = hostInfo.addresses().first().toString(); + proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false) + << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true) + // currently unsupported + // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true); + << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false) + << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true); + } else { + printf("==================================================================\n"); + printf("Proxy could not be looked up. No proxy will be used while testing!\n"); + printf("==================================================================\n"); + } } + + void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth) { auth->setUser("httptest"); @@ -1887,6 +2043,53 @@ void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError() } #endif +void tst_QNetworkReply::ioGetFromHttpBrokenServer_data() +{ + QTest::addColumn<QByteArray>("dataToSend"); + QTest::addColumn<bool>("doDisconnect"); + + QTest::newRow("no-newline") << QByteArray("Hello World") << false; + QTest::newRow("just-newline") << QByteArray("\r\n") << false; + QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false; + QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false; + QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false; + QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false; + QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false; + QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false; + QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false; + + QTest::newRow("empty+disconnect") << QByteArray() << true; + + QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true; + QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true; + QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true; + QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true; + QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true; + QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true; + + QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true; + QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true; + QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true; +} + +void tst_QNetworkReply::ioGetFromHttpBrokenServer() +{ + QFETCH(QByteArray, dataToSend); + QFETCH(bool, doDisconnect); + MiniHttpServer server(dataToSend); + server.doClose = doDisconnect; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QVERIFY(reply->error() != QNetworkReply::NoError); +} + void tst_QNetworkReply::ioGetWithManyProxies_data() { QTest::addColumn<QList<QNetworkProxy> >("proxyList"); @@ -2452,6 +2655,320 @@ void tst_QNetworkReply::ioPostToHttpFromFile() QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex()); } +void tst_QNetworkReply::ioPostToHttpFromSocket_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<QByteArray>("md5sum"); + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QNetworkProxy>("proxy"); + QTest::addColumn<int>("authenticationRequiredCount"); + QTest::addColumn<int>("proxyAuthenticationRequiredCount"); + + for (int i = 0; i < proxies.count(); ++i) + for (int auth = 0; auth < 2; ++auth) { + QUrl url; + if (auth) + url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + else + url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"; + + QNetworkProxy proxy = proxies.at(i).proxy; + QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag; + int proxyauthcount = proxies.at(i).requiresAuthentication; + + QByteArray data; + data = ""; + QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = "This is a normal message."; + QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = "This is a message to show that Qt rocks!\r\n\n"; + QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray("abcd\0\1\2\abcd",12); + QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray(4097, '\4'); + QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray(128*1024+1, '\177'); + QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + } +} + +void tst_QNetworkReply::ioPostToHttpFromSocket() +{ + qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy + qRegisterMetaType<QAuthenticator *>(); + qRegisterMetaType<QNetworkReply *>(); + + QFETCH(QByteArray, data); + QFETCH(QUrl, url); + QFETCH(QNetworkProxy, proxy); + SocketPair socketpair; + socketpair.create(); + QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]); + + socketpair.endPoints[0]->write(data); + + QNetworkRequest request(url); + manager.setProxy(proxy); + QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), socketpair.endPoints[1]); + socketpair.endPoints[0]->close(); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(1); + + disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + // verify that the HTTP status code is 200 Ok + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); + + QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount"); + QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount"); + } + +// this tests checks if rewinding the POST-data to some place in the middle +// worked. +void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd() +{ + QFile sourceFile(SRCDIR "/rfc3252.txt"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + // seeking to the middle + sourceFile.seek(sourceFile.size() / 2); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + sourceFile.seek(sourceFile.size() / 2); + QByteArray data = sourceFile.readAll(); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + +void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes() +{ + QFile sourceFile(SRCDIR "/rfc3252.txt"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + // seeking to the middle + sourceFile.seek(sourceFile.size() / 2); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + // only send 5 bytes + request.setHeader(QNetworkRequest::ContentLengthHeader, 5); + QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid()); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + sourceFile.seek(sourceFile.size() / 2); + QByteArray data = sourceFile.read(5); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + +void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes() +{ + // test needed since a QBuffer goes with a different codepath than the QFile + // tested in ioPostToHttpFromMiddleOfFileFiveBytes + QBuffer uploadBuffer; + uploadBuffer.open(QIODevice::ReadWrite); + uploadBuffer.write("1234567890"); + uploadBuffer.seek(5); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.post(request, &uploadBuffer); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + uploadBuffer.seek(5); + QByteArray data = uploadBuffer.read(5); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + + +void tst_QNetworkReply::ioPostToHttpNoBufferFlag() +{ + QByteArray data = QByteArray("daaaaaaataaaaaaa"); + // create a sequential QIODevice by feeding the data into a local TCP server + SocketPair socketpair; + socketpair.create(); + QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]); + socketpair.endPoints[0]->write(data); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + // disallow buffering + request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true); + request.setHeader(QNetworkRequest::ContentLengthHeader, data.size()); + QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]); + socketpair.endPoints[0]->close(); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + // verify: error code is QNetworkReply::ContentReSendError + QCOMPARE(reply->error(), QNetworkReply::ContentReSendError); +} + + +void tst_QNetworkReply::ioPostToHttpUploadProgress() +{ + QFile sourceFile(SRCDIR "/bigfile"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + + // emulate a minimal http server + QTcpServer server; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + // create the request + QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort())); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); + QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); + connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QTcpSocket *incomingSocket = server.nextPendingConnection(); + QVERIFY(incomingSocket); + disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + incomingSocket->setReadBufferSize(1*1024); + QTestEventLoop::instance().enterLoop(2); + // some progress should have been made + QList<QVariant> args = spy.last(); + QVERIFY(!args.isEmpty()); + QVERIFY(args.at(0).toLongLong() > 0); + + incomingSocket->setReadBufferSize(32*1024); + incomingSocket->read(16*1024); + QTestEventLoop::instance().enterLoop(2); + // some more progress than before + QList<QVariant> args2 = spy.last(); + QVERIFY(!args2.isEmpty()); + QVERIFY(args2.at(0).toLongLong() > args.at(0).toLongLong()); + + // set the read buffer to unlimited + incomingSocket->setReadBufferSize(0); + QTestEventLoop::instance().enterLoop(10); + // progress should be finished + QList<QVariant> args3 = spy.last(); + QVERIFY(!args3.isEmpty()); + QVERIFY(args3.at(0).toLongLong() > args2.at(0).toLongLong()); + QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong()); + QCOMPARE(args3.at(0).toLongLong(), sourceFile.size()); + + // after sending this, the QNAM should emit finished() + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + incomingSocket->write("HTTP/1.0 200 OK\r\n"); + incomingSocket->write("Content-Length: 0\r\n"); + incomingSocket->write("\r\n"); + QTestEventLoop::instance().enterLoop(10); + // not timeouted -> finished() was emitted + QVERIFY(!QTestEventLoop::instance().timeout()); + + incomingSocket->close(); + server.close(); +} + +void tst_QNetworkReply::ioPostToHttpEmtpyUploadProgress() +{ + QByteArray ba; + ba.resize(0); + QBuffer buffer(&ba,0); + QVERIFY(buffer.open(QIODevice::ReadOnly)); + + // emulate a minimal http server + QTcpServer server; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + // create the request + QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort())); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.post(request, &buffer); + QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); + connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QTcpSocket *incomingSocket = server.nextPendingConnection(); + QVERIFY(incomingSocket); + + // after sending this, the QNAM should emit finished() + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + incomingSocket->write("HTTP/1.0 200 OK\r\n"); + incomingSocket->write("Content-Length: 0\r\n"); + incomingSocket->write("\r\n"); + incomingSocket->flush(); + QTestEventLoop::instance().enterLoop(10); + // not timeouted -> finished() was emitted + QVERIFY(!QTestEventLoop::instance().timeout()); + + // final check: only 1 uploadProgress has been emitted + QVERIFY(spy.length() == 1); + QList<QVariant> args = spy.last(); + QVERIFY(!args.isEmpty()); + QCOMPARE(args.at(0).toLongLong(), buffer.size()); + QCOMPARE(args.at(0).toLongLong(), buffer.size()); + + incomingSocket->close(); + server.close(); +} + + void tst_QNetworkReply::rateControl_data() { QTest::addColumn<int>("rate"); @@ -2488,8 +3005,8 @@ void tst_QNetworkReply::rateControl() QTestEventLoop::instance().enterLoop(40); int elapsedTime = loopTime.elapsed(); - qDebug() << "send rate:" << sender.transferRate; - qDebug() << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime + qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate; + qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)"; sender.wait(); @@ -2523,23 +3040,54 @@ void tst_QNetworkReply::downloadPerformance() sender.wait(); qint64 receivedBytes = reader.totalBytes; - qDebug() << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and" + qDebug() << "tst_QNetworkReply::downloadPerformance" << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and" << elapsedTime << "ms"; } void tst_QNetworkReply::uploadPerformance() { - ThreadedDataReader reader; - DataGenerator generator; - QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(reader.serverPort()) + "/?bare=1"); - QNetworkReplyPtr reply = manager.put(request, &generator); + ThreadedDataReader reader; + DataGenerator generator; - connect(&reader, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTimer::singleShot(5000, &generator, SLOT(stop())); - generator.start(); - QTestEventLoop::instance().enterLoop(40); + + QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(reader.serverPort()) + "/?bare=1"); + QNetworkReplyPtr reply = manager.put(request, &generator); + generator.start(); + connect(&reader, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTimer::singleShot(5000, &generator, SLOT(stop())); + + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + +void tst_QNetworkReply::httpUploadPerformance() +{ + enum {UploadSize = 1000*1024*1024}; // 1000 MB + ThreadedDataReaderHttpServer reader; + FixedSizeDataGenerator generator(UploadSize); + + QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(reader.serverPort()) + "/?bare=1")); + request.setHeader(QNetworkRequest::ContentLengthHeader,UploadSize); + + QNetworkReplyPtr reply = manager.put(request, &generator); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QTime time; + generator.start(); + time.start(); + QTestEventLoop::instance().enterLoop(40); + QVERIFY(!QTestEventLoop::instance().timeout()); + + qint64 elapsed = time.elapsed(); + qWarning() << "tst_QNetworkReply::httpUploadPerformance" << elapsed << "msec, " + << ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec"; + + reader.exit(); + reader.wait(3000); } + void tst_QNetworkReply::performanceControlRate() { // this is a control comparison for the other two above @@ -2560,7 +3108,7 @@ void tst_QNetworkReply::performanceControlRate() sender.wait(); qint64 receivedBytes = reader.totalBytes; - qDebug() << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and" + qDebug() << "tst_QNetworkReply::performanceControlRate" << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and" << elapsedTime << "ms"; } @@ -2592,6 +3140,7 @@ void tst_QNetworkReply::downloadProgress() QByteArray data(128, 'a'); QTcpSocket *sender = server.nextPendingConnection(); + QVERIFY(sender); QFETCH(int, loopCount); for (int i = 1; i <= loopCount; ++i) { diff --git a/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp b/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp index 2e5fd00..7e910d4 100644 --- a/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp +++ b/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp @@ -42,6 +42,7 @@ #include <QtTest/QtTest> #include <QtCore/qpropertyanimation.h> +#include <QtCore/qvariantanimation.h> #include <QtGui/qwidget.h> //TESTED_CLASS=QPropertyAnimation @@ -95,6 +96,8 @@ private slots: void zeroDurationStart(); void operationsInStates_data(); void operationsInStates(); + void oneKeyValue(); + void updateOnSetKeyValues(); }; tst_QPropertyAnimation::tst_QPropertyAnimation() @@ -794,9 +797,9 @@ void tst_QPropertyAnimation::operationsInStates() * | pause() |start() |resume() |stop() * ----------+------------+-----------+-----------+-------------------+ * Stopped | Stopped |Running |Stopped |Stopped | - * _| qWarning | |qWarning |- | + * _| qWarning |restart |qWarning | | * Paused | Paused |Running |Running |Stopped | - * _| - | | | | + * _| | | | | * Running | Paused |Running |Running |Stopped | * | |restart |qWarning | | * ----------+------------+-----------+-----------+-------------------+ @@ -850,5 +853,67 @@ void tst_QPropertyAnimation::operationsInStates() #undef Resume #undef Stop +void tst_QPropertyAnimation::oneKeyValue() +{ + QObject o; + o.setProperty("ole", 42); + QCOMPARE(o.property("ole").toInt(), 42); + + QPropertyAnimation animation(&o, "ole"); + animation.setStartValue(43); + animation.setEndValue(44); + animation.setDuration(100); + + animation.setCurrentTime(0); + + QVERIFY(animation.currentValue().isValid()); + QCOMPARE(animation.currentValue().toInt(), 43); + QCOMPARE(o.property("ole").toInt(), 42); + + // remove the last key value + animation.setKeyValueAt(1.0, QVariant()); + + // we will neither interpolate, nor update the current value + // since there is only one 1 key value defined + animation.setCurrentTime(100); + + // the animation should not have been modified + QVERIFY(animation.currentValue().isValid()); + QCOMPARE(animation.currentValue().toInt(), 43); + QCOMPARE(o.property("ole").toInt(), 42); +} + +void tst_QPropertyAnimation::updateOnSetKeyValues() +{ + QObject o; + o.setProperty("ole", 100); + QCOMPARE(o.property("ole").toInt(), 100); + + QPropertyAnimation animation(&o, "ole"); + animation.setStartValue(100); + animation.setEndValue(200); + animation.setDuration(100); + + animation.setCurrentTime(50); + QCOMPARE(animation.currentValue().toInt(), 150); + animation.setKeyValueAt(0.0, 300); + QCOMPARE(animation.currentValue().toInt(), 250); + + o.setProperty("ole", 100); + QPropertyAnimation animation2(&o, "ole"); + QVariantAnimation::KeyValues kValues; + kValues << QVariantAnimation::KeyValue(0.0, 100) << QVariantAnimation::KeyValue(1.0, 200); + animation2.setKeyValues(kValues); + animation2.setDuration(100); + animation2.setCurrentTime(50); + QCOMPARE(animation2.currentValue().toInt(), 150); + + kValues.clear(); + kValues << QVariantAnimation::KeyValue(0.0, 300) << QVariantAnimation::KeyValue(1.0, 200); + animation2.setKeyValues(kValues); + + QCOMPARE(animation2.currentValue().toInt(), animation.currentValue().toInt()); +} + QTEST_MAIN(tst_QPropertyAnimation) #include "tst_qpropertyanimation.moc" diff --git a/tests/auto/qringbuffer/qringbuffer.pro b/tests/auto/qringbuffer/qringbuffer.pro new file mode 100644 index 0000000..91fb0a0 --- /dev/null +++ b/tests/auto/qringbuffer/qringbuffer.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qringbuffer.cpp + +QT = core + + diff --git a/tests/auto/qringbuffer/tst_qringbuffer.cpp b/tests/auto/qringbuffer/tst_qringbuffer.cpp new file mode 100644 index 0000000..c741c2e --- /dev/null +++ b/tests/auto/qringbuffer/tst_qringbuffer.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite 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 <QtTest/QtTest> + +#include <private/qringbuffer_p.h> + +class tst_QRingBuffer : public QObject +{ + Q_OBJECT + +public: + tst_QRingBuffer(); + virtual ~tst_QRingBuffer(); +public slots: + void initTestCase(); + void cleanupTestCase(); +private slots: + void readPointerAtPositionWriteRead(); + void readPointerAtPositionEmptyRead(); + void readPointerAtPositionWithHead(); + void readPointerAtPositionReadTooMuch(); + void sizeWhenEmpty(); + void sizeWhenReservedAndChopped(); + void sizeWhenReserved(); +}; + +tst_QRingBuffer::tst_QRingBuffer() +{ +} + +tst_QRingBuffer::~tst_QRingBuffer() +{ +} + +void tst_QRingBuffer::initTestCase() +{ +} + +void tst_QRingBuffer::cleanupTestCase() +{ +} + +void tst_QRingBuffer::sizeWhenReserved() +{ + QRingBuffer ringBuffer; + ringBuffer.reserve(5); + + QCOMPARE(ringBuffer.size(), 5); +} + +void tst_QRingBuffer::sizeWhenReservedAndChopped() +{ + QRingBuffer ringBuffer; + ringBuffer.reserve(31337); + ringBuffer.chop(31337); + + QCOMPARE(ringBuffer.size(), 0); +} + +void tst_QRingBuffer::sizeWhenEmpty() +{ + QRingBuffer ringBuffer; + + QCOMPARE(ringBuffer.size(), 0); +} + +void tst_QRingBuffer::readPointerAtPositionReadTooMuch() +{ + QRingBuffer ringBuffer; + + qint64 length; + const char *buf = ringBuffer.readPointerAtPosition(42, length); + QVERIFY(buf == 0); + QVERIFY(length == 0); +} + +void tst_QRingBuffer::readPointerAtPositionWithHead() +{ + QRingBuffer ringBuffer; + char *buf = ringBuffer.reserve(4); + memcpy (buf, "0123", 4); + ringBuffer.free(2); + + // ringBuffer should have stayed the same except + // its head it had moved to position 2 + qint64 length; + const char* buf2 = ringBuffer.readPointerAtPosition(0, length); + + QCOMPARE(length, qint64(2)); + QVERIFY(*buf2 == '2'); + QVERIFY(*(buf2+1) == '3'); + + // advance 2 more, ringBuffer should be empty then + ringBuffer.free(2); + buf2 = ringBuffer.readPointerAtPosition(0, length); + QCOMPARE(length, qint64(0)); + QVERIFY(buf2 == 0); +} + +void tst_QRingBuffer::readPointerAtPositionEmptyRead() +{ + QRingBuffer ringBuffer; + + qint64 length; + const char *buf = ringBuffer.readPointerAtPosition(0, length); + QVERIFY(buf == 0); + QVERIFY(length == 0); +} + +void tst_QRingBuffer::readPointerAtPositionWriteRead() +{ + //create some data + QBuffer inData; + inData.open(QIODevice::ReadWrite); + inData.putChar(0x42); + inData.putChar(0x23); + inData.write("Qt rocks!"); + for (int i = 0; i < 5000; i++) + inData.write(QString("Number %1").arg(i).toUtf8()); + inData.reset(); + QVERIFY(inData.size() > 0); + + //put the inData in the QRingBuffer + QRingBuffer ringBuffer; + qint64 remaining = inData.size(); + while (remaining > 0) { + // write in chunks of 50 bytes + // this ensures there will be multiple QByteArrays inside the QRingBuffer + // since QRingBuffer is then only using individual arrays of around 4000 bytes + qint64 thisWrite = qMin(remaining, qint64(50)); + char *pos = ringBuffer.reserve(thisWrite); + inData.read(pos, thisWrite); + remaining -= thisWrite; + } + // was data put into it? + QVERIFY(ringBuffer.size() > 0); + QCOMPARE(qint64(ringBuffer.size()), inData.size()); + + //read from the QRingBuffer in loop, put back into another QBuffer + QBuffer outData; + outData.open(QIODevice::ReadWrite); + remaining = ringBuffer.size(); + while (remaining > 0) { + qint64 thisRead; + // always try to read as much as possible + const char *buf = ringBuffer.readPointerAtPosition(ringBuffer.size() - remaining, thisRead); + outData.write(buf, thisRead); + remaining -= thisRead; + } + outData.reset(); + + QVERIFY(outData.size() > 0); + + // was the data read from the QRingBuffer the same as the one written into it? + QCOMPARE(outData.size(), inData.size()); + QVERIFY(outData.buffer().startsWith(inData.buffer())); +} + + +QTEST_APPLESS_MAIN(tst_QRingBuffer) +#include "tst_qringbuffer.moc" diff --git a/tests/auto/qsidebar/tst_qsidebar.cpp b/tests/auto/qsidebar/tst_qsidebar.cpp index 705e222..1384391 100644 --- a/tests/auto/qsidebar/tst_qsidebar.cpp +++ b/tests/auto/qsidebar/tst_qsidebar.cpp @@ -185,6 +185,13 @@ void tst_QSidebar::addUrls() qsidebar.addUrls(doubleUrls, 1); QCOMPARE(qsidebar.urls().size(), 1); + // Two paths that are effectively pointing to the same location + doubleUrls << QUrl::fromLocalFile(QDir::home().absolutePath()); + doubleUrls << QUrl::fromLocalFile(QDir::home().absolutePath() + "/."); + qsidebar.setUrls(emptyUrls); + qsidebar.addUrls(doubleUrls, 1); + QCOMPARE(qsidebar.urls().size(), 1); + #if defined(Q_OS_WIN) //Windows is case insensitive so no duplicate entries in that case doubleUrls << QUrl::fromLocalFile(QDir::home().absolutePath()); @@ -200,8 +207,6 @@ void tst_QSidebar::addUrls() qsidebar.addUrls(doubleUrls, 1); QCOMPARE(qsidebar.urls().size(), 2); #endif - - } void tst_QSidebar::goToUrl() diff --git a/tests/auto/qspinbox/tst_qspinbox.cpp b/tests/auto/qspinbox/tst_qspinbox.cpp index 1867356..575f261 100644 --- a/tests/auto/qspinbox/tst_qspinbox.cpp +++ b/tests/auto/qspinbox/tst_qspinbox.cpp @@ -241,6 +241,12 @@ void tst_QSpinBox::getSetCheck() QCOMPARE(0.0, obj2.value()); obj2.setValue(1.0); QCOMPARE(1.0, obj2.value()); + + // Make sure we update line edit geometry when updating + // buttons - see task 235747 + QRect oldEditGeometry = obj1.childrenRect(); + obj1.setButtonSymbols(QAbstractSpinBox::NoButtons); + QVERIFY(obj1.childrenRect() != oldEditGeometry); } tst_QSpinBox::tst_QSpinBox() diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp index 074f16f..7f97972 100644 --- a/tests/auto/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp @@ -178,9 +178,11 @@ private slots: void task_217003_data() { generic_data(); } void task_217003(); #endif - void task_250026_data() { generic_data("QODBC"); } void task_250026(); + void task_205701_data() { generic_data("QMYSQL"); } + void task_205701(); + private: @@ -297,7 +299,7 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) #ifdef NOT_READY_YET tablenames << qTableName( "Planet" ); #endif - tablenames << qTableName( "task_250026" ); + tablenames << qTableName( "task_250026" ); tst_Databases::safeDropTables( db, tablenames ); } @@ -2711,5 +2713,21 @@ void tst_QSqlQuery::task_250026() QCOMPARE( q.value( 0 ).toString().length(), data1026.length() ); } +void tst_QSqlQuery::task_205701() +{ + QSqlDatabase qsdb = QSqlDatabase::addDatabase("QMYSQL", "atest"); + qsdb.setHostName("test"); + qsdb.setDatabaseName("test"); + qsdb.setUserName("test"); + qsdb.setPassword("test"); + qsdb.open(); + +// { + QSqlQuery query(qsdb); +// } + QSqlDatabase::removeDatabase("atest"); +} + + QTEST_MAIN( tst_QSqlQuery ) #include "tst_qsqlquery.moc" diff --git a/tests/auto/qstate/tst_qstate.cpp b/tests/auto/qstate/tst_qstate.cpp index bb7de20..75b1905 100644 --- a/tests/auto/qstate/tst_qstate.cpp +++ b/tests/auto/qstate/tst_qstate.cpp @@ -255,7 +255,7 @@ public: } protected: - bool eventTest(QEvent *e) const + bool eventTest(QEvent *e) { return e->type() == m_type; } diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index edd6459..7476831 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -105,6 +105,8 @@ private slots: void eventTransitions(); void historyStates(); void startAndStop(); + void targetStateWithNoParent(); + void targetStateDeleted(); void transitionToRootState(); void transitionEntersParent(); @@ -202,7 +204,7 @@ public: : QAbstractTransition(QList<QAbstractState*>() << target) {} QList<int> triggers; protected: - virtual bool eventTest(QEvent *) const { + virtual bool eventTest(QEvent *) { return true; } virtual void onTransition(QEvent *) { @@ -244,7 +246,7 @@ public: EventTransition(QEvent::Type type, QAbstractState *target, QState *parent = 0) : QAbstractTransition(QList<QAbstractState*>() << target, parent), m_type(type) {} protected: - virtual bool eventTest(QEvent *e) const { + virtual bool eventTest(QEvent *e) { return (e->type() == m_type); } virtual void onTransition(QEvent *) {} @@ -254,6 +256,8 @@ private: void tst_QStateMachine::transitionToRootState() { + s_countWarnings = false; + QStateMachine machine; QState *initialState = new QState(); @@ -668,6 +672,8 @@ void tst_QStateMachine::errorStateHasErrors() void tst_QStateMachine::errorStateIsRootState() { + s_countWarnings = false; + QStateMachine machine; machine.setErrorState(machine.rootState()); @@ -691,9 +697,8 @@ void tst_QStateMachine::errorStateIsRootState() machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); QCoreApplication::processEvents(); - QEXPECT_FAIL("", "Covered by transitionToRootState test. Remove this when that test passes", Continue); QCOMPARE(machine.configuration().count(), 1); - QVERIFY(machine.configuration().contains(initialState)); + QVERIFY(machine.configuration().contains(machine.errorState())); } void tst_QStateMachine::errorStateEntersParentFirst() @@ -1088,11 +1093,28 @@ void tst_QStateMachine::stateEntryAndExit() QStateMachine machine; TestState *s1 = new TestState(machine.rootState()); + QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add transition to null state"); + s1->addTransition((QAbstractState*)0); + QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add null transition"); + s1->addTransition((QAbstractTransition*)0); + QTest::ignoreMessage(QtWarningMsg, "QState::removeTransition: cannot remove null transition"); + s1->removeTransition((QAbstractTransition*)0); + TestState *s2 = new TestState(machine.rootState()); QFinalState *s3 = new QFinalState(machine.rootState()); TestTransition *t = new TestTransition(s2); - s1->addTransition(t); - s2->addTransition(s3); + QCOMPARE(s1->addTransition(t), (QAbstractTransition*)t); + { + QAbstractTransition *trans = s2->addTransition(s3); + QVERIFY(trans != 0); + QCOMPARE(trans->sourceState(), (QAbstractState*)s2); + QCOMPARE(trans->targetState(), (QAbstractState*)s3); + s2->removeTransition(trans); + QCOMPARE(trans->sourceState(), (QAbstractState*)0); + QCOMPARE(trans->targetState(), (QAbstractState*)s3); + QCOMPARE(s2->addTransition(trans), trans); + QCOMPARE(trans->sourceState(), (QAbstractState*)s2); + } QSignalSpy startedSpy(&machine, SIGNAL(started())); QSignalSpy stoppedSpy(&machine, SIGNAL(stopped())); @@ -1231,6 +1253,8 @@ void tst_QStateMachine::assignPropertyWithAnimation() { QStateMachine machine; QObject obj; + obj.setProperty("foo", 321); + obj.setProperty("bar", 654); QState *s1 = new QState(machine.rootState()); s1->assignProperty(&obj, "foo", 123); QState *s2 = new QState(machine.rootState()); @@ -1254,6 +1278,8 @@ void tst_QStateMachine::assignPropertyWithAnimation() { QStateMachine machine; QObject obj; + obj.setProperty("foo", 321); + obj.setProperty("bar", 654); QState *s1 = new QState(machine.rootState()); s1->assignProperty(&obj, "foo", 123); QState *s2 = new QState(machine.rootState()); @@ -1280,6 +1306,8 @@ void tst_QStateMachine::assignPropertyWithAnimation() { QStateMachine machine; QObject obj; + obj.setProperty("foo", 321); + obj.setProperty("bar", 654); QState *s1 = new QState(machine.rootState()); s1->assignProperty(&obj, "foo", 123); s1->assignProperty(&obj, "bar", 321); @@ -1307,7 +1335,11 @@ void tst_QStateMachine::assignPropertyWithAnimation() { QStateMachine machine; QObject obj; + obj.setProperty("foo", 321); + obj.setProperty("bar", 654); QState *s1 = new QState(machine.rootState()); + QCOMPARE(s1->childMode(), QState::ExclusiveStates); + QCOMPARE(s1->initialState(), (QAbstractState*)0); s1->setObjectName("s1"); s1->assignProperty(&obj, "foo", 123); s1->assignProperty(&obj, "bar", 456); @@ -1321,6 +1353,7 @@ void tst_QStateMachine::assignPropertyWithAnimation() s22->setObjectName("s22"); s22->assignProperty(&obj, "bar", 789); s2->setInitialState(s21); + QCOMPARE(s2->initialState(), (QAbstractState*)s21); QAbstractTransition *trans = s1->addTransition(s2); QPropertyAnimation anim(&obj, "foo"); @@ -1361,7 +1394,7 @@ public: : QAbstractTransition(QList<QAbstractState*>() << target), m_value(value) {} protected: - virtual bool eventTest(QEvent *e) const + virtual bool eventTest(QEvent *e) { if (e->type() != QEvent::Type(QEvent::User+2)) return false; @@ -1445,6 +1478,7 @@ void tst_QStateMachine::parallelStates() QStateMachine machine; QState *s1 = new QState(QState::ParallelStates); + QCOMPARE(s1->childMode(), QState::ParallelStates); QState *s1_1 = new QState(s1); QState *s1_1_1 = new QState(s1_1); QFinalState *s1_1_f = new QFinalState(s1_1); @@ -1466,6 +1500,8 @@ void tst_QStateMachine::parallelStates() QSignalSpy finishedSpy(&machine, SIGNAL(finished())); machine.start(); QTRY_COMPARE(finishedSpy.count(), 1); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s2)); } void tst_QStateMachine::allSourceToTargetConfigurations() @@ -1560,7 +1596,7 @@ public: return m_args; } protected: - bool eventTest(QEvent *e) const { + bool eventTest(QEvent *e) { if (!QSignalTransition::eventTest(e)) return false; QSignalEvent *se = static_cast<QSignalEvent*>(e); @@ -1576,9 +1612,28 @@ void tst_QStateMachine::signalTransitions() { QStateMachine machine; QState *s0 = new QState(machine.rootState()); - QFinalState *s1 = new QFinalState(machine.rootState()); + QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: sender cannot be null"); + QCOMPARE(s0->addTransition(0, SIGNAL(noSuchSignal()), 0), (QObject*)0); + SignalEmitter emitter; - s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1); + QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: signal cannot be null"); + QCOMPARE(s0->addTransition(&emitter, 0, 0), (QObject*)0); + + QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add transition to null state"); + QCOMPARE(s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), 0), (QObject*)0); + + QFinalState *s1 = new QFinalState(machine.rootState()); + QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: no such signal SignalEmitter::noSuchSignal()"); + QCOMPARE(s0->addTransition(&emitter, SIGNAL(noSuchSignal()), s1), (QObject*)0); + + { + QSignalTransition *trans = s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1); + QVERIFY(trans != 0); + QCOMPARE(trans->sourceState(), s0); + QCOMPARE(trans->targetState(), (QAbstractState*)s1); + QCOMPARE(trans->senderObject(), (QObject*)&emitter); + QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithNoArg()))); + } QSignalSpy finishedSpy(&machine, SIGNAL(finished())); machine.setInitialState(s0); @@ -1588,6 +1643,8 @@ void tst_QStateMachine::signalTransitions() emitter.emitSignalWithNoArg(); QTRY_COMPARE(finishedSpy.count(), 1); + + emitter.emitSignalWithNoArg(); } { QStateMachine machine; @@ -1654,6 +1711,51 @@ void tst_QStateMachine::signalTransitions() QTRY_COMPARE(finishedSpy.count(), 1); } + // Multiple transitions for same (object,signal) + { + QStateMachine machine; + SignalEmitter emitter; + QState *s0 = new QState(machine.rootState()); + QState *s1 = new QState(machine.rootState()); + QSignalTransition *t0 = s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1); + QSignalTransition *t1 = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s0); + + QSignalSpy finishedSpy(&machine, SIGNAL(finished())); + machine.setInitialState(s0); + machine.start(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s1)); + + s0->removeTransition(t0); + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + s1->removeTransition(t1); + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + s0->addTransition(t0); + s1->addTransition(t1); + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s1)); + } } void tst_QStateMachine::eventTransitions() @@ -1679,6 +1781,8 @@ void tst_QStateMachine::eventTransitions() QCoreApplication::processEvents(); QTRY_COMPARE(finishedSpy.count(), 1); + + QTest::mousePress(&button, Qt::LeftButton); } { QStateMachine machine; @@ -1777,6 +1881,54 @@ void tst_QStateMachine::eventTransitions() QTRY_COMPARE(finishedSpy.count(), 1); } + // Multiple transitions for same (object,event) + { + QStateMachine machine; + QState *s0 = new QState(machine.rootState()); + QState *s1 = new QState(machine.rootState()); + QEventTransition *t0 = new QEventTransition(&button, QEvent::MouseButtonPress); + t0->setTargetState(s1); + s0->addTransition(t0); + QEventTransition *t1 = new QEventTransition(&button, QEvent::MouseButtonPress); + t1->setTargetState(s0); + s1->addTransition(t1); + + QSignalSpy finishedSpy(&machine, SIGNAL(finished())); + machine.setInitialState(s0); + machine.start(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + QTest::mousePress(&button, Qt::LeftButton); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s1)); + + s0->removeTransition(t0); + QTest::mousePress(&button, Qt::LeftButton); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + QTest::mousePress(&button, Qt::LeftButton); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + s1->removeTransition(t1); + QTest::mousePress(&button, Qt::LeftButton); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + s0->addTransition(t0); + s1->addTransition(t1); + QTest::mousePress(&button, Qt::LeftButton); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s1)); + } } void tst_QStateMachine::historyStates() @@ -1868,6 +2020,40 @@ void tst_QStateMachine::startAndStop() QVERIFY(machine.configuration().contains(s1)); } +void tst_QStateMachine::targetStateWithNoParent() +{ + QStateMachine machine; + QState *s1 = new QState(machine.rootState()); + s1->setObjectName("s1"); + QState *s2 = new QState(); + s1->addTransition(s2); + machine.setInitialState(s1); + QSignalSpy startedSpy(&machine, SIGNAL(started())); + QSignalSpy stoppedSpy(&machine, SIGNAL(stopped())); + QSignalSpy finishedSpy(&machine, SIGNAL(finished())); + machine.start(); + QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 's1'"); + QTRY_COMPARE(machine.isRunning(), true); + QTRY_COMPARE(startedSpy.count(), 1); + QCOMPARE(stoppedSpy.count(), 0); + QCOMPARE(finishedSpy.count(), 0); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(machine.errorState())); + QCOMPARE(machine.error(), QStateMachine::NoCommonAncestorForTransitionError); +} + +void tst_QStateMachine::targetStateDeleted() +{ + QStateMachine machine; + QState *s1 = new QState(machine.rootState()); + s1->setObjectName("s1"); + QState *s2 = new QState(machine.rootState()); + QAbstractTransition *trans = s1->addTransition(s2); + delete s2; + QCOMPARE(trans->targetState(), (QAbstractState*)0); + QVERIFY(trans->targetStates().isEmpty()); +} + void tst_QStateMachine::defaultGlobalRestorePolicy() { QStateMachine machine; @@ -2436,6 +2622,7 @@ void tst_QStateMachine::nestedTargetStateForAnimation() QAbstractTransition *at = s2Child->addTransition(new EventTransition(QEvent::User, s2Child2)); QPropertyAnimation *animation = new QPropertyAnimation(object, "bar", s2); + animation->setDuration(2000); connect(animation, SIGNAL(finished()), &counter, SLOT(slot())); at->addAnimation(animation); @@ -2448,10 +2635,11 @@ void tst_QStateMachine::nestedTargetStateForAnimation() animation = new QPropertyAnimation(object, "bar", s2); connect(animation, SIGNAL(finished()), &counter, SLOT(slot())); at->addAnimation(animation); - + QState *s3 = new QState(machine.rootState()); + s2->addTransition(s2Child, SIGNAL(polished()), s3); + QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); - s2->addTransition(s2, SIGNAL(polished()), s3); machine.setInitialState(s1); machine.start(); @@ -2622,9 +2810,12 @@ void tst_QStateMachine::removeDefaultAnimation() { QStateMachine machine; + QObject propertyHolder; + propertyHolder.setProperty("foo", 0); + QCOMPARE(machine.defaultAnimations().size(), 0); - QPropertyAnimation *anim = new QPropertyAnimation(this, "foo"); + QPropertyAnimation *anim = new QPropertyAnimation(&propertyHolder, "foo"); machine.addDefaultAnimation(anim); @@ -2637,7 +2828,7 @@ void tst_QStateMachine::removeDefaultAnimation() machine.addDefaultAnimation(anim); - QPropertyAnimation *anim2 = new QPropertyAnimation(this, "foo"); + QPropertyAnimation *anim2 = new QPropertyAnimation(&propertyHolder, "foo"); machine.addDefaultAnimation(anim2); QCOMPARE(machine.defaultAnimations().size(), 2); diff --git a/tools/assistant/tools/assistant/assistant.qch b/tools/assistant/tools/assistant/assistant.qch Binary files differindex 64763f7..99687ed 100644 --- a/tools/assistant/tools/assistant/assistant.qch +++ b/tools/assistant/tools/assistant/assistant.qch diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 40bf59f..02bb744 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -351,6 +351,7 @@ Configure::Configure( int& argc, char** argv ) dictionary[ "QMAKESPEC" ] = tmp; dictionary[ "INCREDIBUILD_XGE" ] = "auto"; + dictionary[ "LTCG" ] = "no"; } Configure::~Configure() @@ -487,6 +488,12 @@ void Configure::parseCmdLine() else if( configCmdLine.at(i) == "-commercial" ) { dictionary[ "BUILDTYPE" ] = "commercial"; } + else if( configCmdLine.at(i) == "-ltcg" ) { + dictionary[ "LTCG" ] = "yes"; + } + else if( configCmdLine.at(i) == "-no-ltcg" ) { + dictionary[ "LTCG" ] = "no"; + } #endif else if( configCmdLine.at(i) == "-platform" ) { @@ -1464,6 +1471,9 @@ bool Configure::displayHelp() desc("SHARED", "yes", "-shared", "Create and use shared Qt libraries."); desc("SHARED", "no", "-static", "Create and use static Qt libraries.\n"); + desc("LTCG", "yes", "-ltcg", "Use Link Time Code Generation. (Release builds only)"); + desc("LTCG", "no", "-no-ltcg", "Do not use Link Time Code Generation.\n"); + desc("FAST", "no", "-no-fast", "Configure Qt normally by generating Makefiles for all project files."); desc("FAST", "yes", "-fast", "Configure Qt quickly by generating Makefiles only for library and " "subdirectory targets. All other Makefiles are created as wrappers " @@ -2451,6 +2461,8 @@ void Configure::generateCachefile() else configStream << " static"; + if( dictionary[ "LTCG" ] == "yes" ) + configStream << " ltcg"; if( dictionary[ "STL" ] == "yes" ) configStream << " stl"; if ( dictionary[ "EXCEPTIONS" ] == "yes" ) @@ -2873,6 +2885,7 @@ void Configure::displayConfig() cout << "Architecture................" << dictionary[ "ARCHITECTURE" ] << endl; cout << "Maketool...................." << dictionary[ "MAKE" ] << endl; cout << "Debug symbols..............." << (dictionary[ "BUILD" ] == "debug" ? "yes" : "no") << endl; + cout << "Link Time Code Generation..." << dictionary[ "LTCG" ] << endl; cout << "Accessibility support......." << dictionary[ "ACCESSIBILITY" ] << endl; cout << "STL support................." << dictionary[ "STL" ] << endl; cout << "Exception support..........." << dictionary[ "EXCEPTIONS" ] << endl; diff --git a/tools/designer/src/lib/sdk/abstractformeditor.cpp b/tools/designer/src/lib/sdk/abstractformeditor.cpp index e6debd5..09d6976 100644 --- a/tools/designer/src/lib/sdk/abstractformeditor.cpp +++ b/tools/designer/src/lib/sdk/abstractformeditor.cpp @@ -72,7 +72,6 @@ static void initResources() Q_INIT_RESOURCE(shared); Q_INIT_RESOURCE(ClamshellPhone); Q_INIT_RESOURCE(PDAPhone); - Q_INIT_RESOURCE(pda); Q_INIT_RESOURCE(PortableMedia); Q_INIT_RESOURCE(S60_nHD_Touchscreen); Q_INIT_RESOURCE(S60_QVGA_Candybar); diff --git a/tools/designer/src/lib/shared/formwindowbase.cpp b/tools/designer/src/lib/shared/formwindowbase.cpp index 5be907b..377ae43 100644 --- a/tools/designer/src/lib/shared/formwindowbase.cpp +++ b/tools/designer/src/lib/shared/formwindowbase.cpp @@ -51,7 +51,7 @@ #include "deviceprofile_p.h" #include "qdesigner_utils_p.h" -#include <abstractformbuilder.h> +#include "qsimpleresource_p.h" #include <QtDesigner/QDesignerFormEditorInterface> #include <QtDesigner/QDesignerContainerExtension> @@ -478,6 +478,14 @@ void FormWindowBase::setupDefaultAction(QDesignerFormWindowInterface *fw) QObject::connect(fw, SIGNAL(activated(QWidget*)), fw, SLOT(triggerDefaultAction(QWidget*))); } +QString FormWindowBase::fileContents() const +{ + const bool oldValue = QSimpleResource::setWarningsEnabled(false); + const QString rc = contents(); + QSimpleResource::setWarningsEnabled(oldValue); + return rc; +} + } // namespace qdesigner_internal QT_END_NAMESPACE diff --git a/tools/designer/src/lib/shared/formwindowbase_p.h b/tools/designer/src/lib/shared/formwindowbase_p.h index 68e977e..0891f6e 100644 --- a/tools/designer/src/lib/shared/formwindowbase_p.h +++ b/tools/designer/src/lib/shared/formwindowbase_p.h @@ -90,6 +90,9 @@ public: QVariantMap formData(); void setFormData(const QVariantMap &vm); + // Return contents without warnings. Should be 'contents(bool quiet)' + QString fileContents() const; + // Return the widget containing the form. This is used to // apply embedded design settings to that are inherited (for example font). // These are meant to be applied to the form only and not to the other editors diff --git a/tools/designer/src/lib/shared/shared.pri b/tools/designer/src/lib/shared/shared.pri index 0424a41..8ed051a 100644 --- a/tools/designer/src/lib/shared/shared.pri +++ b/tools/designer/src/lib/shared/shared.pri @@ -186,17 +186,4 @@ SOURCES += \ $$PWD/filterwidget.cpp \ $$PWD/plugindialog.cpp -RESOURCES += $$PWD/shared.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/ClamshellPhone.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/PDAPhone.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/pda.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/PortableMedia.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/qvfb.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/S60-nHD-Touchscreen.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/S60-QVGA-Candybar.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/SmartPhone2.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/SmartPhone.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/SmartPhoneWithButtons.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/TouchscreenPhone.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/Trolltech-Keypad.qrc \ -$$QT_SOURCE_TREE/tools/qvfb/Trolltech-Touchscreen.qrc +RESOURCES += $$PWD/shared.qrc diff --git a/tools/designer/src/uitools/quiloader.cpp b/tools/designer/src/uitools/quiloader.cpp index 67bd29c..2a66095 100644 --- a/tools/designer/src/uitools/quiloader.cpp +++ b/tools/designer/src/uitools/quiloader.cpp @@ -572,53 +572,52 @@ void QUiLoaderPrivate::setupWidgetMap() const \class QUiLoader \inmodule QtUiTools - \brief The QUiLoader class allows standalone applications dynamically - create user interfaces at run-time using the information stored in - .ui files or specified plugin paths. + \brief The QUiLoader class enables standalone applications to + dynamically create user interfaces at run-time using the + information stored in .ui files or specified in plugin paths. - In addition, you can customize of creating an user interface by + In addition, you can customize or create your own user interface by deriving your own loader class. - If you have a custom component or an application that embeds Qt - Designer, you can also use the QFormBuilder class provided by the - QtDesigner module to create user interfaces from .ui files. + If you have a custom component or an application that embeds \QD, you can + also use the QFormBuilder class provided by the QtDesigner module to create + user interfaces from \c{.ui} files. - The QUiLoader class provides a collection of functions that allows - you to create widgets based on the information stored in \c .ui - files (created with Qt Designer) or available in the specified - plugin paths. The specified plugin paths can be retrieved using - the pluginPaths() function. You can retrieve the contents of an \c - .ui file using the load() function. For example: + The QUiLoader class provides a collection of functions allowing you to + create widgets based on the information stored in \c .ui files (created + with \QD) or available in the specified plugin paths. The specified plugin + paths can be retrieved using the pluginPaths() function. Similarly, the + contents of a \c{.ui} file can be retrieved using the load() function. For + example: \snippet doc/src/snippets/quiloader/mywidget.cpp 0 - By including the user interface in the form's resources (\c myform.qrc), - we ensure that it will be present at run-time: + By including the user interface in the form's resources (\c myform.qrc), we + ensure that it will be present at run-time: \quotefile doc/src/snippets/quiloader/mywidget.qrc - The availableWidgets() function returns a QStringList with the - class names of the widgets available in the specified plugin - paths. You can create any of these widgets using the - createWidget() function. For example: + The availableWidgets() function returns a QStringList with the class names + of the widgets available in the specified plugin paths. To create these + widgets, simply use the createWidget() function. For example: \snippet doc/src/snippets/quiloader/main.cpp 0 - You can make a custom widget available to the loader using the - addPluginPath() function, and you can remove all the available widgets - by calling the clearPluginPaths() function. + To make a custom widget available to the loader, you can use the + addPluginPath() function; to remove all available widgets, you can call + the clearPluginPaths() function. - The createAction(), createActionGroup(), createLayout() and - createWidget() functions are used internally by the QUiLoader class - whenever it has to create an action, action group, layout or - widget respectively. For that reason, you can subclass the QUiLoader - class and reimplement these functions to intervene the process of - constructing an user interface. For example, you might want to - create a list of the actions created when loading a form or - creating a custom widget. + The createAction(), createActionGroup(), createLayout(), and createWidget() + functions are used internally by the QUiLoader class whenever it has to + create an action, action group, layout, or widget respectively. For that + reason, you can subclass the QUiLoader class and reimplement these + functions to intervene the process of constructing a user interface. For + example, you might want to have a list of the actions created when loading + a form or creating a custom widget. However, in your reimplementation, you + must call QUiLoader's original implementation of these functions first. - For a complete example using the QUiLoader class, see the \l - {designer/calculatorbuilder}{Calculator Builder} example. + For a complete example using the QUiLoader class, see the + \l{Calculator Builder Example}. \sa QtUiTools, QFormBuilder */ @@ -653,8 +652,8 @@ QUiLoader::~QUiLoader() } /*! - Loads a form from the given \a device and creates a new widget with the given - \a parentWidget to hold its contents. + Loads a form from the given \a device and creates a new widget with the + given \a parentWidget to hold its contents. \sa createWidget() */ @@ -668,8 +667,8 @@ QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) } /*! - Returns a list naming the paths the loader searches when locating - custom widget plugins. + Returns a list naming the paths in which the loader will search when + locating custom widget plugins. \sa addPluginPath(), clearPluginPaths() */ @@ -680,7 +679,7 @@ QStringList QUiLoader::pluginPaths() const } /*! - Clears the list of paths the loader searches when locating + Clears the list of paths in which the loader will search when locating plugins. \sa addPluginPath(), pluginPaths() @@ -692,7 +691,7 @@ void QUiLoader::clearPluginPaths() } /*! - Adds the given \a path to the list of paths the loader searches + Adds the given \a path to the list of paths in which the loader will search when locating plugins. \sa pluginPaths(), clearPluginPaths() @@ -704,17 +703,17 @@ void QUiLoader::addPluginPath(const QString &path) } /*! - Creates a new widget with the given \a parent and \a name - using the class specified by \a className. You can use this - function to create any of the widgets returned by the - availableWidgets() function. + Creates a new widget with the given \a parent and \a name using the class + specified by \a className. You can use this function to create any of the + widgets returned by the availableWidgets() function. - The function is also used internally by the QUiLoader class whenever - it has to create a widget. For that reason, you can subclass the - QUiLoader class and reimplement this function to intervene in the - process of constructing a user interface or widget. + The function is also used internally by the QUiLoader class whenever it + creates a widget. Hence, you can subclass QUiLoader and reimplement this + function to intervene process of constructing a user interface or widget. + However, in your implementation, ensure that you call QUiLoader's version + first. - \sa availableWidgets(), load() + \sa availableWidgets(), load() */ QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) { @@ -723,13 +722,14 @@ QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, cons } /*! - Creates a new layout with the given \a parent and \a name - using the class specified by \a className. + Creates a new layout with the given \a parent and \a name using the class + specified by \a className. - The function is used internally by the QUiLoader class whenever it - has to create a layout. For that reason, you can subclass the - QUiLoader class and reimplement this function to intervene the - process of constructing an user interface or widget. + The function is also used internally by the QUiLoader class whenever it + creates a widget. Hence, you can subclass QUiLoader and reimplement this + function to intervene process of constructing a user interface or widget. + However, in your implementation, ensure that you call QUiLoader's version + first. \sa createWidget(), load() */ @@ -742,10 +742,11 @@ QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, cons /*! Creates a new action group with the given \a parent and \a name. - The function is used internally by the QUiLoader class whenever it - has to create an action group. For that reason, you can subclass - the QUiLoader class and reimplement this function to intervene the - process of constructing an user interface or widget. + The function is also used internally by the QUiLoader class whenever it + creates a widget. Hence, you can subclass QUiLoader and reimplement this + function to intervene process of constructing a user interface or widget. + However, in your implementation, ensure that you call QUiLoader's version + first. \sa createAction(), createWidget(), load() */ @@ -758,10 +759,11 @@ QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) /*! Creates a new action with the given \a parent and \a name. - The function is used internally by the QUiLoader class whenever it - has to create an action. For that reason, you can subclass the - QUiLoader class and reimplement this function to intervene the - process of constructing an user interface or widget. + The function is also used internally by the QUiLoader class whenever it + creates a widget. Hence, you can subclass QUiLoader and reimplement this + function to intervene process of constructing a user interface or widget. + However, in your implementation, ensure that you call QUiLoader's version + first. \sa createActionGroup(), createWidget(), load() */ @@ -772,9 +774,9 @@ QAction *QUiLoader::createAction(QObject *parent, const QString &name) } /*! - Returns a list naming the available widgets that can be built - using the createWidget() function, i.e all the widgets specified - within the given plugin paths. + Returns a list naming all available widgets that can be built using the + createWidget() function, i.e all the widgets specified within the given + plugin paths. \sa pluginPaths(), createWidget() @@ -795,11 +797,11 @@ QStringList QUiLoader::availableWidgets() const /*! - Returns a list naming the available layouts that can be built - using the createLayout() function + \since 4.5 + Returns a list naming all available layouts that can be built using the + createLayout() function \sa createLayout() - \since 4.5 */ QStringList QUiLoader::availableLayouts() const @@ -816,9 +818,9 @@ QStringList QUiLoader::availableLayouts() const } /*! - Sets the working directory of the loader to \a dir. The loader - looks for other resources, such as icons and resource files, - in paths relative to this directory. + Sets the working directory of the loader to \a dir. The loader will look + for other resources, such as icons and resource files, in paths relative to + this directory. \sa workingDirectory() */ @@ -842,9 +844,13 @@ QDir QUiLoader::workingDirectory() const } /*! - Sets whether the execution of scripts is enabled to \a enabled. - \since 4.3 \internal + \since 4.3 + + If \a enabled is true, the loader will be able to execute scripts. + Otherwise, execution of scripts will be disabled. + + \sa isScriptingEnabled() */ void QUiLoader::setScriptingEnabled(bool enabled) @@ -854,10 +860,12 @@ void QUiLoader::setScriptingEnabled(bool enabled) } /*! - Returns whether the execution of scripts is enabled. - \sa setScriptingEnabled() - \since 4.3 - \internal + \internal + \since 4.3 + + Returns true if execution of scripts is enabled; returns false otherwise. + + \sa setScriptingEnabled() */ bool QUiLoader::isScriptingEnabled() const @@ -867,11 +875,13 @@ bool QUiLoader::isScriptingEnabled() const } /*! - Sets whether user interfaces loaded by this loader automatically - retranslate themselves upon receiving a language change event or not, - depending on \a enabled. - \since 4.5 + + If \a enabled is true, user interfaces loaded by this loader will + automatically retranslate themselves upon receiving a language change + event. Otherwise, the user interfaces will not be retranslated. + + \sa isLanguageChangeEnabled() */ void QUiLoader::setLanguageChangeEnabled(bool enabled) @@ -881,9 +891,12 @@ void QUiLoader::setLanguageChangeEnabled(bool enabled) } /*! - Returns whether dynamic retranslation on language change is enabled. - \sa setLanguageChangeEnabled() - \since 4.5 + \since 4.5 + + Returns true if dynamic retranslation on language change is enabled; + returns false otherwise. + + \sa setLanguageChangeEnabled() */ bool QUiLoader::isLanguageChangeEnabled() const @@ -894,11 +907,14 @@ bool QUiLoader::isLanguageChangeEnabled() const /*! \internal + \since 4.5 - Sets whether user interfaces loaded by this loader are translated - at all. Note that this is orthogonal to languageChangeEnabled. + If \a enabled is true, user interfaces loaded by this loader will be + translated. Otherwise, the user interfaces will not be translated. - \since 4.5 + \note This is orthogonal to languageChangeEnabled. + + \sa isLanguageChangeEnabled(), setLanguageChangeEnabled() */ void QUiLoader::setTranslationEnabled(bool enabled) @@ -909,11 +925,11 @@ void QUiLoader::setTranslationEnabled(bool enabled) /*! \internal + \since 4.5 - Returns whether translation is enabled. - \sa setTranslationEnabled() + Returns true if translation is enabled; returns false otherwise. - \since 4.5 + \sa setTranslationEnabled() */ bool QUiLoader::isTranslationEnabled() const diff --git a/tools/linguist/lupdate/lupdate.h b/tools/linguist/lupdate/lupdate.h index 2f98643..6db544f 100644 --- a/tools/linguist/lupdate/lupdate.h +++ b/tools/linguist/lupdate/lupdate.h @@ -79,6 +79,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat bool loadJava(Translator &translator, const QString &filename, ConversionData &cd); bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd); bool loadUI(Translator &translator, const QString &filename, ConversionData &cd); +bool loadQml(Translator &translator, const QString &filename, ConversionData &cd); QT_END_NAMESPACE diff --git a/tools/linguist/lupdate/lupdate.pro b/tools/linguist/lupdate/lupdate.pro index ccc2d47..283d69f 100644 --- a/tools/linguist/lupdate/lupdate.pro +++ b/tools/linguist/lupdate/lupdate.pro @@ -15,6 +15,9 @@ build_all:!build_pass { include(../shared/formats.pri) include(../shared/proparser.pri) +include($$QT_SOURCE_TREE/src/declarative/qml/parser/parser.pri) +INCLUDEPATH += $$QT_SOURCE_TREE/src/declarative/qml + SOURCES += \ main.cpp \ merge.cpp \ @@ -23,6 +26,7 @@ SOURCES += \ cpp.cpp \ java.cpp \ qscript.cpp \ + qml.cpp \ ui.cpp HEADERS += \ diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp index 8a70b55..f47844f 100644 --- a/tools/linguist/lupdate/main.cpp +++ b/tools/linguist/lupdate/main.cpp @@ -428,7 +428,8 @@ int main(int argc, char **argv) if (!fn.endsWith(QLatin1String(".java")) && !fn.endsWith(QLatin1String(".ui")) && !fn.endsWith(QLatin1String(".js")) - && !fn.endsWith(QLatin1String(".qs"))) { + && !fn.endsWith(QLatin1String(".qs")) + && !fn.endsWith(QLatin1String(".qml"))) { int offset = 0; int depth = 0; do { @@ -518,6 +519,8 @@ int main(int argc, char **argv) else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive) || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) loadQScript(fetchedTor, *it, cd); + else if (it->endsWith(QLatin1String(".qml"), Qt::CaseInsensitive)) + loadQml(fetchedTor, *it, cd); else sourceFilesCpp << *it; } diff --git a/tools/linguist/lupdate/qml.cpp b/tools/linguist/lupdate/qml.cpp new file mode 100644 index 0000000..78a9afd --- /dev/null +++ b/tools/linguist/lupdate/qml.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Linguist 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 "lupdate.h" + +#include <translator.h> + +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +#include "parser/javascriptengine_p.h" +#include "parser/javascriptparser_p.h" +#include "parser/javascriptlexer_p.h" +#include "parser/javascriptnodepool_p.h" +#include "parser/javascriptastvisitor_p.h" +#include "parser/javascriptast_p.h" + +#include <QCoreApplication> +#include <QFile> +#include <QFileInfo> +#include <QtDebug> +#include <QStringList> + +#include <iostream> +#include <cstdlib> + +using namespace JavaScript; + +class FindTrCalls: protected AST::Visitor +{ +public: + void operator()(Translator *translator, const QString &fileName, AST::Node *node) + { + m_translator = translator; + m_fileName = fileName; + m_component = QFileInfo(fileName).baseName(); //matches qsTr usage in QScriptEngine + accept(node); + } + +protected: + using AST::Visitor::visit; + using AST::Visitor::endVisit; + + void accept(AST::Node *node) + { AST::Node::acceptChild(node, this); } + + virtual void endVisit(AST::CallExpression *node) + { + if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(node->base)) { + if (idExpr->name->asString() == QLatin1String("qsTr") || + idExpr->name->asString() == QLatin1String("QT_TR_NOOP")) { + if (node->arguments && AST::cast<AST::StringLiteral *>(node->arguments->expression)) { + AST::StringLiteral *literal = AST::cast<AST::StringLiteral *>(node->arguments->expression); + const QString source = literal->value->asString(); + + QString comment; + bool plural = false; + AST::ArgumentList *commentNode = node->arguments->next; + if (commentNode) { + literal = AST::cast<AST::StringLiteral *>(commentNode->expression); + comment = literal->value->asString(); + + AST::ArgumentList *nNode = commentNode->next; + if (nNode) { + AST::NumericLiteral *numLiteral = AST::cast<AST::NumericLiteral *>(nNode->expression); + if (numLiteral) { + plural = true; + } + } + } + + TranslatorMessage msg(m_component, source, + comment, QString(), m_fileName, + node->firstSourceLocation().startLine, QStringList(), + TranslatorMessage::Unfinished, plural); + m_translator->extend(msg); + } + } else if (idExpr->name->asString() == QLatin1String("qsTranslate") || + idExpr->name->asString() == QLatin1String("QT_TRANSLATE_NOOP")) { + if (node->arguments && AST::cast<AST::StringLiteral *>(node->arguments->expression)) { + AST::StringLiteral *literal = AST::cast<AST::StringLiteral *>(node->arguments->expression); + const QString context = literal->value->asString(); + + QString source; + QString comment; + bool plural = false; + AST::ArgumentList *sourceNode = node->arguments->next; + if (sourceNode) { + literal = AST::cast<AST::StringLiteral *>(sourceNode->expression); + source = literal->value->asString(); + AST::ArgumentList *commentNode = sourceNode->next; + if (commentNode) { + literal = AST::cast<AST::StringLiteral *>(commentNode->expression); + comment = literal->value->asString(); + + AST::ArgumentList *nNode = commentNode->next; + if (nNode) { + AST::NumericLiteral *numLiteral = AST::cast<AST::NumericLiteral *>(nNode->expression); + if (numLiteral) { + plural = true; + } + } + } + } + + TranslatorMessage msg(context, source, + comment, QString(), m_fileName, + node->firstSourceLocation().startLine, QStringList(), + TranslatorMessage::Unfinished, plural); + m_translator->extend(msg); + } + + } + } + } + +private: + Translator *m_translator; + QString m_fileName; + QString m_component; +}; + +QString createErrorString(const QString &filename, const QString &code, Parser &parser) +{ + // print out error + QStringList lines = code.split(QLatin1Char('\n')); + lines.append(QLatin1String("\n")); // sentinel. + QString errorString; + + foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { + + if (m.isWarning()) + continue; + + QString error = filename + QLatin1Char(':') + QString::number(m.loc.startLine) + + QLatin1Char(':') + QString::number(m.loc.startColumn) + QLatin1String(": error: ") + + m.message + QLatin1Char('\n'); + + int line = 0; + if (m.loc.startLine > 0) + line = m.loc.startLine - 1; + + const QString textLine = lines.at(line); + + error += textLine + QLatin1Char('\n'); + + int column = m.loc.startColumn - 1; + if (column < 0) + column = 0; + + column = qMin(column, textLine.length()); + + for (int i = 0; i < column; ++i) { + const QChar ch = textLine.at(i); + if (ch.isSpace()) + error += ch.unicode(); + else + error += QLatin1Char(' '); + } + error += QLatin1String("^\n"); + errorString += error; + } + return errorString; +} + +bool loadQml(Translator &translator, const QString &filename, ConversionData &cd) +{ + cd.m_sourceFileName = filename; + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + cd.appendError(QString::fromLatin1("Cannot open %1: %2") + .arg(filename, file.errorString())); + return false; + } + + const QString code = QTextStream(&file).readAll(); + + Engine driver; + Parser parser(&driver); + + NodePool nodePool(filename, &driver); + driver.setNodePool(&nodePool); + + Lexer lexer(&driver); + lexer.setCode(code, /*line = */ 1); + driver.setLexer(&lexer); + + if (parser.parse()) { + FindTrCalls trCalls; + trCalls(&translator, filename, parser.ast()); + } else { + QString error = createErrorString(filename, code, parser); + cd.appendError(error); + return false; + } + return true; +} + +QT_END_NAMESPACE diff --git a/tools/macdeployqt/shared/shared.cpp b/tools/macdeployqt/shared/shared.cpp index a10e668..3b9ba73 100644 --- a/tools/macdeployqt/shared/shared.cpp +++ b/tools/macdeployqt/shared/shared.cpp @@ -357,7 +357,7 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, copiedFrameworks.append(framework.frameworkName); // Get the qt path from one of the Qt frameworks; - if (deploymenInfo.qtPath == QString() && framework.frameworkName.contains("Qt") + if (deploymenInfo.qtPath.isNull() && framework.frameworkName.contains("Qt") && framework.frameworkDirectory.contains("/lib")) { deploymenInfo.qtPath = framework.frameworkDirectory; @@ -375,7 +375,7 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, // Copy farmework to app bundle. const QString deployedBinaryPath = copyFramework(framework, bundlePath); // Skip the rest if already was deployed. - if (deployedBinaryPath == QString()) + if (deployedBinaryPath.isNull()) continue; runStrip(deployedBinaryPath); diff --git a/tools/porting/src/portingrules.cpp b/tools/porting/src/portingrules.cpp index 4931064..cd29403 100644 --- a/tools/porting/src/portingrules.cpp +++ b/tools/porting/src/portingrules.cpp @@ -189,7 +189,7 @@ void PortingRules::parseXml(QString fileName) QString includeFile = xml[QLatin1String("Rules")][QLatin1String("Include")].text(); - if(includeFile != QString()) { + if(!includeFile.isNull()) { QString resolvedIncludeFile = resolveFileName(fileName, includeFile); if (!resolvedIncludeFile.isEmpty()) parseXml(resolvedIncludeFile); diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp index f27606e..f59918f 100644 --- a/tools/qmlviewer/main.cpp +++ b/tools/qmlviewer/main.cpp @@ -17,6 +17,8 @@ #include <QDir> #include "qfxtestengine.h" #include <QApplication> +#include <QTranslator> +#include <QDebug> void usage() { @@ -38,6 +40,7 @@ void usage() qWarning(" -cache ................................... disk cache remote content"); qWarning(" -recordtest <directory> .................. record an autotest"); qWarning(" -runtest <directory> ..................... run a previously recorded test"); + qWarning(" -translation <translationfile> ........... set the language to run in"); qWarning(" "); qWarning(" Press F1 for interactive help"); exit(1); @@ -83,6 +86,7 @@ int main(int argc, char ** argv) bool cache = false; QFxTestEngine::TestMode testMode = QFxTestEngine::NoTest; QString testDir; + QString translationFile; for (int i = 1; i < newargc; ++i) { QString arg = newargv[i]; @@ -123,6 +127,11 @@ int main(int argc, char ** argv) } else if (arg == QLatin1String("-v") || arg == QLatin1String("-version")) { fprintf(stderr, "Qt Declarative UI Viewer version %s\n", QT_VERSION_STR); return 0; + } else if (arg == "-translation") { + if(i + 1 >= newargc) + usage(); + translationFile = newargv[i + 1]; + ++i; } else if (arg[0] != '-') { fileName = arg; } else if (1 || arg == "-help") { @@ -130,6 +139,12 @@ int main(int argc, char ** argv) } } + QTranslator qmlTranslator; + if (!translationFile.isEmpty()) { + qmlTranslator.load(translationFile); + app.installTranslator(&qmlTranslator); + } + QmlViewer viewer(testMode, testDir, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget); viewer.setCacheEnabled(cache); viewer.setRecordFile(recordfile); @@ -137,7 +152,7 @@ int main(int argc, char ** argv) viewer.setRecordPeriod(period); if (autorecord_to) viewer.setAutoRecord(autorecord_from,autorecord_to); - if (QDir(skin).exists()) + if (!skin.isEmpty() && QDir(skin).exists()) viewer.setSkin(skin); if (devkeys) viewer.setDeviceKeys(true); diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 2eddb6a..97db22e 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -24,6 +24,7 @@ #include <QNetworkDiskCache> #include <QNetworkAccessManager> +#include <QSignalMapper> #include <QmlComponent> #include <QWidget> #include <QApplication> @@ -39,8 +40,91 @@ #include <QFileDialog> #include <QTimer> +class PreviewDeviceSkin : public DeviceSkin +{ + Q_OBJECT +public: + explicit PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent); + + void setPreview(QWidget *formWidget); + void setPreviewAndScale(QWidget *formWidget); + + void setScreenSize(const QSize& size) + { + QMatrix fit; + fit = fit.scale(qreal(size.width())/m_screenSize.width(), + qreal(size.height())/m_screenSize.height()); + setTransform(fit); + QApplication::syncX(); + } + + QSize standardScreenSize() const { return m_screenSize; } + + QMenu* menu; + +private slots: + void slotSkinKeyPressEvent(int code, const QString& text, bool autorep); + void slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep); + void slotPopupMenu(); + +private: + const QSize m_screenSize; +}; + + +PreviewDeviceSkin::PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent) : + DeviceSkin(parameters, parent), + m_screenSize(parameters.screenSize()) +{ + menu = new QMenu(this); + connect(this, SIGNAL(skinKeyPressEvent(int,QString,bool)), + this, SLOT(slotSkinKeyPressEvent(int,QString,bool))); + connect(this, SIGNAL(skinKeyReleaseEvent(int,QString,bool)), + this, SLOT(slotSkinKeyReleaseEvent(int,QString,bool))); + connect(this, SIGNAL(popupMenu()), this, SLOT(slotPopupMenu())); +} + +void PreviewDeviceSkin::setPreview(QWidget *formWidget) +{ + formWidget->setFixedSize(m_screenSize); + formWidget->setParent(this, Qt::SubWindow); + formWidget->setAutoFillBackground(true); + setView(formWidget); +} + +void PreviewDeviceSkin::setPreviewAndScale(QWidget *formWidget) +{ + setScreenSize(formWidget->sizeHint()); + formWidget->setParent(this, Qt::SubWindow); + formWidget->setAutoFillBackground(true); + setView(formWidget); +} + +void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, bool autorep) +{ + if (QWidget *focusWidget = QApplication::focusWidget()) { + QKeyEvent e(QEvent::KeyPress,code,0,text,autorep); + QApplication::sendEvent(focusWidget, &e); + } + +} + +void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep) +{ + if (QWidget *focusWidget = QApplication::focusWidget()) { + QKeyEvent e(QEvent::KeyRelease,code,0,text,autorep); + QApplication::sendEvent(focusWidget, &e); + } +} + +void PreviewDeviceSkin::slotPopupMenu() +{ + menu->exec(QCursor::pos()); +} + + QmlViewer::QmlViewer(QFxTestEngine::TestMode testMode, const QString &testDir, QWidget *parent, Qt::WindowFlags flags) - : QMainWindow(parent, flags), frame_stream(0) + : QMainWindow(parent, flags), frame_stream(0), scaleSkin(true) { testEngine = 0; devicemode = false; @@ -55,6 +139,8 @@ QmlViewer::QmlViewer(QFxTestEngine::TestMode testMode, const QString &testDir, Q createMenu(menuBar(),0); canvas = new QFxView(this); + canvas->setContentResizable(!skin || !scaleSkin); + if(testMode != QFxTestEngine::NoTest) testEngine = new QFxTestEngine(testMode, testDir, canvas, this); @@ -77,14 +163,16 @@ QSize QmlViewer::sizeHint() const void QmlViewer::createMenu(QMenuBar *menu, QMenu *flatmenu) { + QObject *parent = flatmenu ? (QObject*)flatmenu : (QObject*)menu; + QMenu *fileMenu = flatmenu ? flatmenu : menu->addMenu(tr("&File")); - QAction *openAction = new QAction(tr("&Open..."), this); + QAction *openAction = new QAction(tr("&Open..."), parent); openAction->setShortcut(QKeySequence("Ctrl+O")); connect(openAction, SIGNAL(triggered()), this, SLOT(open())); fileMenu->addAction(openAction); - QAction *reloadAction = new QAction(tr("&Reload"), this); + QAction *reloadAction = new QAction(tr("&Reload"), parent); reloadAction->setShortcut(QKeySequence("Ctrl+R")); connect(reloadAction, SIGNAL(triggered()), this, SLOT(reload())); fileMenu->addAction(reloadAction); @@ -93,29 +181,106 @@ void QmlViewer::createMenu(QMenuBar *menu, QMenu *flatmenu) QMenu *recordMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Recording")); - QAction *snapshotAction = new QAction(tr("&Take Snapsot\tF3"), this); + QAction *snapshotAction = new QAction(tr("&Take Snapsot\tF3"), parent); connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot())); recordMenu->addAction(snapshotAction); - recordAction = new QAction(tr("Start Recording &Video\tF2"), this); + recordAction = new QAction(tr("Start Recording &Video\tF2"), parent); connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection())); recordMenu->addAction(recordAction); if (flatmenu) flatmenu->addSeparator(); + QMenu *skinMenu = flatmenu ? flatmenu->addMenu(tr("&Skin")) : menu->addMenu(tr("&Skin")); + + QActionGroup *skinActions; + QAction *skinAction; + + skinActions = new QActionGroup(parent); + skinAction = new QAction(tr("Scale skin"), parent); + skinAction->setCheckable(true); + skinAction->setChecked(scaleSkin); + skinActions->addAction(skinAction); + skinMenu->addAction(skinAction); + connect(skinAction, SIGNAL(triggered()), this, SLOT(setScaleSkin())); + skinAction = new QAction(tr("Scale view"), parent); + skinAction->setCheckable(true); + skinAction->setChecked(!scaleSkin); + skinActions->addAction(skinAction); + skinMenu->addAction(skinAction); + connect(skinAction, SIGNAL(triggered()), this, SLOT(setScaleView())); + skinMenu->addSeparator(); + + skinActions = new QActionGroup(parent); + QSignalMapper *mapper = new QSignalMapper(parent); + skinAction = new QAction(tr("None"), parent); + skinAction->setCheckable(true); + if (currentSkin.isEmpty()) + skinAction->setChecked(true); + skinActions->addAction(skinAction); + skinMenu->addAction(skinAction); + mapper->setMapping(skinAction, ""); + connect(skinAction, SIGNAL(triggered()), mapper, SLOT(map())); + skinMenu->addSeparator(); + + QDir dir(":/skins/","*.skin"); + const QFileInfoList l = dir.entryInfoList(); + for (QFileInfoList::const_iterator it = l.begin(); it != l.end(); ++it) { + QString name = (*it).baseName(); // should perhaps be in file + QString file = (*it).filePath(); + skinAction = new QAction(name, parent); + skinActions->addAction(skinAction); + skinMenu->addAction(skinAction); + skinAction->setCheckable(true); + if (file == currentSkin) + skinAction->setChecked(true); + mapper->setMapping(skinAction, file); + connect(skinAction, SIGNAL(triggered()), mapper, SLOT(map())); + } + //connect(skinActions, SIGNAL(triggered(QAction*)), mapper, SLOT(map(QObject*))); // "incompatible" + connect(mapper, SIGNAL(mapped(QString)), this, SLOT(setSkin(QString))); + + if (flatmenu) flatmenu->addSeparator(); + QMenu *helpMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Help")); - QAction *aboutAction = new QAction(tr("&About Qt..."), this); + QAction *aboutAction = new QAction(tr("&About Qt..."), parent); connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); helpMenu->addAction(aboutAction); - QAction *quitAction = new QAction(tr("&Quit"), this); + QAction *quitAction = new QAction(tr("&Quit"), parent); quitAction->setShortcut(QKeySequence("Ctrl+Q")); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); fileMenu->addSeparator(); fileMenu->addAction(quitAction); +} +void QmlViewer::setScaleSkin() +{ + if (scaleSkin) + return; + scaleSkin = true; + canvas->setContentResizable(!skin || !scaleSkin); + if (skin) { + canvas->setFixedSize(canvas->sizeHint()); + skin->setScreenSize(canvas->sizeHint()); + } } +void QmlViewer::setScaleView() +{ + if (!scaleSkin) + return; + scaleSkin = false; + if (skin) { + canvas->setContentResizable(!skin || !scaleSkin); + canvas->setMinimumSize(QSize(0,0)); + canvas->setMaximumSize(QSize(16777215,16777215)); + canvas->resize(skin->standardScreenSize()); + skin->setScreenSize(skin->standardScreenSize()); + } +} + + void QmlViewer::takeSnapShot() { static int snapshotcount = 1; @@ -210,100 +375,76 @@ void QmlViewer::openQml(const QString& fileName) canvas->execute(); qWarning() << "Wall startup time:" << t.elapsed(); - resize(sizeHint()); + if (!skin) { + canvas->resize(canvas->sizeHint()); + resize(sizeHint()); + } else { + if (scaleSkin) + canvas->resize(canvas->sizeHint()); + else { + canvas->setFixedSize(skin->standardScreenSize()); + canvas->resize(skin->standardScreenSize()); + } + } #ifdef QTOPIA show(); #endif } -class PreviewDeviceSkin : public DeviceSkin -{ - Q_OBJECT -public: - explicit PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent); - - void setPreview(QWidget *formWidget); - void setScreenSize(const QSize& size) - { - QMatrix fit; - fit = fit.scale(qreal(size.width())/m_screenSize.width(), - qreal(size.height())/m_screenSize.height()); - setTransform(fit); - } - - QMenu* menu; -private slots: - void slotSkinKeyPressEvent(int code, const QString& text, bool autorep); - void slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep); - void slotPopupMenu(); - -private: - const QSize m_screenSize; -}; - - -PreviewDeviceSkin::PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent) : - DeviceSkin(parameters, parent), - m_screenSize(parameters.screenSize()) -{ - menu = new QMenu(this); - connect(this, SIGNAL(skinKeyPressEvent(int,QString,bool)), - this, SLOT(slotSkinKeyPressEvent(int,QString,bool))); - connect(this, SIGNAL(skinKeyReleaseEvent(int,QString,bool)), - this, SLOT(slotSkinKeyReleaseEvent(int,QString,bool))); - connect(this, SIGNAL(popupMenu()), this, SLOT(slotPopupMenu())); -} - -void PreviewDeviceSkin::setPreview(QWidget *formWidget) +void QmlViewer::setSkin(const QString& skinDirectory) { - formWidget->setFixedSize(m_screenSize); - formWidget->setParent(this, Qt::SubWindow); - formWidget->setAutoFillBackground(true); - setView(formWidget); -} + // XXX QWidget::setMask does not handle changes well, and we may + // XXX have been signalled from an item in a menu we're replacing, + // XXX hence some rather convoluted resetting here... -void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, bool autorep) -{ - if (QWidget *focusWidget = QApplication::focusWidget()) { - QKeyEvent e(QEvent::KeyPress,code,0,text,autorep); - QApplication::sendEvent(focusWidget, &e); - } + if (currentSkin == skinDirectory) + return; -} + currentSkin = skinDirectory; -void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep) -{ - if (QWidget *focusWidget = QApplication::focusWidget()) { - QKeyEvent e(QEvent::KeyRelease,code,0,text,autorep); - QApplication::sendEvent(focusWidget, &e); + QString err; + if (skin) { + skin->hide(); + skin->deleteLater(); } -} -void PreviewDeviceSkin::slotPopupMenu() -{ - menu->exec(QCursor::pos()); -} + canvas->setContentResizable(!skin || !scaleSkin); -void QmlViewer::setSkin(const QString& skinDirectory) -{ DeviceSkinParameters parameters; - QString err; - if (parameters.read(skinDirectory,DeviceSkinParameters::ReadAll,&err)) { - delete skin; + if (!skinDirectory.isEmpty() && parameters.read(skinDirectory,DeviceSkinParameters::ReadAll,&err)) { + layout()->setEnabled(false); + setMenuBar(0); if (!err.isEmpty()) qWarning() << err; - delete menuBar(); skin = new PreviewDeviceSkin(parameters,this); - skin->setScreenSize(canvas->sizeHint()); - canvas->setParent(skin, Qt::SubWindow); - canvas->setAutoFillBackground(true); - skin->setView(canvas); + canvas->resize(canvas->sizeHint()); + if (scaleSkin) + skin->setPreviewAndScale(canvas); + else + skin->setPreview(canvas); createMenu(0,skin->menu); - - canvas->show(); + skin->show(); + } else { + skin = 0; + clearMask(); + menuBar()->clear(); + canvas->setParent(this, Qt::SubWindow); + createMenu(menuBar(),0); + setMinimumSize(QSize(0,0)); + setMaximumSize(QSize(16777215,16777215)); + canvas->setMinimumSize(QSize(0,0)); + canvas->setMaximumSize(QSize(16777215,16777215)); + QRect g = geometry(); + g.setSize(sizeHint()); + setParent(0,windowFlags()); // recreate + canvas->move(0,menuBar()->sizeHint().height()+1); + setGeometry(g); + layout()->setEnabled(true); + show(); } + canvas->show(); } void QmlViewer::setAutoRecord(int from, int to) @@ -335,7 +476,7 @@ void QmlViewer::setRecordPeriod(int ms) void QmlViewer::sceneResized(QSize size) { if (size.width() > 0 && size.height() > 0) { - if (skin) + if (skin && scaleSkin) skin->setScreenSize(size); } } @@ -395,7 +536,6 @@ void QmlViewer::setRecording(bool on) connect(proc, SIGNAL(finished(int)), this, SLOT(ffmpegFinished(int))); frame_stream = proc; -qDebug() << canvas->width() << canvas->height(); QStringList args; args << "-sameq"; // ie. high args << "-y"; diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h index 0748de4..09b2b5b 100644 --- a/tools/qmlviewer/qmlviewer.h +++ b/tools/qmlviewer/qmlviewer.h @@ -40,7 +40,6 @@ public: void setRecording(bool on); bool isRecording() const { return recordTimer.isActive(); } void setAutoRecord(int from, int to); - void setSkin(const QString& skinDirectory); void setDeviceKeys(bool); void setCacheEnabled(bool); @@ -55,6 +54,7 @@ public slots: void toggleRecording(); void toggleRecordingWithSelection(); void ffmpegFinished(int code); + void setSkin(const QString& skinDirectory); protected: virtual void keyPressEvent(QKeyEvent *); @@ -62,6 +62,10 @@ protected: void createMenu(QMenuBar *menu, QMenu *flatmenu); +private slots: + void setScaleSkin(); + void setScaleView(); + private: QString currentFileName; PreviewDeviceSkin *skin; @@ -80,6 +84,8 @@ private: int record_autotime; bool devicemode; QAction *recordAction; + QString currentSkin; + bool scaleSkin; QFxTestEngine *testEngine; }; diff --git a/tools/qtestlib/chart/chart.pro b/tools/qtestlib/chart/chart.pro index 6f6e6d5..7328e5d 100644 --- a/tools/qtestlib/chart/chart.pro +++ b/tools/qtestlib/chart/chart.pro @@ -4,7 +4,7 @@ SOURCES += main.cpp RESOURCES = $$PWD/chart.qrc QT += sql xml -CONFIG += console release +CONFIG += console CONFIG -= app_bundle diff --git a/tools/qvfb/PDAPhone.skin/pda_up.png b/tools/qvfb/PDAPhone.skin/pda_up.png Binary files differdeleted file mode 100644 index 541e3c4..0000000 --- a/tools/qvfb/PDAPhone.skin/pda_up.png +++ /dev/null diff --git a/tools/qvfb/pda.qrc b/tools/qvfb/pda.qrc deleted file mode 100644 index b14e7b3..0000000 --- a/tools/qvfb/pda.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource prefix="/skins"> - <file>pda.skin</file> -</qresource> -</RCC> diff --git a/tools/qvfb/pda.skin b/tools/qvfb/pda.skin deleted file mode 100644 index 037f750..0000000 --- a/tools/qvfb/pda.skin +++ /dev/null @@ -1,14 +0,0 @@ -pda_up.png pda_down.png -57 81 -240 320 -11 -"Power" 0x0100000a 277 36 302 57 -"F1" 0x01000030 52 439 81 470 -"F2" 0x01000031 101 422 130 451 -"F3" 0x01000032 232 423 260 452 -"F4" 0x01000033 279 445 309 473 -"Left" 0x01000012 155 438 176 472 -"Down" 0x01000015 169 471 203 486 -"Right" 0x01000014 193 448 215 472 -"Up" 0x01000013 166 427 199 451 -"Enter" 0x01000005 177 448 193 468 diff --git a/tools/qvfb/pda_down.png b/tools/qvfb/pda_down.png Binary files differdeleted file mode 100644 index 0ea157d..0000000 --- a/tools/qvfb/pda_down.png +++ /dev/null diff --git a/tools/qvfb/qvfb.pro b/tools/qvfb/qvfb.pro index 85c4d96..247337a 100644 --- a/tools/qvfb/qvfb.pro +++ b/tools/qvfb/qvfb.pro @@ -60,15 +60,4 @@ unix:x11 { LIBS += -lXtst } -RESOURCES += qvfb.qrc \ - ClamshellPhone.qrc \ - PDAPhone.qrc \ - SmartPhone2.qrc \ - SmartPhone.qrc \ - SmartPhoneWithButtons.qrc \ - TouchscreenPhone.qrc \ - Trolltech-Keypad.qrc \ - Trolltech-Touchscreen.qrc \ - PortableMedia.qrc \ - S60-QVGA-Candybar.qrc \ - S60-nHD-Touchscreen.qrc +RESOURCES += qvfb.qrc diff --git a/tools/shared/deviceskin/deviceskin.pri b/tools/shared/deviceskin/deviceskin.pri index e4c9ef7..2552c92 100644 --- a/tools/shared/deviceskin/deviceskin.pri +++ b/tools/shared/deviceskin/deviceskin.pri @@ -1,3 +1,15 @@ INCLUDEPATH += $$PWD HEADERS += $$PWD/deviceskin.h SOURCES += $$PWD/deviceskin.cpp +RESOURCES += $$PWD/skins/ClamshellPhone.qrc \ + $$PWD/skins/PDAPhone.qrc \ + $$PWD/skins/SmartPhone2.qrc \ + $$PWD/skins/SmartPhone.qrc \ + $$PWD/skins/SmartPhoneWithButtons.qrc \ + $$PWD/skins/TouchscreenPhone.qrc \ + $$PWD/skins/Trolltech-Keypad.qrc \ + $$PWD/skins/Trolltech-Touchscreen.qrc \ + $$PWD/skins/PortableMedia.qrc \ + $$PWD/skins/S60-QVGA-Candybar.qrc \ + $$PWD/skins/S60-nHD-Touchscreen.qrc + diff --git a/tools/qvfb/ClamshellPhone.qrc b/tools/shared/deviceskin/skins/ClamshellPhone.qrc index 39cd422..39cd422 100644 --- a/tools/qvfb/ClamshellPhone.qrc +++ b/tools/shared/deviceskin/skins/ClamshellPhone.qrc diff --git a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone.skin b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone.skin index cb24a8e..cb24a8e 100644 --- a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone.skin +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone.skin diff --git a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5-closed.png b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-closed.png Binary files differindex 88ba3a1..88ba3a1 100644 --- a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5-closed.png +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-closed.png diff --git a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png Binary files differindex 971cdef..971cdef 100644 --- a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png diff --git a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5.png b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5.png Binary files differindex f3550ee..f3550ee 100644 --- a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5.png +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5.png diff --git a/tools/qvfb/S60-QVGA-Candybar.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/ClamshellPhone.skin/defaultbuttons.conf index e349dbc..e349dbc 100644 --- a/tools/qvfb/S60-QVGA-Candybar.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/DualScreenPhone.skin/DualScreen-pressed.png b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen-pressed.png Binary files differindex d62ef4a..d62ef4a 100644 --- a/tools/qvfb/DualScreenPhone.skin/DualScreen-pressed.png +++ b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen-pressed.png diff --git a/tools/qvfb/DualScreenPhone.skin/DualScreen.png b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen.png Binary files differindex cb3d1a7..cb3d1a7 100644 --- a/tools/qvfb/DualScreenPhone.skin/DualScreen.png +++ b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen.png diff --git a/tools/qvfb/DualScreenPhone.skin/DualScreenPhone.skin b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreenPhone.skin index a82ef23..a82ef23 100644 --- a/tools/qvfb/DualScreenPhone.skin/DualScreenPhone.skin +++ b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreenPhone.skin diff --git a/tools/qvfb/SmartPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/DualScreenPhone.skin/defaultbuttons.conf index 1103350..1103350 100644 --- a/tools/qvfb/SmartPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/DualScreenPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/PDAPhone.qrc b/tools/shared/deviceskin/skins/PDAPhone.qrc index 1a1c35a..1a1c35a 100644 --- a/tools/qvfb/PDAPhone.qrc +++ b/tools/shared/deviceskin/skins/PDAPhone.qrc diff --git a/tools/qvfb/PDAPhone.skin/PDAPhone.skin b/tools/shared/deviceskin/skins/PDAPhone.skin/PDAPhone.skin index d6a1966..d6a1966 100644 --- a/tools/qvfb/PDAPhone.skin/PDAPhone.skin +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/PDAPhone.skin diff --git a/tools/qvfb/PDAPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/PDAPhone.skin/defaultbuttons.conf index e3ae813..e3ae813 100644 --- a/tools/qvfb/PDAPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/PDAPhone.skin/finger.png b/tools/shared/deviceskin/skins/PDAPhone.skin/finger.png Binary files differindex 24cf0cb..24cf0cb 100644 --- a/tools/qvfb/PDAPhone.skin/finger.png +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/finger.png diff --git a/tools/qvfb/PDAPhone.skin/pda_down.png b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_down.png Binary files differindex f65c059..f65c059 100644 --- a/tools/qvfb/PDAPhone.skin/pda_down.png +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_down.png diff --git a/tools/qvfb/pda_up.png b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_up.png Binary files differindex 541e3c4..541e3c4 100644 --- a/tools/qvfb/pda_up.png +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_up.png diff --git a/tools/qvfb/PortableMedia.qrc b/tools/shared/deviceskin/skins/PortableMedia.qrc index a902f1a..a902f1a 100644 --- a/tools/qvfb/PortableMedia.qrc +++ b/tools/shared/deviceskin/skins/PortableMedia.qrc diff --git a/tools/qvfb/PortableMedia.skin/PortableMedia.skin b/tools/shared/deviceskin/skins/PortableMedia.skin/PortableMedia.skin index b76e5cf..b76e5cf 100644 --- a/tools/qvfb/PortableMedia.skin/PortableMedia.skin +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/PortableMedia.skin diff --git a/tools/qvfb/PortableMedia.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/PortableMedia.skin/defaultbuttons.conf index 514e881..514e881 100644 --- a/tools/qvfb/PortableMedia.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/defaultbuttons.conf diff --git a/tools/qvfb/PortableMedia.skin/portablemedia-pressed.png b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia-pressed.png Binary files differindex 730e762..730e762 100644 --- a/tools/qvfb/PortableMedia.skin/portablemedia-pressed.png +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia-pressed.png diff --git a/tools/qvfb/PortableMedia.skin/portablemedia.png b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia.png Binary files differindex e44cbe1..e44cbe1 100644 --- a/tools/qvfb/PortableMedia.skin/portablemedia.png +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia.png diff --git a/tools/qvfb/PortableMedia.skin/portablemedia.xcf b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia.xcf Binary files differindex 127e07c..127e07c 100644 --- a/tools/qvfb/PortableMedia.skin/portablemedia.xcf +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia.xcf diff --git a/tools/qvfb/S60-QVGA-Candybar.qrc b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.qrc index 8138484..8138484 100644 --- a/tools/qvfb/S60-QVGA-Candybar.qrc +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.qrc diff --git a/tools/qvfb/S60-QVGA-Candybar.skin/S60-QVGA-Candybar-down.png b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar-down.png Binary files differindex 89d40cb..89d40cb 100644 --- a/tools/qvfb/S60-QVGA-Candybar.skin/S60-QVGA-Candybar-down.png +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar-down.png diff --git a/tools/qvfb/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png Binary files differindex 0d0e598..0d0e598 100644 --- a/tools/qvfb/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png diff --git a/tools/qvfb/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin index 4f8fe5d..4f8fe5d 100644 --- a/tools/qvfb/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin diff --git a/tools/qvfb/ClamshellPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/defaultbuttons.conf index e349dbc..e349dbc 100644 --- a/tools/qvfb/ClamshellPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/defaultbuttons.conf diff --git a/tools/qvfb/S60-nHD-Touchscreen.qrc b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.qrc index daf0cc3..daf0cc3 100644 --- a/tools/qvfb/S60-nHD-Touchscreen.qrc +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.qrc diff --git a/tools/qvfb/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen-down.png b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen-down.png Binary files differindex 7253e38..7253e38 100644 --- a/tools/qvfb/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen-down.png +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen-down.png diff --git a/tools/qvfb/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.png b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.png Binary files differindex 675563e..675563e 100644 --- a/tools/qvfb/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.png +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.png diff --git a/tools/qvfb/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.skin b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.skin index ed25d0e..ed25d0e 100644 --- a/tools/qvfb/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.skin +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.skin diff --git a/tools/qvfb/Trolltech-Touchscreen.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/defaultbuttons.conf index 6665125..6665125 100644 --- a/tools/qvfb/Trolltech-Touchscreen.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/defaultbuttons.conf diff --git a/tools/qvfb/SmartPhone.qrc b/tools/shared/deviceskin/skins/SmartPhone.qrc index 8bb5325..8bb5325 100644 --- a/tools/qvfb/SmartPhone.qrc +++ b/tools/shared/deviceskin/skins/SmartPhone.qrc diff --git a/tools/qvfb/SmartPhone.skin/SmartPhone-pressed.png b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone-pressed.png Binary files differindex d0db2ed..d0db2ed 100644 --- a/tools/qvfb/SmartPhone.skin/SmartPhone-pressed.png +++ b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone-pressed.png diff --git a/tools/qvfb/SmartPhone.skin/SmartPhone.png b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.png Binary files differindex e6ac5a0..e6ac5a0 100644 --- a/tools/qvfb/SmartPhone.skin/SmartPhone.png +++ b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.png diff --git a/tools/qvfb/SmartPhone.skin/SmartPhone.skin b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.skin index 2f44c5a..2f44c5a 100644 --- a/tools/qvfb/SmartPhone.skin/SmartPhone.skin +++ b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.skin diff --git a/tools/qvfb/DualScreenPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/SmartPhone.skin/defaultbuttons.conf index 1103350..1103350 100644 --- a/tools/qvfb/DualScreenPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/SmartPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/SmartPhone2.qrc b/tools/shared/deviceskin/skins/SmartPhone2.qrc index 751e985..751e985 100644 --- a/tools/qvfb/SmartPhone2.qrc +++ b/tools/shared/deviceskin/skins/SmartPhone2.qrc diff --git a/tools/qvfb/SmartPhone2.skin/SmartPhone2-pressed.png b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2-pressed.png Binary files differindex d4eb5b0..d4eb5b0 100644 --- a/tools/qvfb/SmartPhone2.skin/SmartPhone2-pressed.png +++ b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2-pressed.png diff --git a/tools/qvfb/SmartPhone2.skin/SmartPhone2.png b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.png Binary files differindex 48ccc1c..48ccc1c 100644 --- a/tools/qvfb/SmartPhone2.skin/SmartPhone2.png +++ b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.png diff --git a/tools/qvfb/SmartPhone2.skin/SmartPhone2.skin b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.skin index 16884bf..16884bf 100644 --- a/tools/qvfb/SmartPhone2.skin/SmartPhone2.skin +++ b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.skin diff --git a/tools/qvfb/SmartPhone2.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/SmartPhone2.skin/defaultbuttons.conf index b083203..b083203 100644 --- a/tools/qvfb/SmartPhone2.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/SmartPhone2.skin/defaultbuttons.conf diff --git a/tools/qvfb/SmartPhoneWithButtons.qrc b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.qrc index f3393ba..f3393ba 100644 --- a/tools/qvfb/SmartPhoneWithButtons.qrc +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.qrc diff --git a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png Binary files differindex 456a068..456a068 100644 --- a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png diff --git a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png Binary files differindex 5ffbd6e..5ffbd6e 100644 --- a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png diff --git a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin index 9afa67f..9afa67f 100644 --- a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin diff --git a/tools/qvfb/SmartPhoneWithButtons.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/defaultbuttons.conf index ebd6926..ebd6926 100644 --- a/tools/qvfb/SmartPhoneWithButtons.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/defaultbuttons.conf diff --git a/tools/qvfb/TouchscreenPhone.qrc b/tools/shared/deviceskin/skins/TouchscreenPhone.qrc index 023144d..023144d 100644 --- a/tools/qvfb/TouchscreenPhone.qrc +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.qrc diff --git a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone-pressed.png b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone-pressed.png Binary files differindex 01acb86..01acb86 100644 --- a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone-pressed.png +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone-pressed.png diff --git a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone.png b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.png Binary files differindex e90de0d..e90de0d 100644 --- a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone.png +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.png diff --git a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone.skin b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.skin index 24316a1..24316a1 100644 --- a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone.skin +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.skin diff --git a/tools/qvfb/TouchscreenPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/defaultbuttons.conf index a13dfdc..a13dfdc 100644 --- a/tools/qvfb/TouchscreenPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/Trolltech-Keypad.qrc b/tools/shared/deviceskin/skins/Trolltech-Keypad.qrc index 4775068..4775068 100644 --- a/tools/qvfb/Trolltech-Keypad.qrc +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.qrc diff --git a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png Binary files differindex 8dd5719..8dd5719 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png diff --git a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad-down.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-down.png Binary files differindex 5e1e6be..5e1e6be 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad-down.png +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-down.png diff --git a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.png Binary files differindex fb3d549..fb3d549 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad.png +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.png diff --git a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad.skin b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.skin index 4d90321..4d90321 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad.skin +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.skin diff --git a/tools/qvfb/Trolltech-Keypad.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/defaultbuttons.conf index 6a78e67..6a78e67 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/defaultbuttons.conf diff --git a/tools/qvfb/Trolltech-Touchscreen.qrc b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.qrc index 40fafeb..40fafeb 100644 --- a/tools/qvfb/Trolltech-Touchscreen.qrc +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.qrc diff --git a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png Binary files differindex c1a422f..c1a422f 100644 --- a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png diff --git a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png Binary files differindex 544a425..544a425 100644 --- a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png diff --git a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin index 5de882e..5de882e 100644 --- a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin diff --git a/tools/qvfb/S60-nHD-Touchscreen.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/defaultbuttons.conf index 6665125..6665125 100644 --- a/tools/qvfb/S60-nHD-Touchscreen.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/defaultbuttons.conf diff --git a/tools/tools.pro b/tools/tools.pro index 2ff0214..7493aec 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -22,7 +22,7 @@ mac { SUBDIRS += macdeployqt } -SUBDIRS += kmap2qmap +embedded:SUBDIRS += kmap2qmap contains(QT_CONFIG, declarative):SUBDIRS += qmlviewer contains(QT_CONFIG, dbus):SUBDIRS += qdbus |