summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/src/animation.qdoc19
-rw-r--r--doc/src/diagrams/animations-architecture.svg351
-rw-r--r--doc/src/examples-overview.qdoc8
-rw-r--r--doc/src/examples.qdoc5
-rw-r--r--doc/src/examples/eventtransitions.qdoc86
-rw-r--r--doc/src/examples/factorial.qdoc102
-rw-r--r--doc/src/examples/pingpong.qdoc107
-rw-r--r--doc/src/examples/tankgame.qdoc117
-rw-r--r--doc/src/examples/trafficlight.qdoc79
-rw-r--r--doc/src/examples/twowaybutton.qdoc (renamed from examples/statemachine/helloworld/main.cpp)66
-rw-r--r--doc/src/groups.qdoc4
-rw-r--r--doc/src/images/animations-architecture.pngbin0 -> 27619 bytes
-rw-r--r--doc/src/images/factorial-example.pngbin0 -> 4032 bytes
-rw-r--r--doc/src/images/pingpong-example.pngbin0 -> 7843 bytes
-rw-r--r--doc/src/images/statemachine-button-history.pngbin91677 -> 8493 bytes
-rw-r--r--doc/src/images/statemachine-button-nested.pngbin73774 -> 7051 bytes
-rw-r--r--doc/src/images/statemachine-button.pngbin32767 -> 4233 bytes
-rw-r--r--doc/src/images/statemachine-customevents.pngbin0 -> 2544 bytes
-rw-r--r--doc/src/images/statemachine-customevents2.pngbin0 -> 6713 bytes
-rw-r--r--doc/src/images/statemachine-finished.pngbin37907 -> 5518 bytes
-rw-r--r--doc/src/images/statemachine-nonparallel.pngbin68482 -> 5350 bytes
-rw-r--r--doc/src/images/statemachine-parallel.pngbin99587 -> 8631 bytes
-rw-r--r--doc/src/images/tankgame-example.pngbin0 -> 16089 bytes
-rw-r--r--doc/src/images/trafficlight-example1.pngbin0 -> 3694 bytes
-rw-r--r--doc/src/images/trafficlight-example2.pngbin0 -> 7257 bytes
-rw-r--r--doc/src/statemachine.qdoc430
-rw-r--r--examples/animation/animation.pro3
-rw-r--r--examples/animation/moveblocks/main.cpp2
-rw-r--r--examples/animation/stickman/lifecycle.cpp4
-rw-r--r--examples/animation/sub-attaq/boat_p.h6
-rw-r--r--examples/animation/sub-attaq/states.cpp6
-rw-r--r--examples/animation/sub-attaq/states.h6
-rw-r--r--examples/statemachine/clockticking/clockticking.pro10
-rw-r--r--examples/statemachine/clockticking/main.cpp123
-rw-r--r--examples/statemachine/composition/composition.pro7
-rw-r--r--examples/statemachine/composition/main.cpp104
-rw-r--r--examples/statemachine/errorstateplugins/errorstateplugins.pro11
-rw-r--r--examples/statemachine/eventtransitions/main.cpp16
-rw-r--r--examples/statemachine/factorial/main.cpp64
-rw-r--r--examples/statemachine/helloworld/helloworld.pro10
-rw-r--r--examples/statemachine/pauseandresume/main.cpp102
-rw-r--r--examples/statemachine/pauseandresume/pauseandresume.pro7
-rw-r--r--examples/statemachine/pingpong/main.cpp18
-rw-r--r--examples/statemachine/statemachine.pro8
-rw-r--r--examples/statemachine/tankgame/gameitem.cpp (renamed from examples/statemachine/errorstate/gameitem.cpp)0
-rw-r--r--examples/statemachine/tankgame/gameitem.h (renamed from examples/statemachine/errorstate/gameitem.h)0
-rw-r--r--examples/statemachine/tankgame/gameovertransition.cpp39
-rw-r--r--examples/statemachine/tankgame/gameovertransition.h22
-rw-r--r--examples/statemachine/tankgame/main.cpp (renamed from examples/statemachine/errorstate/main.cpp)0
-rw-r--r--examples/statemachine/tankgame/mainwindow.cpp (renamed from examples/statemachine/errorstate/mainwindow.cpp)138
-rw-r--r--examples/statemachine/tankgame/mainwindow.h (renamed from examples/statemachine/errorstate/mainwindow.h)3
-rw-r--r--examples/statemachine/tankgame/plugin.h (renamed from examples/statemachine/errorstate/plugin.h)0
-rw-r--r--examples/statemachine/tankgame/rocketitem.cpp (renamed from examples/statemachine/errorstate/rocketitem.cpp)0
-rw-r--r--examples/statemachine/tankgame/rocketitem.h (renamed from examples/statemachine/errorstate/rocketitem.h)0
-rw-r--r--examples/statemachine/tankgame/tankgame.pro (renamed from examples/statemachine/errorstate/errorstate.pro)6
-rw-r--r--examples/statemachine/tankgame/tankitem.cpp (renamed from examples/statemachine/errorstate/tankitem.cpp)1
-rw-r--r--examples/statemachine/tankgame/tankitem.h (renamed from examples/statemachine/errorstate/tankitem.h)3
-rw-r--r--examples/statemachine/tankgameplugins/random_ai/random_ai.pro (renamed from examples/statemachine/errorstateplugins/random_ai/random_ai.pro)6
-rw-r--r--examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp (renamed from examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp)0
-rw-r--r--examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.h (renamed from examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h)4
-rw-r--r--examples/statemachine/tankgameplugins/seek_ai/seek_ai.cpp (renamed from examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp)0
-rw-r--r--examples/statemachine/tankgameplugins/seek_ai/seek_ai.h (renamed from examples/statemachine/errorstateplugins/seek_ai/seek_ai.h)16
-rw-r--r--examples/statemachine/tankgameplugins/seek_ai/seek_ai.pro (renamed from examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro)6
-rw-r--r--examples/statemachine/tankgameplugins/spin_ai/spin_ai.cpp (renamed from examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp)0
-rw-r--r--examples/statemachine/tankgameplugins/spin_ai/spin_ai.h (renamed from examples/statemachine/errorstateplugins/spin_ai/spin_ai.h)11
-rw-r--r--examples/statemachine/tankgameplugins/spin_ai/spin_ai.pro (renamed from examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro)6
-rw-r--r--examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.cpp (renamed from examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp)0
-rw-r--r--examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.h (renamed from examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h)11
-rw-r--r--examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.pro (renamed from examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro)6
-rw-r--r--examples/statemachine/tankgameplugins/tankgameplugins.pro11
-rw-r--r--examples/statemachine/trafficlight/main.cpp47
-rw-r--r--examples/statemachine/twowaybutton/main.cpp22
-rw-r--r--src/corelib/animation/qanimationgroup.cpp54
-rw-r--r--src/corelib/animation/qparallelanimationgroup.cpp23
-rw-r--r--src/corelib/animation/qpauseanimation.cpp16
-rw-r--r--src/corelib/animation/qpropertyanimation.cpp4
-rw-r--r--src/corelib/animation/qpropertyanimation_p.h1
-rw-r--r--src/corelib/animation/qsequentialanimationgroup.cpp33
-rw-r--r--src/corelib/animation/qvariantanimation.cpp99
-rw-r--r--src/corelib/animation/qvariantanimation_p.h4
-rw-r--r--src/corelib/statemachine/qabstractstate.cpp27
-rw-r--r--src/corelib/statemachine/qabstractstate.h3
-rw-r--r--src/corelib/statemachine/qabstractstate_p.h8
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp88
-rw-r--r--src/corelib/statemachine/qabstracttransition.h5
-rw-r--r--src/corelib/statemachine/qabstracttransition_p.h13
-rw-r--r--src/corelib/statemachine/qeventtransition.cpp6
-rw-r--r--src/corelib/statemachine/qeventtransition.h8
-rw-r--r--src/corelib/statemachine/qfinalstate.h4
-rw-r--r--src/corelib/statemachine/qhistorystate.h4
-rw-r--r--src/corelib/statemachine/qsignaleventgenerator_p.h9
-rw-r--r--src/corelib/statemachine/qsignaltransition.cpp6
-rw-r--r--src/corelib/statemachine/qsignaltransition.h6
-rw-r--r--src/corelib/statemachine/qstate.cpp44
-rw-r--r--src/corelib/statemachine/qstate.h4
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp288
-rw-r--r--src/corelib/statemachine/qstatemachine.h9
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h17
-rw-r--r--src/declarative/fx/qfximage.cpp36
-rw-r--r--src/declarative/fx/qfxrect.cpp52
-rw-r--r--src/declarative/qml/qmlengine.cpp19
-rw-r--r--src/declarative/qml/qmlengine_p.h2
-rw-r--r--src/declarative/qml/qmlexpression.h2
-rw-r--r--src/declarative/qml/qmlvme.cpp2
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp2
-rw-r--r--src/gui/statemachine/qbasickeyeventtransition.cpp4
-rw-r--r--src/gui/statemachine/qbasickeyeventtransition_p.h2
-rw-r--r--src/gui/statemachine/qbasicmouseeventtransition.cpp4
-rw-r--r--src/gui/statemachine/qbasicmouseeventtransition_p.h2
-rw-r--r--src/gui/statemachine/qguistatemachine.cpp5
-rw-r--r--src/gui/statemachine/qkeyeventtransition.cpp2
-rw-r--r--src/gui/statemachine/qkeyeventtransition.h2
-rw-r--r--src/gui/statemachine/qmouseeventtransition.cpp2
-rw-r--r--src/gui/statemachine/qmouseeventtransition.h2
-rw-r--r--src/opengl/qglpixmapfilter.cpp2
-rw-r--r--tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp69
-rw-r--r--tests/auto/qstate/tst_qstate.cpp2
-rw-r--r--tests/auto/qstatemachine/tst_qstatemachine.cpp219
-rw-r--r--tools/linguist/lupdate/lupdate.h1
-rw-r--r--tools/linguist/lupdate/lupdate.pro4
-rw-r--r--tools/linguist/lupdate/main.cpp2
-rw-r--r--tools/linguist/lupdate/qml.cpp205
-rw-r--r--tools/qmlviewer/main.cpp15
123 files changed, 2622 insertions, 1059 deletions
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/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/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/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/examples/statemachine/helloworld/main.cpp b/doc/src/examples/twowaybutton.qdoc
index fbe34b5..87de2e8 100644
--- a/examples/statemachine/helloworld/main.cpp
+++ b/doc/src/examples/twowaybutton.qdoc
@@ -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 documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
@@ -39,40 +39,44 @@
**
****************************************************************************/
-#include <QtCore>
-#ifdef QT_STATEMACHINE_SOLUTION
-#include <qstatemachine.h>
-#include <qstate.h>
-#include <qfinalstate.h>
-#endif
+/*!
+ \example statemachine/twowaybutton
+ \title Two-way Button Example
-class S0 : public QState
-{
-public:
- S0(QState *parent = 0)
- : QState(parent) {}
+ 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.
- virtual void onEntry(QEvent *)
- {
- fprintf(stdout, "Hello world!\n");
- }
-};
+ \snippet examples/statemachine/twowaybutton/main.cpp 0
-int main(int argc, char **argv)
-{
- QCoreApplication app(argc, argv);
+ The application's main() function begins by constructing the application
+ object, a button and a state machine.
- QStateMachine machine;
- QState *s0 = new S0();
- QFinalState *s1 = new QFinalState();
- s0->addTransition(s1);
+ \snippet examples/statemachine/twowaybutton/main.cpp 1
- machine.addState(s0);
- machine.addState(s1);
- machine.setInitialState(s0);
+ 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.
- QObject::connect(&machine, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit()));
- machine.start();
+ \snippet examples/statemachine/twowaybutton/main.cpp 2
- return app.exec();
-}
+ 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
new file mode 100644
index 0000000..9b581af
--- /dev/null
+++ b/doc/src/images/animations-architecture.png
Binary files differ
diff --git a/doc/src/images/factorial-example.png b/doc/src/images/factorial-example.png
new file mode 100644
index 0000000..8fb1cc6
--- /dev/null
+++ b/doc/src/images/factorial-example.png
Binary files differ
diff --git a/doc/src/images/pingpong-example.png b/doc/src/images/pingpong-example.png
new file mode 100644
index 0000000..af707e4
--- /dev/null
+++ b/doc/src/images/pingpong-example.png
Binary files differ
diff --git a/doc/src/images/statemachine-button-history.png b/doc/src/images/statemachine-button-history.png
index cd66478..7f51cae 100644
--- a/doc/src/images/statemachine-button-history.png
+++ b/doc/src/images/statemachine-button-history.png
Binary files differ
diff --git a/doc/src/images/statemachine-button-nested.png b/doc/src/images/statemachine-button-nested.png
index 60360d1..762ac14 100644
--- a/doc/src/images/statemachine-button-nested.png
+++ b/doc/src/images/statemachine-button-nested.png
Binary files differ
diff --git a/doc/src/images/statemachine-button.png b/doc/src/images/statemachine-button.png
index 75d9e53..10102bd 100644
--- a/doc/src/images/statemachine-button.png
+++ b/doc/src/images/statemachine-button.png
Binary files differ
diff --git a/doc/src/images/statemachine-customevents.png b/doc/src/images/statemachine-customevents.png
new file mode 100644
index 0000000..62a4222
--- /dev/null
+++ b/doc/src/images/statemachine-customevents.png
Binary files differ
diff --git a/doc/src/images/statemachine-customevents2.png b/doc/src/images/statemachine-customevents2.png
new file mode 100644
index 0000000..57b37ef
--- /dev/null
+++ b/doc/src/images/statemachine-customevents2.png
Binary files differ
diff --git a/doc/src/images/statemachine-finished.png b/doc/src/images/statemachine-finished.png
index 802621e..0ac081d 100644
--- a/doc/src/images/statemachine-finished.png
+++ b/doc/src/images/statemachine-finished.png
Binary files differ
diff --git a/doc/src/images/statemachine-nonparallel.png b/doc/src/images/statemachine-nonparallel.png
index 1fe60d8..f9850a7 100644
--- a/doc/src/images/statemachine-nonparallel.png
+++ b/doc/src/images/statemachine-nonparallel.png
Binary files differ
diff --git a/doc/src/images/statemachine-parallel.png b/doc/src/images/statemachine-parallel.png
index 1868792..a65c297 100644
--- a/doc/src/images/statemachine-parallel.png
+++ b/doc/src/images/statemachine-parallel.png
Binary files differ
diff --git a/doc/src/images/tankgame-example.png b/doc/src/images/tankgame-example.png
new file mode 100644
index 0000000..9e17e30
--- /dev/null
+++ b/doc/src/images/tankgame-example.png
Binary files differ
diff --git a/doc/src/images/trafficlight-example1.png b/doc/src/images/trafficlight-example1.png
new file mode 100644
index 0000000..ec8c7ff
--- /dev/null
+++ b/doc/src/images/trafficlight-example1.png
Binary files differ
diff --git a/doc/src/images/trafficlight-example2.png b/doc/src/images/trafficlight-example2.png
new file mode 100644
index 0000000..a12e4db
--- /dev/null
+++ b/doc/src/images/trafficlight-example2.png
Binary files differ
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/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/clockticking/main.cpp b/examples/statemachine/clockticking/main.cpp
deleted file mode 100644
index ea8e692..0000000
--- a/examples/statemachine/clockticking/main.cpp
+++ /dev/null
@@ -1,123 +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 <QtCore>
-#include <stdio.h>
-#ifdef QT_STATEMACHINE_SOLUTION
-#include <qstatemachine.h>
-#include <qstate.h>
-#include <qabstracttransition.h>
-#endif
-
-class ClockEvent : public QEvent
-{
-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
-{
-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
-{
-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");
- }
-};
-
-int main(int argc, char **argv)
-{
- QCoreApplication app(argc, argv);
-
- QStateMachine machine;
- QState *group = new QState(QState::ParallelStates);
- group->setObjectName("group");
-
- ClockState *clock = new ClockState(group);
- clock->setObjectName("clock");
- clock->addTransition(new ClockTransition());
-
- QState *listener = new QState(group);
- listener->setObjectName("listener");
- listener->addTransition(new ClockListener());
-
- machine.addState(group);
- machine.setInitialState(group);
- machine.start();
-
- return app.exec();
-}
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/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/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/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/qfxrect.cpp b/src/declarative/fx/qfxrect.cpp
index dafd8a2..d75a45a 100644
--- a/src/declarative/fx/qfxrect.cpp
+++ b/src/declarative/fx/qfxrect.cpp
@@ -486,45 +486,57 @@ void QFxRect::drawRect(QPainter &p)
}
//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();
+ int h = height();
+ int xOffset = offset;
+ int xSide = xOffset * 2;
+ if (xSide > w) {
+ xOffset = w/2;
+ xSide = xOffset * 2;
+ }
+ int yOffset = offset;
+ int ySide = yOffset * 2;
+ if (ySide > h) {
+ yOffset = h/2;
+ ySide = yOffset * 2;
+ }
// Upper left
- p.drawImage(QRect(0, 0, offset, offset), d->_rectImage, QRect(0, 0, offset, offset));
+ p.drawImage(QRect(0, 0, 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));
+ p.drawImage(QRect(xOffset, 0, w - xSide, yOffset), d->_rectImage,
+ QRect(xOffset, 0, d->_rectImage.width() - xSide, yOffset));
// Upper right
- if (d->_rectImage.width() - offset) {
- p.drawImage(QPoint(width()-offset, 0), d->_rectImage,
- QRect(d->_rectImage.width()-offset, 0, offset, offset));
+ if (d->_rectImage.width() - xOffset) {
+ p.drawImage(QPoint(w-xOffset, 0), 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));
+ p.drawImage(QRect(0, yOffset, xOffset, height() - ySide), d->_rectImage,
+ QRect(0, yOffset, xOffset, d->_rectImage.height() - ySide));
// 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));
+ p.drawImage(QRect(xOffset, yOffset, w - xSide, height() - ySide), d->_rectImage,
+ QRect(xOffset, yOffset, 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));
+ p.drawImage(QRect(w-xOffset, yOffset, xOffset, height() - ySide), d->_rectImage,
+ QRect(d->_rectImage.width()-xOffset, yOffset, xOffset, d->_rectImage.height() - ySide));
// Lower left
- p.drawImage(QPoint(0, height() - offset), d->_rectImage, QRect(0, d->_rectImage.height() - offset, offset, offset));
+ p.drawImage(QPoint(0, height() - yOffset), 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));
+ p.drawImage(QRect(xOffset, height() - yOffset, w - xSide, yOffset), d->_rectImage,
+ QRect(xOffset, d->_rectImage.height() - yOffset, d->_rectImage.width() - xSide, 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));
+ if (d->_rectImage.width() - xOffset)
+ p.drawImage(QPoint(w-xOffset, height() - yOffset), d->_rectImage,
+ QRect(d->_rectImage.width()-xOffset, d->_rectImage.height() - yOffset, xOffset, yOffset));
}
}
#endif
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index b2d3a9c..0209c1d 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);
@@ -781,17 +782,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 +997,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();
@@ -1151,6 +1152,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_p.h b/src/declarative/qml/qmlengine_p.h
index 7578fdf..7cafb59 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -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/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index 53ed05a..f4ce891 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -526,6 +526,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;
@@ -551,6 +552,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/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 3078792..e02b3eb 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -2840,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/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/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/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/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/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..8597672 100644
--- a/tools/linguist/lupdate/main.cpp
+++ b/tools/linguist/lupdate/main.cpp
@@ -518,6 +518,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..8c3f1c5
--- /dev/null
+++ b/tools/linguist/lupdate/qml.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** 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")) {
+ 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;
+ AST::ArgumentList *commentNode = node->arguments->next;
+ if (commentNode) {
+ literal = AST::cast<AST::StringLiteral *>(commentNode->expression);
+ comment = literal->value->asString();
+ }
+
+ bool plural = false;
+ AST::ArgumentList *nNode = commentNode->next;
+ if (nNode) {
+ AST::NumericLiteral *literal3 = AST::cast<AST::NumericLiteral *>(nNode->expression);
+ if (literal3) {
+ plural = true;
+ }
+ }
+
+ TranslatorMessage msg(m_component, source,
+ comment, QString(), m_fileName,
+ node->firstSourceLocation().startLine, QStringList(),
+ TranslatorMessage::Unfinished, plural);
+ m_translator->extend(msg);
+ }
+ }
+ //### support qsTranslate, QT_TR_NOOP, and QT_TRANSLATE_NOOP
+ }
+ }
+
+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/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp
index da13c1a..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);