diff options
206 files changed, 4669 insertions, 1496 deletions
diff --git a/doc/config/qtquick-dita.qdocconf b/doc/config/qtquick-dita.qdocconf index e259a2fa74..ee471c1df1 100644 --- a/doc/config/qtquick-dita.qdocconf +++ b/doc/config/qtquick-dita.qdocconf @@ -7,9 +7,21 @@ project = Qt Quick # Images should be placed in <rootdir>/dic/images and examples in # <rootdir>/examples. # Paths are relative to the location of this file. -exampledirs += ../src/examples -headerdirs += ../src -sourcedirs += ../src +exampledirs += ../src/examples \ + ../.. \ + ../../examples + +headerdirs += ../src \ + ../../src + +imagedirs += ../src/images \ + +sourcedirs += ../src \ + ../../src + +excludedirs += ../src/qtquick1 \ + ../../src/qtquick1 + diff --git a/doc/config/qtquick.qdocconf b/doc/config/qtquick.qdocconf index 3f4645aeaa..0870bde323 100644 --- a/doc/config/qtquick.qdocconf +++ b/doc/config/qtquick.qdocconf @@ -37,10 +37,7 @@ qhp.projects = qtquick qhp.qtquick.file = qtquick.qhp # Namespace for the output file. This namespace is used to distinguish between -# different documentation files in Creator/Assistant. Normal format for MP -# projects should be: com.nokia.mp.<projectname>.version with version being -# a number containing a major, minor and revision element. E.g. version 1.0 -# becomes 100. +# different documentation files in Creator/Assistant. Qt Quick 2 release. qhp.qtquick.namespace = qtquick.200 # Title for the package, will be the main title for the package in diff --git a/doc/src/images/gridview-layout-lefttoright-ltr-btt.png b/doc/src/images/gridview-layout-lefttoright-ltr-btt.png Binary files differnew file mode 100644 index 0000000000..4439f8370a --- /dev/null +++ b/doc/src/images/gridview-layout-lefttoright-ltr-btt.png diff --git a/doc/src/images/gridview-layout-lefttoright-ltr-ttb.png b/doc/src/images/gridview-layout-lefttoright-ltr-ttb.png Binary files differnew file mode 100644 index 0000000000..af745b7d1e --- /dev/null +++ b/doc/src/images/gridview-layout-lefttoright-ltr-ttb.png diff --git a/doc/src/images/gridview-layout-lefttoright-rtl-btt.png b/doc/src/images/gridview-layout-lefttoright-rtl-btt.png Binary files differnew file mode 100644 index 0000000000..bc7e568972 --- /dev/null +++ b/doc/src/images/gridview-layout-lefttoright-rtl-btt.png diff --git a/doc/src/images/gridview-layout-lefttoright-rtl-ttb.png b/doc/src/images/gridview-layout-lefttoright-rtl-ttb.png Binary files differnew file mode 100644 index 0000000000..3ebf74fae5 --- /dev/null +++ b/doc/src/images/gridview-layout-lefttoright-rtl-ttb.png diff --git a/doc/src/images/gridview-layout-toptobottom-ltr-btt.png b/doc/src/images/gridview-layout-toptobottom-ltr-btt.png Binary files differnew file mode 100644 index 0000000000..b60ab4b5e7 --- /dev/null +++ b/doc/src/images/gridview-layout-toptobottom-ltr-btt.png diff --git a/doc/src/images/gridview-layout-toptobottom-ltr-ttb.png b/doc/src/images/gridview-layout-toptobottom-ltr-ttb.png Binary files differnew file mode 100644 index 0000000000..9078cbde6f --- /dev/null +++ b/doc/src/images/gridview-layout-toptobottom-ltr-ttb.png diff --git a/doc/src/images/gridview-layout-toptobottom-rtl-btt.png b/doc/src/images/gridview-layout-toptobottom-rtl-btt.png Binary files differnew file mode 100644 index 0000000000..0d0f095598 --- /dev/null +++ b/doc/src/images/gridview-layout-toptobottom-rtl-btt.png diff --git a/doc/src/images/gridview-layout-toptobottom-rtl-ttb.png b/doc/src/images/gridview-layout-toptobottom-rtl-ttb.png Binary files differnew file mode 100644 index 0000000000..c1c353a4da --- /dev/null +++ b/doc/src/images/gridview-layout-toptobottom-rtl-ttb.png diff --git a/doc/src/images/listview-layout-bottomtotop.png b/doc/src/images/listview-layout-bottomtotop.png Binary files differnew file mode 100644 index 0000000000..980f81d07f --- /dev/null +++ b/doc/src/images/listview-layout-bottomtotop.png diff --git a/doc/src/images/listview-layout-lefttoright.png b/doc/src/images/listview-layout-lefttoright.png Binary files differnew file mode 100644 index 0000000000..2ee0e4c4ff --- /dev/null +++ b/doc/src/images/listview-layout-lefttoright.png diff --git a/doc/src/images/listview-layout-righttoleft.png b/doc/src/images/listview-layout-righttoleft.png Binary files differnew file mode 100644 index 0000000000..2c54a2a7b1 --- /dev/null +++ b/doc/src/images/listview-layout-righttoleft.png diff --git a/doc/src/images/listview-layout-toptobottom.png b/doc/src/images/listview-layout-toptobottom.png Binary files differnew file mode 100644 index 0000000000..2054a5743b --- /dev/null +++ b/doc/src/images/listview-layout-toptobottom.png diff --git a/doc/src/external-resources.qdoc b/doc/src/qml/external-resources.qdoc index b4aecbad75..386992f439 100644 --- a/doc/src/external-resources.qdoc +++ b/doc/src/qml/external-resources.qdoc @@ -28,5 +28,8 @@ /*! \externalpage http://www.ecma-international.org/publications/standards/Ecma-262.htm \title ECMA-262 + + \externalpage http://www.w3schools.com/jsref/default.asp + \title W3Schools JavaScript Reference */ diff --git a/doc/src/qml/hostenvironment.qdoc b/doc/src/qml/hostenvironment.qdoc new file mode 100644 index 0000000000..b0d9118944 --- /dev/null +++ b/doc/src/qml/hostenvironment.qdoc @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qmlhostenvironment.html +\title QML JavaScript Host Environment + +QML provides a JavaScript host environment tailored to writing QML applications. +This environment is different from the host environment provided by a browser +or a server-side JavaScript environment such as Node.js. For example, QML does +not provide a \c window object or \c{DOM API} as commonly found in a browser environment. + +\section1 Common Base + +Like a browser or server-side JavaScript environment, the QML runtime implements the +\l{ECMA-262}{ECMAScript Language Specification} standard. This provides access to +all of the built-in types and functions defined by the standard, such as Object, Array, and Math. +The QML runtime implements the 5th edition of the standard, which is the same edition commonly +implemented by browsers. + +The standard ECMAScript built-ins are not explicitly documented in the QML documentation. For more +information on their use, please refer to the ECMA-262 5th edition standard or one of the many online +JavaScript reference and tutorial sites, such as the \l{W3Schools JavaScript Reference} (JavaScript Objects +Reference section). Many sites focus on JavaScript in the browser, so in some cases you may need to double +check the specification to determine whether a given function or object is part of standard ECMAScript or +specific to the browser environment. In the case of the W3Schools link above, the \c{JavaScript Objects +Reference} section generally covers the standard, while the \c{Browser Objects Reference} and \c{HTML DOM +Objects Reference} sections are browser specific (and thus not applicable to QML). + +\section1 Host Objects and Functions + +The QML JavaScript host environment implements the following host objects and functions: + +\list +\li The \l{QmlGlobalQtObject}{Qt object}: This object is specific to QML, and provides helper methods + and properties specific to the QML environment. +\li qsTr(), qsTranslate(), qsTrId(), QT_TR_NOOP(), QT_TRANSLATE_NOOP(), and QT_TRID_NOOP() functions: + These functions are specific to QML, and provide \l{Translation}{translation capabilities} to the QML environment. +\li gc() function: This function is specific to QML, and provides a way to manually trigger garbage collection. +\li print() function: This function is specific to QML, and provides a simple way to output information to the console. +\li The \l{Console API}{console object}: This object implements a subset of the \l{http://getfirebug.com/wiki/index.php/Console_API}{FireBug Console API}. +\li \l{XMLHttpRequest}, DOMException: These objects implement a subset of the \l{http://www.w3.org/TR/XMLHttpRequest/}{W3C XMLHttpRequest specification}. +\endlist + +See \l{QML Global Object} for more details on these host objects and functions. + +\section1 Native Object Modification + +QML makes the following modifications to native objects: + +\list +\li An arg() function is added to the String prototype. +\li Locale-aware coversion functions are added to the \l{Date} and \l{Number} prototypes. +\endlist + +\section1 Restrictions + +QML implements the following restrictions for JavaScript code: + +\list +\li JavaScript code cannot modify the global object. +\li Global code is run in a reduced scope. +\li The value of \c this is undefined in QML in the majority of contexts. +\endlist + +See \l {QML JavaScript Restrictions} for more details on these restrictions. + +*/ diff --git a/doc/src/qml/qmlengine.qdoc b/doc/src/qml/qmlengine.qdoc index b0754fe3ab..ad77d43cb5 100644 --- a/doc/src/qml/qmlengine.qdoc +++ b/doc/src/qml/qmlengine.qdoc @@ -467,9 +467,13 @@ specified in QML files, plugins, or applications. \section1 JavaScript Runtime - The runtime implements the \l{ECMA-262}{ECMAScript Language Specification} standard. - The reserved words, conditionals, variables, and object behaviors follow - after the standard. + The runtime implements the \l{ECMA-262}{ECMAScript Language Specification} standard, + 5th edition. The reserved words, conditionals, variables, and object behaviors + follow after the standard. + + The \l{QML JavaScript Host Environment} article has information about the + JavaScript host environment provided by QML, which is different than the + browser host environment many are familiar with. The \l{JavaScript Code} article has information about placing JavaScript code within QML code. diff --git a/doc/src/qml/qmli18n.qdoc b/doc/src/qml/qmli18n.qdoc index d15beafb38..b65c001e8e 100644 --- a/doc/src/qml/qmli18n.qdoc +++ b/doc/src/qml/qmli18n.qdoc @@ -33,8 +33,8 @@ \section1 Translation -Strings in QML can be marked for translation using the qsTr(), qsTranslate(), -QT_TR_NOOP(), and QT_TRANSLATE_NOOP() functions. +Strings in QML can be marked for translation using the qsTr(), qsTranslate(), qsTrId(), +QT_TR_NOOP(), QT_TRANSLATE_NOOP(), and QT_TRID_NOOP() functions. For example: \qml diff --git a/doc/src/qml/qtdeclarative.qdoc b/doc/src/qml/qtqml.qdoc index 5ad637ab50..7bd797e8d0 100644 --- a/doc/src/qml/qtdeclarative.qdoc +++ b/doc/src/qml/qtqml.qdoc @@ -27,10 +27,10 @@ /*! \module QtQml - \title Qt Qml Module + \title Qt QML Module \ingroup modules - \brief The Qt Qml module provides a declarative framework + \brief The Qt QML module provides a declarative framework for building highly dynamic, custom user interfaces. To include the definitions of the module's classes, use the @@ -47,8 +47,8 @@ QT += qml \endcode - For more information on the Qt Qml module (including the visual - elements which are implemented on top of the Qt Qml module) see the + For more information on the Qt QML module (including the visual + elements which are implemented on top of the Qt QML module) see the \l{Qt Quick} documentation. */ @@ -68,7 +68,7 @@ Declares additional properties of the given \a Type as described by the specified \a Flags. - + Current the only supported type info is \c QML_HAS_ATTACHED_PROPERTIES which declares that the \a Type supports \l {Attached Properties}. @@ -113,7 +113,7 @@ qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider"); \endcode - Once this is registered, the type can be used in QML by importing the + Once this is registered, the type can be used in QML by importing the specified module name and version number: \qml diff --git a/doc/src/qtdeclarative.qdoc b/doc/src/qtquick2/qtdeclarative.qdoc index d9b9234c90..d9b9234c90 100644 --- a/doc/src/qtdeclarative.qdoc +++ b/doc/src/qtquick2/qtdeclarative.qdoc diff --git a/doc/src/quick/qtquick.qdoc b/doc/src/qtquick2/qtquick.qdoc index c38ef3c801..c38ef3c801 100644 --- a/doc/src/quick/qtquick.qdoc +++ b/doc/src/qtquick2/qtquick.qdoc diff --git a/doc/src/whatsnew.qdoc b/doc/src/qtquick2/whatsnew.qdoc index 1997a42a6b..1997a42a6b 100644 --- a/doc/src/whatsnew.qdoc +++ b/doc/src/qtquick2/whatsnew.qdoc diff --git a/examples/demos/stockchart/contents/Button.qml b/examples/demos/stockchart/contents/Button.qml new file mode 100644 index 0000000000..ab9ce350db --- /dev/null +++ b/examples/demos/stockchart/contents/Button.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + id: container + + signal clicked + + property string text + width: buttonText.width + 28 + height: buttonText.height + 14 + + BorderImage { + id: buttonImage + source: "images/toolbutton.sci" + width: container.width - 10 + height: container.height + } + BorderImage { + id: pressed + opacity: 0 + source: "images/toolbutton.sci" + width: container.width - 10 + height: container.height + } + MouseArea { + id: mouseRegion + anchors.fill: buttonImage + onClicked: { container.clicked(); } + } + Text { + id: buttonText + color: "white" + anchors.centerIn: buttonImage + font.bold: true + font.pointSize: 15 + text: container.text + style: Text.Raised + styleColor: "black" + } + states: [ + State { + name: "Pressed" + when: mouseRegion.pressed == true + PropertyChanges { target: pressed; opacity: 1 } + } + ] +} diff --git a/examples/demos/stockchart/contents/ScrollBar.qml b/examples/demos/stockchart/contents/ScrollBar.qml new file mode 100644 index 0000000000..98b8efee4a --- /dev/null +++ b/examples/demos/stockchart/contents/ScrollBar.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + id: scrollBar + // The properties that define the scrollbar's state. + // position and pageSize are in the range 0.0 - 1.0. They are relative to the + // height of the page, i.e. a pageSize of 0.5 means that you can see 50% + // of the height of the view. + // orientation can be either 'Vertical' or 'Horizontal' + property real position + property real pageSize + property string orientation : "Vertical" + property alias bgColor: background.color + property alias fgColor: thumb.color + + // A light, semi-transparent background + Rectangle { + id: background + radius: orientation == 'Vertical' ? (width/2 - 1) : (height/2 - 1) + color: "white"; opacity: 0.3 + anchors.fill: parent + } + // Size the bar to the required size, depending upon the orientation. + Rectangle { + id: thumb + opacity: 0.7 + color: "black" + radius: orientation == 'Vertical' ? (width/2 - 1) : (height/2 - 1) + x: orientation == 'Vertical' ? 1 : (scrollBar.position * (scrollBar.width-2) + 1) + y: orientation == 'Vertical' ? (scrollBar.position * (scrollBar.height-2) + 1) : 1 + width: orientation == 'Vertical' ? (parent.width-2) : (scrollBar.pageSize * (scrollBar.width-2)) + height: orientation == 'Vertical' ? (scrollBar.pageSize * (scrollBar.height-2)) : (parent.height-2) + } +} diff --git a/examples/demos/stockchart/contents/Stocks.qml b/examples/demos/stockchart/contents/Stocks.qml new file mode 100644 index 0000000000..043bca132e --- /dev/null +++ b/examples/demos/stockchart/contents/Stocks.qml @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +ListModel { + id:stocks + //Data from : http://en.wikipedia.org/wiki/NASDAQ-100 + + ListElement {name:"Activision Blizzard"; stockId:"ATVI"} + ListElement {name:"Adobe Systems Incorporated"; stockId:"ADBE"} + ListElement {name:"Akamai Technologies, Inc"; stockId:"AKAM"} + ListElement {name:"Alexion Pharmaceuticals"; stockId:"ALXN"} + ListElement {name:"Altera Corporation"; stockId:"ALTR"} + ListElement {name:"Amazon.com, Inc."; stockId:"AMZN"} + ListElement {name:"Amgen Inc."; stockId:"AMGN"} + ListElement {name:"Apollo Group, Inc."; stockId:"APOL"} + ListElement {name:"Apple Inc."; stockId:"AAPL"} + ListElement {name:"Applied Materials, Inc."; stockId:"AMAT"} + ListElement {name:"Autodesk, Inc."; stockId:"ADSK"} + ListElement {name:"Automatic Data Processing, Inc."; stockId:"ADP"} + ListElement {name:"Baidu.com, Inc."; stockId:"BIDU"} + ListElement {name:"Bed Bath & Beyond Inc."; stockId:"BBBY"} + ListElement {name:"Biogen Idec, Inc"; stockId:"BIIB"} + ListElement {name:"BMC Software, Inc."; stockId:"BMC"} + ListElement {name:"Broadcom Corporation"; stockId:"BRCM"} + ListElement {name:"C. H. Robinson Worldwide, Inc."; stockId:"CHRW"} + ListElement {name:"CA, Inc."; stockId:"CA"} + ListElement {name:"Celgene Corporation"; stockId:"CELG"} + ListElement {name:"Cephalon, Inc."; stockId:"CEPH"} + ListElement {name:"Cerner Corporation"; stockId:"CERN"} + ListElement {name:"Check Point Software Technologies Ltd."; stockId:"CHKP"} + ListElement {name:"Cisco Systems, Inc."; stockId:"CSCO"} + ListElement {name:"Citrix Systems, Inc."; stockId:"CTXS"} + ListElement {name:"Cognizant Technology Solutions Corporation"; stockId:"CTSH"} + ListElement {name:"Comcast Corporation"; stockId:"CMCSA"} + ListElement {name:"Costco Wholesale Corporation"; stockId:"COST"} + ListElement {name:"Ctrip.com International, Ltd."; stockId:"CTRP"} + ListElement {name:"Dell Inc."; stockId:"DELL"} + ListElement {name:"DENTSPLY International Inc."; stockId:"XRAY"} + ListElement {name:"DirecTV"; stockId:"DTV"} + ListElement {name:"Dollar Tree, Inc."; stockId:"DLTR"} + ListElement {name:"eBay Inc."; stockId:"EBAY"} + ListElement {name:"Electronic Arts Inc."; stockId:"ERTS"} + ListElement {name:"Expedia, Inc."; stockId:"EXPE"} + ListElement {name:"Expeditors International of Washington, Inc."; stockId:"EXPD"} + ListElement {name:"Express Scripts, Inc."; stockId:"ESRX"} + ListElement {name:"F5 Networks, Inc."; stockId:"FFIV"} + ListElement {name:"Fastenal Company"; stockId:"FAST"} + ListElement {name:"First Solar, Inc."; stockId:"FSLR"} + ListElement {name:"Fiserv, Inc."; stockId:"FISV"} + ListElement {name:"Flextronics International Ltd."; stockId:"FLEX"} + ListElement {name:"FLIR Systems, Inc."; stockId:"FLIR"} + ListElement {name:"Garmin Ltd."; stockId:"GRMN"} + ListElement {name:"Gilead Sciences, Inc."; stockId:"GILD"} + ListElement {name:"Google Inc."; stockId:"GOOG"} + ListElement {name:"Green Mountain Coffee Roasters, Inc."; stockId:"GMCR"} + ListElement {name:"Henry Schein, Inc."; stockId:"HSIC"} + ListElement {name:"Illumina, Inc."; stockId:"ILMN"} + ListElement {name:"Infosys Technologies"; stockId:"INFY"} + ListElement {name:"Intel Corporation"; stockId:"INTC"} + ListElement {name:"Intuit, Inc."; stockId:"INTU"} + ListElement {name:"Intuitive Surgical Inc."; stockId:"ISRG"} + ListElement {name:"Joy Global Inc."; stockId:"JOYG"} + ListElement {name:"KLA Tencor Corporation"; stockId:"KLAC"} + ListElement {name:"Lam Research Corporation"; stockId:"LRCX"} + ListElement {name:"Liberty Media Corporation, Interactive Series A"; stockId:"LINTA"} + ListElement {name:"Life Technologies Corporation"; stockId:"LIFE"} + ListElement {name:"Linear Technology Corporation"; stockId:"LLTC"} + ListElement {name:"Marvell Technology Group, Ltd."; stockId:"MRVL"} + ListElement {name:"Mattel, Inc."; stockId:"MAT"} + ListElement {name:"Maxim Integrated Products"; stockId:"MXIM"} + ListElement {name:"Microchip Technology Incorporated"; stockId:"MCHP"} + ListElement {name:"Micron Technology, Inc."; stockId:"MU"} + ListElement {name:"Microsoft Corporation"; stockId:"MSFT"} + ListElement {name:"Mylan, Inc."; stockId:"MYL"} + ListElement {name:"NetApp, Inc."; stockId:"NTAP"} + ListElement {name:"Netflix, Inc."; stockId:"NFLX"} + ListElement {name:"News Corporation, Ltd."; stockId:"NWSA"} + ListElement {name:"NII Holdings, Inc."; stockId:"NIHD"} + ListElement {name:"NVIDIA Corporation"; stockId:"NVDA"} + ListElement {name:"O'Reilly Automotive, Inc."; stockId:"ORLY"} + ListElement {name:"Oracle Corporation"; stockId:"ORCL"} + ListElement {name:"PACCAR Inc."; stockId:"PCAR"} + ListElement {name:"Paychex, Inc."; stockId:"PAYX"} + ListElement {name:"Priceline.com, Incorporated"; stockId:"PCLN"} + ListElement {name:"Qiagen N.V."; stockId:"QGEN"} + ListElement {name:"QUALCOMM Incorporated"; stockId:"QCOM"} + ListElement {name:"Research in Motion Limited"; stockId:"RIMM"} + ListElement {name:"Ross Stores Inc."; stockId:"ROST"} + ListElement {name:"SanDisk Corporation"; stockId:"SNDK"} + ListElement {name:"Seagate Technology Holdings"; stockId:"STX"} + ListElement {name:"Sears Holdings Corporation"; stockId:"SHLD"} + ListElement {name:"Sigma-Aldrich Corporation"; stockId:"SIAL"} + ListElement {name:"Staples Inc."; stockId:"SPLS"} + ListElement {name:"Starbucks Corporation"; stockId:"SBUX"} + ListElement {name:"Stericycle, Inc"; stockId:"SRCL"} + ListElement {name:"Symantec Corporation"; stockId:"SYMC"} + ListElement {name:"Teva Pharmaceutical Industries Ltd."; stockId:"TEVA"} + ListElement {name:"Urban Outfitters, Inc."; stockId:"URBN"} + ListElement {name:"VeriSign, Inc."; stockId:"VRSN"} + ListElement {name:"Vertex Pharmaceuticals"; stockId:"VRTX"} + ListElement {name:"Virgin Media, Inc."; stockId:"VMED"} + ListElement {name:"Vodafone Group, plc."; stockId:"VOD"} + ListElement {name:"Warner Chilcott, Ltd."; stockId:"WCRX"} + ListElement {name:"Whole Foods Market, Inc."; stockId:"WFM"} + ListElement {name:"Wynn Resorts Ltd."; stockId:"WYNN"} + ListElement {name:"Xilinx, Inc."; stockId:"XLNX"} + ListElement {name:"Yahoo! Inc."; stockId:"YHOO"} +} diff --git a/examples/demos/stockchart/contents/TitleBar.qml b/examples/demos/stockchart/contents/TitleBar.qml new file mode 100644 index 0000000000..28edda2ae7 --- /dev/null +++ b/examples/demos/stockchart/contents/TitleBar.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + id: titleBar + property string title: "" + + BorderImage { source: "images/titlebar.sci"; width: parent.width; height: parent.height + 14; y: -7 } + + Image { + id: quitButton + anchors.left: parent.left//; anchors.leftMargin: 0 + anchors.verticalCenter: parent.verticalCenter + source: "images/quit.png" + MouseArea { + anchors.fill: parent + onClicked: Qt.quit() + } + } + + Text { + id: categoryText + anchors { + left: quitButton.right; right: parent.right; //leftMargin: 10; rightMargin: 10 + verticalCenter: parent.verticalCenter + } + elide: Text.ElideLeft + text: title + font.bold: true; font.pointSize: 20; color: "White"; style: Text.Raised; styleColor: "Black" + } +} diff --git a/examples/demos/stockchart/contents/ToolBar.qml b/examples/demos/stockchart/contents/ToolBar.qml new file mode 100644 index 0000000000..7ae7391ddf --- /dev/null +++ b/examples/demos/stockchart/contents/ToolBar.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + id: toolbar + + property variant labels + signal buttonClicked(int index) + + BorderImage { + source: "images/titlebar.sci" + width: parent.width + height: parent.height + 14 + y: -7 + } + + Row { + y: 3 + anchors.horizontalCenter: parent.horizontalCenter + Repeater { + model: toolbar.labels + delegate: + Button { + text: modelData + onClicked: toolbar.buttonClicked(model.index) + } + } + } + +} diff --git a/examples/demos/stockchart/contents/images/quit.png b/examples/demos/stockchart/contents/images/quit.png Binary files differnew file mode 100755 index 0000000000..5bda1b6e0d --- /dev/null +++ b/examples/demos/stockchart/contents/images/quit.png diff --git a/examples/demos/stockchart/contents/images/stripes.png b/examples/demos/stockchart/contents/images/stripes.png Binary files differnew file mode 100755 index 0000000000..9f36727ea4 --- /dev/null +++ b/examples/demos/stockchart/contents/images/stripes.png diff --git a/examples/demos/stockchart/stock.qml b/examples/demos/stockchart/stock.qml index 1c95fde2ce..819625c808 100644 --- a/examples/demos/stockchart/stock.qml +++ b/examples/demos/stockchart/stock.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.0 import com.nokia.StockChartExample 1.0 -import "../contents" +import "./contents" Rectangle { id:container diff --git a/modules/qt_quickparticles.pri b/modules/qt_quickparticles.pri new file mode 100644 index 0000000000..ae1064aca8 --- /dev/null +++ b/modules/qt_quickparticles.pri @@ -0,0 +1,17 @@ +QT.quickparticles.VERSION = 5.0.0 +QT.quickparticles.MAJOR_VERSION = 5 +QT.quickparticles.MINOR_VERSION = 0 +QT.quickparticles.PATCH_VERSION = 0 + +QT.quickparticles.name = QtQuickParticles +QT.quickparticles.bins = $$QT_MODULE_BIN_BASE +QT.quickparticles.includes = $$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/QtQuickParticles +QT.quickparticles.private_includes = $$QT_MODULE_INCLUDE_BASE/QtQuickParticles/$$QT.quickparticles.VERSION +QT.quickparticles.sources = $$QT_MODULE_BASE/src/particles +QT.quickparticles.libs = $$QT_MODULE_LIB_BASE +QT.quickparticles.plugins = $$QT_MODULE_PLUGIN_BASE +QT.quickparticles.imports = $$QT_MODULE_IMPORT_BASE +QT.quickparticles.depends = qml quick +QT.quickparticles.DEFINES = QT_QUICKPARTICLES_LIB + +QT_CONFIG += quickparticles diff --git a/src/imports/particles/particles.pro b/src/imports/particles/particles.pro index dc3198d124..a9d0ece448 100644 --- a/src/imports/particles/particles.pro +++ b/src/imports/particles/particles.pro @@ -5,7 +5,7 @@ include(../qimportbase.pri) SOURCES += \ plugin.cpp -QT += quick-private qml-private +QT += quick-private quickparticles-private qml-private OTHER_FILES += \ qmldir diff --git a/src/quick/particles/particleresources/noise.png b/src/particles/particleresources/noise.png Binary files differindex 3c723e1a5a..3c723e1a5a 100644 --- a/src/quick/particles/particleresources/noise.png +++ b/src/particles/particleresources/noise.png diff --git a/src/quick/particles/particles.pri b/src/particles/particles.pri index 3a40a3b911..3e083ab291 100644 --- a/src/quick/particles/particles.pri +++ b/src/particles/particles.pri @@ -28,7 +28,8 @@ HEADERS += \ $$PWD/qquickv8particledata_p.h \ $$PWD/qquickrectangleextruder_p.h \ $$PWD/qquickparticlegroup_p.h \ - $$PWD/qquickgroupgoal_p.h + $$PWD/qquickgroupgoal_p.h \ + $$PWD/qtquickparticlesglobal_p.h SOURCES += \ $$PWD/qquickangledirection.cpp \ diff --git a/src/particles/particles.pro b/src/particles/particles.pro new file mode 100644 index 0000000000..3aff6bbcc0 --- /dev/null +++ b/src/particles/particles.pro @@ -0,0 +1,40 @@ +load(qt_module) + +TARGET = QtQuickParticles + +CONFIG += module +CONFIG += dll warn_on +MODULE_PRI = ../../modules/qt_quickparticles.pri + +QT = core-private gui-private v8-private qml-private quick-private + +DEFINES += QT_BUILD_QUICKPARTICLES_LIB QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES +win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS +solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 + +exists("qqml_enable_gcov") { + QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors + LIBS += -lgcov +} + +MODULE = quickparticles +load(qt_module_config) + +include(particles.pri) + +mac { + # FIXME: this is a workaround for broken qmake logic in qtAddModule() + # This function refuses to use frameworks unless the framework exists on + # the filesystem at the time qmake is run, resulting in a build failure + # if QtQuick is qmaked before QtQml is built and frameworks are + # in use. qtAddLibrary() contains correct logic to deal with this, so + # we'll explicitly call that for now. + load(qt) + LIBS -= -lQtQml # in non-framework builds, these should be re-added + LIBS -= -lQtQml_debug # within the qtAddLibrary if appropriate, so no + qtAddLibrary(QtQml) # harm done :) + LIBS -= -lQtQuick + LIBS -= -lQtQuick_debug + qtAddLibrary(QtQuick) +} + diff --git a/src/quick/particles/particles.qrc b/src/particles/particles.qrc index 344f9489a4..344f9489a4 100644 --- a/src/quick/particles/particles.qrc +++ b/src/particles/particles.qrc diff --git a/src/quick/particles/qquickage.cpp b/src/particles/qquickage.cpp index 9f24cba3cc..9f24cba3cc 100644 --- a/src/quick/particles/qquickage.cpp +++ b/src/particles/qquickage.cpp diff --git a/src/quick/particles/qquickage_p.h b/src/particles/qquickage_p.h index 2ec8faae4b..2ec8faae4b 100644 --- a/src/quick/particles/qquickage_p.h +++ b/src/particles/qquickage_p.h diff --git a/src/quick/particles/qquickangledirection.cpp b/src/particles/qquickangledirection.cpp index e77c47362c..e77c47362c 100644 --- a/src/quick/particles/qquickangledirection.cpp +++ b/src/particles/qquickangledirection.cpp diff --git a/src/quick/particles/qquickangledirection_p.h b/src/particles/qquickangledirection_p.h index 84633cd40e..84633cd40e 100644 --- a/src/quick/particles/qquickangledirection_p.h +++ b/src/particles/qquickangledirection_p.h diff --git a/src/quick/particles/qquickcumulativedirection.cpp b/src/particles/qquickcumulativedirection.cpp index d7c4094297..d7c4094297 100644 --- a/src/quick/particles/qquickcumulativedirection.cpp +++ b/src/particles/qquickcumulativedirection.cpp diff --git a/src/quick/particles/qquickcumulativedirection_p.h b/src/particles/qquickcumulativedirection_p.h index e1675a18d8..e1675a18d8 100644 --- a/src/quick/particles/qquickcumulativedirection_p.h +++ b/src/particles/qquickcumulativedirection_p.h diff --git a/src/quick/particles/qquickcustomaffector.cpp b/src/particles/qquickcustomaffector.cpp index acec98192d..acec98192d 100644 --- a/src/quick/particles/qquickcustomaffector.cpp +++ b/src/particles/qquickcustomaffector.cpp diff --git a/src/quick/particles/qquickcustomaffector_p.h b/src/particles/qquickcustomaffector_p.h index 1266830f94..1266830f94 100644 --- a/src/quick/particles/qquickcustomaffector_p.h +++ b/src/particles/qquickcustomaffector_p.h diff --git a/src/quick/particles/qquickcustomparticle.cpp b/src/particles/qquickcustomparticle.cpp index 7d27e48c6b..7d27e48c6b 100644 --- a/src/quick/particles/qquickcustomparticle.cpp +++ b/src/particles/qquickcustomparticle.cpp diff --git a/src/quick/particles/qquickcustomparticle_p.h b/src/particles/qquickcustomparticle_p.h index f689091268..f689091268 100644 --- a/src/quick/particles/qquickcustomparticle_p.h +++ b/src/particles/qquickcustomparticle_p.h diff --git a/src/quick/particles/qquickdirection.cpp b/src/particles/qquickdirection.cpp index 4127d06be0..4127d06be0 100644 --- a/src/quick/particles/qquickdirection.cpp +++ b/src/particles/qquickdirection.cpp diff --git a/src/quick/particles/qquickdirection_p.h b/src/particles/qquickdirection_p.h index 651865a1f5..651865a1f5 100644 --- a/src/quick/particles/qquickdirection_p.h +++ b/src/particles/qquickdirection_p.h diff --git a/src/quick/particles/qquickellipseextruder.cpp b/src/particles/qquickellipseextruder.cpp index 083564e5cb..083564e5cb 100644 --- a/src/quick/particles/qquickellipseextruder.cpp +++ b/src/particles/qquickellipseextruder.cpp diff --git a/src/quick/particles/qquickellipseextruder_p.h b/src/particles/qquickellipseextruder_p.h index c2d0c634ab..c2d0c634ab 100644 --- a/src/quick/particles/qquickellipseextruder_p.h +++ b/src/particles/qquickellipseextruder_p.h diff --git a/src/quick/particles/qquickfriction.cpp b/src/particles/qquickfriction.cpp index d37d109f48..d37d109f48 100644 --- a/src/quick/particles/qquickfriction.cpp +++ b/src/particles/qquickfriction.cpp diff --git a/src/quick/particles/qquickfriction_p.h b/src/particles/qquickfriction_p.h index 3b06710529..3b06710529 100644 --- a/src/quick/particles/qquickfriction_p.h +++ b/src/particles/qquickfriction_p.h diff --git a/src/quick/particles/qquickgravity.cpp b/src/particles/qquickgravity.cpp index cf4f35eb72..cf4f35eb72 100644 --- a/src/quick/particles/qquickgravity.cpp +++ b/src/particles/qquickgravity.cpp diff --git a/src/quick/particles/qquickgravity_p.h b/src/particles/qquickgravity_p.h index a738fd3ef3..a738fd3ef3 100644 --- a/src/quick/particles/qquickgravity_p.h +++ b/src/particles/qquickgravity_p.h diff --git a/src/quick/particles/qquickgroupgoal.cpp b/src/particles/qquickgroupgoal.cpp index 0d7f15a9e1..0d7f15a9e1 100644 --- a/src/quick/particles/qquickgroupgoal.cpp +++ b/src/particles/qquickgroupgoal.cpp diff --git a/src/quick/particles/qquickgroupgoal_p.h b/src/particles/qquickgroupgoal_p.h index f553badbd6..f553badbd6 100644 --- a/src/quick/particles/qquickgroupgoal_p.h +++ b/src/particles/qquickgroupgoal_p.h diff --git a/src/quick/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index d9eb6ed01b..d9eb6ed01b 100644 --- a/src/quick/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp diff --git a/src/quick/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h index 4db2c9801a..4db2c9801a 100644 --- a/src/quick/particles/qquickimageparticle_p.h +++ b/src/particles/qquickimageparticle_p.h diff --git a/src/quick/particles/qquickitemparticle.cpp b/src/particles/qquickitemparticle.cpp index 91ef06fcb2..91ef06fcb2 100644 --- a/src/quick/particles/qquickitemparticle.cpp +++ b/src/particles/qquickitemparticle.cpp diff --git a/src/quick/particles/qquickitemparticle_p.h b/src/particles/qquickitemparticle_p.h index c7b8a2661e..c7b8a2661e 100644 --- a/src/quick/particles/qquickitemparticle_p.h +++ b/src/particles/qquickitemparticle_p.h diff --git a/src/quick/particles/qquicklineextruder.cpp b/src/particles/qquicklineextruder.cpp index f555de3f72..f555de3f72 100644 --- a/src/quick/particles/qquicklineextruder.cpp +++ b/src/particles/qquicklineextruder.cpp diff --git a/src/quick/particles/qquicklineextruder_p.h b/src/particles/qquicklineextruder_p.h index 6f2b2493a6..6f2b2493a6 100644 --- a/src/quick/particles/qquicklineextruder_p.h +++ b/src/particles/qquicklineextruder_p.h diff --git a/src/quick/particles/qquickmaskextruder.cpp b/src/particles/qquickmaskextruder.cpp index 50b71749c0..50b71749c0 100644 --- a/src/quick/particles/qquickmaskextruder.cpp +++ b/src/particles/qquickmaskextruder.cpp diff --git a/src/quick/particles/qquickmaskextruder_p.h b/src/particles/qquickmaskextruder_p.h index 8b6c3f0b2d..8b6c3f0b2d 100644 --- a/src/quick/particles/qquickmaskextruder_p.h +++ b/src/particles/qquickmaskextruder_p.h diff --git a/src/quick/particles/qquickparticleaffector.cpp b/src/particles/qquickparticleaffector.cpp index 0005af86af..0005af86af 100644 --- a/src/quick/particles/qquickparticleaffector.cpp +++ b/src/particles/qquickparticleaffector.cpp diff --git a/src/quick/particles/qquickparticleaffector_p.h b/src/particles/qquickparticleaffector_p.h index 4147488f87..4147488f87 100644 --- a/src/quick/particles/qquickparticleaffector_p.h +++ b/src/particles/qquickparticleaffector_p.h diff --git a/src/quick/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp index 035d66cbcd..035d66cbcd 100644 --- a/src/quick/particles/qquickparticleemitter.cpp +++ b/src/particles/qquickparticleemitter.cpp diff --git a/src/quick/particles/qquickparticleemitter_p.h b/src/particles/qquickparticleemitter_p.h index eb9e1fd591..eb9e1fd591 100644 --- a/src/quick/particles/qquickparticleemitter_p.h +++ b/src/particles/qquickparticleemitter_p.h diff --git a/src/quick/particles/qquickparticleextruder.cpp b/src/particles/qquickparticleextruder.cpp index 279f7c05f3..279f7c05f3 100644 --- a/src/quick/particles/qquickparticleextruder.cpp +++ b/src/particles/qquickparticleextruder.cpp diff --git a/src/quick/particles/qquickparticleextruder_p.h b/src/particles/qquickparticleextruder_p.h index e24950e4e8..e24950e4e8 100644 --- a/src/quick/particles/qquickparticleextruder_p.h +++ b/src/particles/qquickparticleextruder_p.h diff --git a/src/quick/particles/qquickparticlegroup.cpp b/src/particles/qquickparticlegroup.cpp index 9a165074a1..9a165074a1 100644 --- a/src/quick/particles/qquickparticlegroup.cpp +++ b/src/particles/qquickparticlegroup.cpp diff --git a/src/quick/particles/qquickparticlegroup_p.h b/src/particles/qquickparticlegroup_p.h index 8889187558..8889187558 100644 --- a/src/quick/particles/qquickparticlegroup_p.h +++ b/src/particles/qquickparticlegroup_p.h diff --git a/src/quick/particles/qquickparticlepainter.cpp b/src/particles/qquickparticlepainter.cpp index e490b70240..e490b70240 100644 --- a/src/quick/particles/qquickparticlepainter.cpp +++ b/src/particles/qquickparticlepainter.cpp diff --git a/src/quick/particles/qquickparticlepainter_p.h b/src/particles/qquickparticlepainter_p.h index 1ae4625856..1ae4625856 100644 --- a/src/quick/particles/qquickparticlepainter_p.h +++ b/src/particles/qquickparticlepainter_p.h diff --git a/src/quick/particles/qquickparticlesmodule.cpp b/src/particles/qquickparticlesmodule.cpp index e83cde3cd1..e83cde3cd1 100644 --- a/src/quick/particles/qquickparticlesmodule.cpp +++ b/src/particles/qquickparticlesmodule.cpp diff --git a/src/quick/particles/qquickparticlesmodule_p.h b/src/particles/qquickparticlesmodule_p.h index 23a40488cf..87e99fa6bb 100644 --- a/src/quick/particles/qquickparticlesmodule_p.h +++ b/src/particles/qquickparticlesmodule_p.h @@ -42,13 +42,13 @@ #ifndef QQUICKPARTICLESMODULE_H #define QQUICKPARTICLESMODULE_H -#include <private/qtquickglobal_p.h> +#include <private/qtquickparticlesglobal_p.h> QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class Q_QUICK_PRIVATE_EXPORT QQuickParticlesModule +class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticlesModule { public: static void defineModule(); diff --git a/src/quick/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 4fd6108f2f..4fd6108f2f 100644 --- a/src/quick/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp diff --git a/src/quick/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index f70cc5af94..f70cc5af94 100644 --- a/src/quick/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h diff --git a/src/quick/particles/qquickpointattractor.cpp b/src/particles/qquickpointattractor.cpp index a54ee41c1e..a54ee41c1e 100644 --- a/src/quick/particles/qquickpointattractor.cpp +++ b/src/particles/qquickpointattractor.cpp diff --git a/src/quick/particles/qquickpointattractor_p.h b/src/particles/qquickpointattractor_p.h index 85b7a9aa30..85b7a9aa30 100644 --- a/src/quick/particles/qquickpointattractor_p.h +++ b/src/particles/qquickpointattractor_p.h diff --git a/src/quick/particles/qquickpointdirection.cpp b/src/particles/qquickpointdirection.cpp index e35eb4854c..e35eb4854c 100644 --- a/src/quick/particles/qquickpointdirection.cpp +++ b/src/particles/qquickpointdirection.cpp diff --git a/src/quick/particles/qquickpointdirection_p.h b/src/particles/qquickpointdirection_p.h index 7b18e6d8d7..7b18e6d8d7 100644 --- a/src/quick/particles/qquickpointdirection_p.h +++ b/src/particles/qquickpointdirection_p.h diff --git a/src/quick/particles/qquickrectangleextruder.cpp b/src/particles/qquickrectangleextruder.cpp index ad2207ca9a..ad2207ca9a 100644 --- a/src/quick/particles/qquickrectangleextruder.cpp +++ b/src/particles/qquickrectangleextruder.cpp diff --git a/src/quick/particles/qquickrectangleextruder_p.h b/src/particles/qquickrectangleextruder_p.h index 1d4f8cc439..1d4f8cc439 100644 --- a/src/quick/particles/qquickrectangleextruder_p.h +++ b/src/particles/qquickrectangleextruder_p.h diff --git a/src/quick/particles/qquickspritegoal.cpp b/src/particles/qquickspritegoal.cpp index 95d913cafa..95d913cafa 100644 --- a/src/quick/particles/qquickspritegoal.cpp +++ b/src/particles/qquickspritegoal.cpp diff --git a/src/quick/particles/qquickspritegoal_p.h b/src/particles/qquickspritegoal_p.h index 2b6b4f28fc..2b6b4f28fc 100644 --- a/src/quick/particles/qquickspritegoal_p.h +++ b/src/particles/qquickspritegoal_p.h diff --git a/src/quick/particles/qquicktargetdirection.cpp b/src/particles/qquicktargetdirection.cpp index 695684dfde..695684dfde 100644 --- a/src/quick/particles/qquicktargetdirection.cpp +++ b/src/particles/qquicktargetdirection.cpp diff --git a/src/quick/particles/qquicktargetdirection_p.h b/src/particles/qquicktargetdirection_p.h index 0e0e942ca8..0e0e942ca8 100644 --- a/src/quick/particles/qquicktargetdirection_p.h +++ b/src/particles/qquicktargetdirection_p.h diff --git a/src/quick/particles/qquicktrailemitter.cpp b/src/particles/qquicktrailemitter.cpp index 32f8763599..32f8763599 100644 --- a/src/quick/particles/qquicktrailemitter.cpp +++ b/src/particles/qquicktrailemitter.cpp diff --git a/src/quick/particles/qquicktrailemitter_p.h b/src/particles/qquicktrailemitter_p.h index 0b63a444ec..0b63a444ec 100644 --- a/src/quick/particles/qquicktrailemitter_p.h +++ b/src/particles/qquicktrailemitter_p.h diff --git a/src/quick/particles/qquickturbulence.cpp b/src/particles/qquickturbulence.cpp index 18ecc6a4cd..18ecc6a4cd 100644 --- a/src/quick/particles/qquickturbulence.cpp +++ b/src/particles/qquickturbulence.cpp diff --git a/src/quick/particles/qquickturbulence_p.h b/src/particles/qquickturbulence_p.h index cd5535c387..cd5535c387 100644 --- a/src/quick/particles/qquickturbulence_p.h +++ b/src/particles/qquickturbulence_p.h diff --git a/src/quick/particles/qquickv8particledata.cpp b/src/particles/qquickv8particledata.cpp index 8e50e41091..8e50e41091 100644 --- a/src/quick/particles/qquickv8particledata.cpp +++ b/src/particles/qquickv8particledata.cpp diff --git a/src/quick/particles/qquickv8particledata_p.h b/src/particles/qquickv8particledata_p.h index 21ec6458c1..21ec6458c1 100644 --- a/src/quick/particles/qquickv8particledata_p.h +++ b/src/particles/qquickv8particledata_p.h diff --git a/src/quick/particles/qquickwander.cpp b/src/particles/qquickwander.cpp index 0f9a5f069b..0f9a5f069b 100644 --- a/src/quick/particles/qquickwander.cpp +++ b/src/particles/qquickwander.cpp diff --git a/src/quick/particles/qquickwander_p.h b/src/particles/qquickwander_p.h index bb418f7912..bb418f7912 100644 --- a/src/quick/particles/qquickwander_p.h +++ b/src/particles/qquickwander_p.h diff --git a/src/particles/qtquickparticlesglobal_p.h b/src/particles/qtquickparticlesglobal_p.h new file mode 100644 index 0000000000..d7814f759d --- /dev/null +++ b/src/particles/qtquickparticlesglobal_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQuickParticles module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTQUICKPARTICLESGLOBAL_P_H +#define QTQUICKPARTICLESGLOBAL_P_H + +#include <QtCore/qglobal.h> + +// We only have private exports from this library + +#if defined(Q_OS_WIN) +# if defined(QT_MAKEDLL) /* create a Qt DLL library */ +# if defined(QT_BUILD_QUICKPARTICLES_LIB) +# define Q_QUICKPARTICLES_PRIVATE_EXPORT Q_DECL_EXPORT +# else +# define Q_QUICKPARTICLES_PRIVATE_EXPORT Q_DECL_IMPORT +# endif +# elif defined(QT_DLL) /* use a Qt DLL library */ +# define Q_QUICKPARTICLES_PRIVATE_EXPORT Q_DECL_IMPORT +# endif +#endif + +#if !defined(Q_QUICKPARTICLES_PRIVATE_EXPORT) +# if defined(QT_SHARED) +# define Q_QUICKPARTICLES_PRIVATE_EXPORT Q_DECL_EXPORT +# else +# define Q_QUICKPARTICLES_PRIVATE_EXPORT +# endif +#endif + +#endif // QTQUICKPARTICLESGLOBAL_P_H diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp index da959933f7..d014dd4e0d 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp @@ -42,6 +42,7 @@ #include "highlight.h" #include <QtGui/QPainter> +#include <QtQuick/QQuickCanvas> namespace QmlJSDebugger { namespace QtQuick2 { @@ -55,7 +56,7 @@ Highlight::Highlight(QQuickItem *item, QQuickItem *parent) void Highlight::setItem(QQuickItem *item) { if (m_item) - m_item.data()->disconnect(this); + m_item->disconnect(this); if (item) { connect(item, SIGNAL(xChanged()), SLOT(adjust())); @@ -66,34 +67,81 @@ void Highlight::setItem(QQuickItem *item) connect(item, SIGNAL(transformOriginChanged(TransformOrigin)), SLOT(adjust())); } - + QQuickCanvas *view = item->canvas(); + QQuickItem * rootItem = view->rootItem(); + if (rootItem) { + connect(rootItem, SIGNAL(xChanged()), SLOT(adjust())); + connect(rootItem, SIGNAL(yChanged()), SLOT(adjust())); + connect(rootItem, SIGNAL(widthChanged()), SLOT(adjust())); + connect(rootItem, SIGNAL(heightChanged()), SLOT(adjust())); + connect(rootItem, SIGNAL(rotationChanged()), SLOT(adjust())); + connect(rootItem, SIGNAL(transformOriginChanged(TransformOrigin)), + SLOT(adjust())); + } m_item = item; adjust(); } void Highlight::adjust() { - const QQuickItem *item = m_item.data(); - setSize(QSizeF(item->width(), item->height())); - setPos(parentItem()->mapFromItem(item->parentItem(), item->pos())); - setRotation(item->rotation()); - setTransformOrigin(item->transformOrigin()); + if (!m_item) + return; + + bool success = false; + m_transform = m_item->itemTransform(0, &success); + if (!success) + m_transform = QTransform(); + + setSize(QSizeF(m_item->width(), m_item->height())); + qreal scaleFactor = 1; + QPointF originOffset = QPointF(0,0); + QQuickCanvas *view = m_item->canvas(); + if (view->rootItem()) { + scaleFactor = view->rootItem()->scale(); + originOffset -= view->rootItem()->pos(); + } + // The scale transform for the overlay needs to be cancelled + // as the Item's transform which will be applied to the painter + // takes care of it. + parentItem()->setScale(1/scaleFactor); + setPos(originOffset); + setContentsSize(view->size()); + update(); } void HoverHighlight::paint(QPainter *painter) { + if (!item()) + return; + + painter->save(); + painter->setTransform(transform()); painter->setPen(QColor(108, 141, 221)); - painter->drawRect(QRect(0, 0, width() - 1, height() - 1)); + painter->drawRect(QRect(0, 0, item()->width() - 1, item()->height() - 1)); + painter->restore(); } void SelectionHighlight::paint(QPainter *painter) { + if (!item()) + return; + + painter->save(); + painter->setTransform(transform()); + if (item()->height() >= 10 && item()->width() >= 10) { + QColor colorHighlight = Qt::green; + painter->fillRect(QRectF(0, 0, item()->width(), 5), colorHighlight); + painter->fillRect(QRectF(0, item()->height()-5, item()->width(), 5), colorHighlight); + painter->fillRect(QRectF(0, 5, 5, item()->height() - 10), colorHighlight); + painter->fillRect(QRectF(item()->width()-5, 5, 5, item()->height() - 10), colorHighlight); + } painter->setPen(QPen(QColor(0, 22, 159))); - painter->drawRect(QRect(1, 1, width() - 3, height() - 3)); + painter->drawRect(QRect(1, 1, item()->width() - 3, item()->height() - 3)); painter->setPen(QColor(158, 199, 255)); - painter->drawRect(QRect(0, 0, width() - 1, height() - 1)); + painter->drawRect(QRect(0, 0, item()->width() - 1, item()->height() - 1)); + painter->restore(); } } // namespace QtQuick2 diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/highlight.h b/src/plugins/qmltooling/qmldbg_qtquick2/highlight.h index 1b1f10c8bb..3dbd109934 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/highlight.h +++ b/src/plugins/qmltooling/qmldbg_qtquick2/highlight.h @@ -42,9 +42,11 @@ #ifndef HIGHLIGHT_H #define HIGHLIGHT_H -#include <QtCore/QWeakPointer> +#include <QtCore/QPointer> +#include <QtGui/QTransform> #include <QtQuick/QQuickPaintedItem> + namespace QmlJSDebugger { namespace QtQuick2 { @@ -57,12 +59,17 @@ public: Highlight(QQuickItem *item, QQuickItem *parent); void setItem(QQuickItem *item); + QQuickItem *item() {return m_item;} + +protected: + QTransform transform() {return m_transform;} private slots: void adjust(); private: - QWeakPointer<QQuickItem> m_item; + QPointer<QQuickItem> m_item; + QTransform m_transform; }; /** diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.cpp index 67b12822be..796549f237 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.cpp @@ -68,7 +68,6 @@ InspectTool::InspectTool(QQuickViewInspector *inspector, QQuickView *view) : m_tapEvent(false), m_rootItem(view->rootItem()), m_originalPosition(view->rootItem()->pos()), - m_currentScale(1.0f), m_smoothScaleFactor(Constants::ZoomSnapDelta), m_minScale(0.125f), m_maxScale(48.0f), @@ -128,16 +127,20 @@ void InspectTool::mouseReleaseEvent(QMouseEvent *event) { m_mousePosition = event->posF(); m_pressAndHoldTimer.stop(); - if (event->button() == Qt::LeftButton) + if (event->button() == Qt::LeftButton && !m_dragStarted) { selectItem(); + m_hoverHighlight->setVisible(false); + } } void InspectTool::mouseDoubleClickEvent(QMouseEvent *event) { m_mousePosition = event->posF(); m_pressAndHoldTimer.stop(); - if (event->button() == Qt::LeftButton) + if (event->button() == Qt::LeftButton) { selectNextItem(); + m_hoverHighlight->setVisible(false); + } } void InspectTool::mouseMoveEvent(QMouseEvent *event) @@ -167,8 +170,8 @@ void InspectTool::wheelEvent(QWheelEvent *event) Qt::KeyboardModifier smoothZoomModifier = Qt::ControlModifier; if (event->modifiers() & smoothZoomModifier) { int numDegrees = event->delta() / 8; - qreal newScale = m_currentScale + m_smoothScaleFactor * (numDegrees / 15.0f); - scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition); + qreal newScale = m_rootItem->scale() + m_smoothScaleFactor * (numDegrees / 15.0f); + scaleView(newScale / m_rootItem->scale(), m_mousePosition, m_mousePosition); } else if (!event->modifiers()) { if (event->delta() > 0) { zoomIn(); @@ -197,7 +200,7 @@ void InspectTool::keyReleaseEvent(QKeyEvent *event) case Qt::Key_8: case Qt::Key_9: { qreal newScale = ((event->key() - Qt::Key_0) * 1.0f); - scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition); + scaleView(newScale / m_rootItem->scale(), m_mousePosition, m_mousePosition); break; } default: @@ -273,38 +276,34 @@ void InspectTool::touchEvent(QTouchEvent *event) void InspectTool::scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter) { m_pressAndHoldTimer.stop(); - if (((m_currentScale * factor) > m_maxScale) - || ((m_currentScale * factor) < m_minScale)) { + if (((m_rootItem->scale() * factor) > m_maxScale) + || ((m_rootItem->scale() * factor) < m_minScale)) { return; } //New position = new center + scalefactor * (oldposition - oldcenter) - m_adjustedOrigin = newcenter + (factor * (m_adjustedOrigin - oldcenter)); - m_currentScale *= factor; - - m_rootItem->setScale(m_currentScale); - m_rootItem->setPos(m_adjustedOrigin); + QPointF newPosition = newcenter + (factor * (m_rootItem->pos() - oldcenter)); + m_rootItem->setScale(m_rootItem->scale() * factor); + m_rootItem->setPos(newPosition); } void InspectTool::zoomIn() { qreal newScale = nextZoomScale(ZoomIn); - scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition); + scaleView(newScale / m_rootItem->scale(), m_mousePosition, m_mousePosition); } void InspectTool::zoomOut() { qreal newScale = nextZoomScale(ZoomOut); - scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition); + scaleView(newScale / m_rootItem->scale(), m_mousePosition, m_mousePosition); } void InspectTool::zoomTo100() { m_didPressAndHold = true; - m_currentScale = 1.0; - m_adjustedOrigin = QPointF(0, 0); - m_rootItem->setPos(m_adjustedOrigin); - m_rootItem->setScale(m_currentScale); + m_rootItem->setPos(QPointF(0, 0)); + m_rootItem->setScale(1.0); } qreal InspectTool::nextZoomScale(ZoomDirection direction) @@ -332,13 +331,13 @@ qreal InspectTool::nextZoomScale(ZoomDirection direction) if (direction == ZoomIn) { for (int i = 0; i < zoomScales.length(); ++i) { - if (zoomScales[i] > m_currentScale) + if (zoomScales[i] > m_rootItem->scale()) return zoomScales[i]; } return zoomScales.last(); } else { for (int i = zoomScales.length() - 1; i >= 0; --i) { - if (zoomScales[i] < m_currentScale) + if (zoomScales[i] < m_rootItem->scale()) return zoomScales[i]; } return zoomScales.first(); @@ -355,9 +354,9 @@ void InspectTool::initializeDrag(const QPointF &pos) void InspectTool::dragItemToPosition() { - m_adjustedOrigin += m_mousePosition - m_dragStartPosition; + QPointF newPosition = m_rootItem->pos() + m_mousePosition - m_dragStartPosition; m_dragStartPosition = m_mousePosition; - m_rootItem->setPos(m_adjustedOrigin); + m_rootItem->setPos(newPosition); } void InspectTool::moveItem(bool valid) diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.h b/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.h index 25d0c634b2..f452802f6a 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.h +++ b/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.h @@ -108,11 +108,9 @@ private: bool m_didPressAndHold; bool m_tapEvent; QPointer<QQuickItem> m_rootItem; - QPointF m_adjustedOrigin; QPointF m_dragStartPosition; QPointF m_mousePosition; QPointF m_originalPosition; - qreal m_currentScale; qreal m_smoothScaleFactor; qreal m_minScale; qreal m_maxScale; diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp index 95ce86678c..f92fbb94c6 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp @@ -58,8 +58,8 @@ namespace QtQuick2 { /* * Collects all the items at the given position, from top to bottom. */ -static void collectItemsAt(QQuickItem *item, const QPointF &pos, QQuickItem *overlay, - QList<QQuickItem *> &resultList) +static void collectItemsAt(QQuickItem *item, const QPointF &pos, + QQuickItem *overlay, QList<QQuickItem *> &resultList) { if (item == overlay) return; @@ -85,7 +85,8 @@ static void collectItemsAt(QQuickItem *item, const QPointF &pos, QQuickItem *ove * Returns the first visible item at the given position, or 0 when no such * child exists. */ -static QQuickItem *itemAt(QQuickItem *item, const QPointF &pos, QQuickItem *overlay) +static QQuickItem *itemAt(QQuickItem *item, const QPointF &pos, + QQuickItem *overlay) { if (item == overlay) return 0; @@ -101,7 +102,8 @@ static QQuickItem *itemAt(QQuickItem *item, const QPointF &pos, QQuickItem *over QList<QQuickItem *> children = QQuickItemPrivate::get(item)->paintOrderChildItems(); for (int i = children.count() - 1; i >= 0; --i) { QQuickItem *child = children.at(i); - if (QQuickItem *betterCandidate = itemAt(child, item->mapToItem(child, pos), overlay)) + if (QQuickItem *betterCandidate = itemAt(child, item->mapToItem(child, pos), + overlay)) return betterCandidate; } @@ -171,6 +173,8 @@ void QQuickViewInspector::changeTool(InspectorProtocol::Tool tool) setCurrentTool(m_inspectTool); emit inspectToolActivated(); break; + default: + break; } } @@ -213,16 +217,17 @@ QList<QQuickItem *> QQuickViewInspector::itemsAt(const QPointF &pos) const { QQuickItem *root = m_view->rootItem(); QList<QQuickItem *> resultList; - collectItemsAt(root, root->mapFromScene(pos), m_overlay, resultList); + collectItemsAt(root, root->mapFromScene(pos), m_overlay, + resultList); return resultList; } QList<QQuickItem*> QQuickViewInspector::selectedItems() const { QList<QQuickItem *> selection; - foreach (const QWeakPointer<QQuickItem> &selectedItem, m_selectedItems) { + foreach (const QPointer<QQuickItem> &selectedItem, m_selectedItems) { if (selectedItem) - selection << selectedItem.data(); + selection << selectedItem; } return selection; } @@ -244,16 +249,16 @@ bool QQuickViewInspector::syncSelectedItems(const QList<QQuickItem *> &items) bool selectionChanged = false; // Disconnect and remove items that are no longer selected - foreach (const QWeakPointer<QQuickItem> &item, m_selectedItems) { + foreach (const QPointer<QQuickItem> &item, m_selectedItems) { if (!item) // Don't see how this can happen due to handling of destroyed() continue; - if (items.contains(item.data())) + if (items.contains(item)) continue; selectionChanged = true; - item.data()->disconnect(this); + item->disconnect(this); m_selectedItems.removeOne(item); - delete m_highlightItems.take(item.data()); + delete m_highlightItems.take(item); } // Connect and add newly selected items @@ -264,7 +269,9 @@ bool QQuickViewInspector::syncSelectedItems(const QList<QQuickItem *> &items) selectionChanged = true; connect(item, SIGNAL(destroyed(QObject*)), this, SLOT(removeFromSelectedItems(QObject*))); m_selectedItems.append(item); - m_highlightItems.insert(item, new SelectionHighlight(item, m_overlay)); + SelectionHighlight *selectionHighlightItem; + selectionHighlightItem = new SelectionHighlight(item, m_overlay); + m_highlightItems.insert(item, selectionHighlightItem); } return selectionChanged; diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h index 0fd2948279..bcc008cbac 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h @@ -44,7 +44,7 @@ #include "abstractviewinspector.h" -#include <QtCore/QWeakPointer> +#include <QtCore/QPointer> #include <QtCore/QHash> QT_BEGIN_NAMESPACE @@ -100,7 +100,7 @@ private: InspectTool *m_inspectTool; - QList<QWeakPointer<QQuickItem> > m_selectedItems; + QList<QPointer<QQuickItem> > m_selectedItems; QHash<QQuickItem*, SelectionHighlight*> m_highlightItems; bool m_designMode; diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp index fecd8fbc5d..d1b8880087 100644 --- a/src/qml/animations/qabstractanimationjob.cpp +++ b/src/qml/animations/qabstractanimationjob.cpp @@ -567,7 +567,6 @@ void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeLis changeListeners.removeOne(ChangeListener(listener, changes)); } - QT_END_NAMESPACE //#include "moc_qabstractanimation2_p.cpp" diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h index e7d96ddfce..d26aa868ce 100644 --- a/src/qml/animations/qabstractanimationjob_p.h +++ b/src/qml/animations/qabstractanimationjob_p.h @@ -113,7 +113,6 @@ public: void addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes); void removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes); - QAbstractAnimationJob *nextSibling() const { return m_nextSibling; } QAbstractAnimationJob *previousSibling() const { return m_previousSibling; } diff --git a/src/qml/debugger/qv8debugservice.cpp b/src/qml/debugger/qv8debugservice.cpp index 7d54a59ac0..f8831db6c6 100644 --- a/src/qml/debugger/qv8debugservice.cpp +++ b/src/qml/debugger/qv8debugservice.cpp @@ -67,7 +67,6 @@ const char *V8_DEBUGGER_KEY_DISCONNECT = "disconnect"; const char *V8_DEBUGGER_KEY_REQUEST = "v8request"; const char *V8_DEBUGGER_KEY_V8MESSAGE = "v8message"; const char *V8_DEBUGGER_KEY_BREAK_ON_SIGNAL = "breakonsignal"; -const char *V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE = "breakaftercompile"; QT_BEGIN_NAMESPACE @@ -92,10 +91,15 @@ void DebugMessageHandler(const v8::Debug::Message& message) { v8::DebugEvent event = message.GetEvent(); - if (event != v8::Break && event != v8::Exception && - event != v8::AfterCompile && event != v8::BeforeCompile) + if (message.IsEvent()) { + if (event == v8::AfterCompile || event == v8::BeforeCompile) return; - v8ServiceInstancePtr->debugMessageHandler(QJSConverter::toString(message.GetJSON()), event); + } else if (event != v8::Break && event != v8::Exception && + event != v8::AfterCompile && event != v8::BeforeCompile) { + return; + } + + v8ServiceInstancePtr->debugMessageHandler(QJSConverter::toString(message.GetJSON())); } class QV8DebugServicePrivate : public QQmlDebugServicePrivate @@ -103,7 +107,6 @@ class QV8DebugServicePrivate : public QQmlDebugServicePrivate public: QV8DebugServicePrivate() : connectReceived(false) - , breakAfterCompile(false) , engine(0) { } @@ -113,7 +116,6 @@ public: static QByteArray packMessage(const QString &type, const QString &message = QString()); bool connectReceived; - bool breakAfterCompile; QMutex initializeMutex; QStringList breakOnSignals; const QV8Engine *engine; @@ -160,12 +162,9 @@ void QV8DebugService::setEngine(const QV8Engine *engine) d->engine = engine; } -void QV8DebugService::debugMessageHandler(const QString &message, const v8::DebugEvent &event) +void QV8DebugService::debugMessageHandler(const QString &message) { - Q_D(QV8DebugService); sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_V8MESSAGE), message)); - if (event == v8::AfterCompile && d->breakAfterCompile) - scheduledDebugBreak(true); } void QV8DebugService::signalEmitted(const QString &signal) @@ -262,11 +261,6 @@ void QV8DebugService::messageReceived(const QByteArray &message) d->breakOnSignals.removeOne(signalName); sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_BREAK_ON_SIGNAL))); - } else if (command == V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE) { - QDataStream rs(data); - rs >> d->breakAfterCompile; - sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE))); - } } } diff --git a/src/qml/debugger/qv8debugservice_p.h b/src/qml/debugger/qv8debugservice_p.h index 8ff4adc778..84b300cee4 100644 --- a/src/qml/debugger/qv8debugservice_p.h +++ b/src/qml/debugger/qv8debugservice_p.h @@ -74,7 +74,7 @@ public: static QV8DebugService *instance(); static void initialize(const QV8Engine *engine); - void debugMessageHandler(const QString &message, const v8::DebugEvent &event); + void debugMessageHandler(const QString &message); void signalEmitted(const QString &signal); diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp index 64df87ada5..2ff2cd054f 100644 --- a/src/qml/qml/ftw/qqmlpool.cpp +++ b/src/qml/qml/ftw/qqmlpool.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qqmlpool_p.h" +#include <stdlib.h> #ifdef Q_OS_QNX #include <malloc.h> diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index ad28e38a64..c3537dac9d 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -88,7 +88,7 @@ void QQmlListReferencePrivate::release() /*! \class QQmlListReference \since 5.0 -\module QtQml +\inmodule QtQml \brief The QQmlListReference class allows the manipulation of QQmlListProperty properties. QQmlListReference allows C++ programs to read from, and assign values to a QML list property in a diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 4a4563ccd4..f15565c0a5 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -750,8 +750,8 @@ V8_DEFINE_EXTENSION(QV8LocaleDataDeletable, localeV8Data); \inqmlmodule QtQuick 2 \brief The Locale object provides locale specific properties and formatted data. - The Locale object is created via the \l{QML:Qt::locale()}{Qt.locale()} function. It cannot be created - directly. + The Locale object may only be created via the \l{QML:Qt::locale()}{Qt.locale()} function. + It cannot be created directly. The \l{QML:Qt::locale()}{Qt.locale()} function returns a JS Locale object representing the locale with the specified name, which has the format diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp index 4c92598c32..e055cad4f2 100644 --- a/src/qml/qml/v4/qv4bindings.cpp +++ b/src/qml/qml/v4/qv4bindings.cpp @@ -94,11 +94,9 @@ struct Register { inline QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); } inline QString *getstringptr() { return (QString *)typeDataPtr(); } inline QUrl *geturlptr() { return (QUrl *)typeDataPtr(); } - inline QColor *getcolorptr() { return (QColor *)typeDataPtr(); } inline const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); } inline const QString *getstringptr() const { return (QString *)typeDataPtr(); } inline const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); } - inline const QColor *getcolorptr() const { return (QColor *)typeDataPtr(); } size_t dataSize() { return sizeof(data); } inline void *typeDataPtr() { return (void *)&data; } @@ -458,7 +456,7 @@ static void testBindingResult(const QString &binding, int line, int column, if (expression.hasError()) { iserror = true; qtscriptResult = "exception"; - } else if (value.userType() != resultType) { + } else if ((value.userType() != resultType) && (resultType != QMetaType::QVariant)) { // Override the QMetaType conversions to make them more JS friendly. if (value.userType() == QMetaType::Double && (resultType == QMetaType::QString || resultType == QMetaType::QUrl)) { @@ -508,6 +506,12 @@ static void testBindingResult(const QString &binding, int line, int column, case QMetaType::Double: v4value = result.getnumber(); break; + case QMetaType::QColor: + v4value = QVariant(QMetaType::QColor, result.typeDataPtr()); + break; + case QMetaType::QVariant: + v4value = *result.getvariantptr(); + break; default: if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) { v4value = QVariant(QQmlMetaType::QQuickAnchorLineMetaTypeId(), result.typeDataPtr()); @@ -884,6 +888,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertBoolToString, unaryop) + QML_V4_BEGIN_INSTR(ConvertBoolToVariant, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + new (output.getvariantptr()) QVariant(src.getbool()); + VARIANT_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertBoolToVariant, unaryop) + QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -908,13 +925,26 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, Register &output = registers[instr->unaryop.output]; if (src.isUndefined()) { output.setUndefined(); - } else { + } else { new (output.getstringptr()) QString(QString::number(src.getint())); STRING_REGISTER(instr->unaryop.output); } } QML_V4_END_INSTR(ConvertIntToString, unaryop) + QML_V4_BEGIN_INSTR(ConvertIntToVariant, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + new (output.getvariantptr()) QVariant(src.getint()); + VARIANT_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertIntToVariant, unaryop) + QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -947,6 +977,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertNumberToString, unaryop) + QML_V4_BEGIN_INSTR(ConvertNumberToVariant, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + new (output.getvariantptr()) QVariant(src.getnumber()); + VARIANT_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertNumberToVariant, unaryop) + QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1049,6 +1092,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertStringToUrl, unaryop) + QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + const QString tmp(*src.getstringptr()); + if (instr->unaryop.src == instr->unaryop.output) { + output.cleanupString(); + MARK_CLEAN_REGISTER(instr->unaryop.output); + } + new (output.getvariantptr()) QVariant(tmp); + + VARIANT_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertStringToVariant, unaryop) + QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1086,6 +1148,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertUrlToString, unaryop) + QML_V4_BEGIN_INSTR(ConvertUrlToVariant, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + // ### NaN + if (src.isUndefined()) { + output.setUndefined(); + } else { + const QUrl tmp(*src.geturlptr()); + if (instr->unaryop.src == instr->unaryop.output) { + output.cleanupUrl(); + MARK_CLEAN_REGISTER(instr->unaryop.output); + } + new (output.getvariantptr()) QVariant(tmp); + VARIANT_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertUrlToVariant, unaryop) + QML_V4_BEGIN_INSTR(ConvertColorToBool, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1114,6 +1195,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertColorToString, unaryop) + QML_V4_BEGIN_INSTR(ConvertColorToVariant, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + // ### NaN + if (src.isUndefined()) { + output.setUndefined(); + } else { + QVariant tmp(QMetaType::QColor, src.typeDataPtr()); + if (instr->unaryop.src == instr->unaryop.output) { + output.cleanupColor(); + MARK_CLEAN_REGISTER(instr->unaryop.output); + } + new (output.getvariantptr()) QVariant(tmp); + VARIANT_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertColorToVariant, unaryop) + QML_V4_BEGIN_INSTR(ConvertObjectToBool, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1126,6 +1226,20 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertObjectToBool, unaryop) + QML_V4_BEGIN_INSTR(ConvertObjectToVariant, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + // ### NaN + if (src.isUndefined()) + output.setUndefined(); + else { + new (output.getvariantptr()) QVariant(qVariantFromValue<QObject *>(src.getQObject())); + VARIANT_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertObjectToVariant, unaryop) + QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop) { Register &output = registers[instr->unaryop.output]; @@ -1133,6 +1247,14 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertNullToObject, unaryop) + QML_V4_BEGIN_INSTR(ConvertNullToVariant, unaryop) + { + Register &output = registers[instr->unaryop.output]; + new (output.getvariantptr()) QVariant(); + VARIANT_REGISTER(instr->unaryop.output); + } + QML_V4_END_INSTR(ConvertNullToVariant, unaryop) + QML_V4_BEGIN_INSTR(ResolveUrl, unaryop) { const Register &src = registers[instr->unaryop.src]; diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp index 045a14fbb5..e03270cf1d 100644 --- a/src/qml/qml/v4/qv4compiler.cpp +++ b/src/qml/qml/v4/qv4compiler.cpp @@ -377,6 +377,9 @@ void QV4CompilerPrivate::visitName(IR::Name *e) case QMetaType::QColor: regType = QColorType; break; + case QMetaType::QVariant: + regType = QVariantType; + break; default: if (propTy == QQmlMetaType::QQuickAnchorLineMetaTypeId()) { @@ -966,6 +969,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) switch (targetTy) { case IR::BoolType: case IR::StringType: + case IR::VariantType: // nothing to do. V4 will generate optimized // url-to-xxx conversions. break; @@ -1068,6 +1072,20 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) case IR::NullType: opcode = V4Instr::ConvertNullToObject; break; default: break; } // switch + } else if (targetTy == IR::VariantType) { + if (s->isMoveForReturn) { + switch (sourceTy) { + case IR::BoolType: opcode = V4Instr::ConvertBoolToVariant; break; + case IR::IntType: opcode = V4Instr::ConvertIntToVariant; break; + case IR::NumberType: opcode = V4Instr::ConvertNumberToVariant; break; + case IR::UrlType: opcode = V4Instr::ConvertUrlToVariant; break; + case IR::ColorType: opcode = V4Instr::ConvertColorToVariant; break; + case IR::StringType: opcode = V4Instr::ConvertStringToVariant; break; + case IR::ObjectType: opcode = V4Instr::ConvertObjectToVariant; break; + case IR::NullType: opcode = V4Instr::ConvertNullToVariant; break; + default: break; + } // switch + } } if (opcode != V4Instr::Noop) { V4Instr conv; @@ -1141,6 +1159,9 @@ void QV4CompilerPrivate::visitRet(IR::Ret *s) case IR::ObjectType: test.regType = QMetaType::QObjectStar; break; + case IR::VariantType: + test.regType = QMetaType::QVariant; + break; case IR::BoolType: test.regType = QMetaType::Bool; break; diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp index ecd4f01ef3..c20297975d 100644 --- a/src/qml/qml/v4/qv4instruction.cpp +++ b/src/qml/qml/v4/qv4instruction.cpp @@ -144,6 +144,9 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertBoolToString: INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertBoolToVariant: + INSTR_DUMP << "\t" << "ConvertBoolToVariant" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ConvertIntToBool: INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; @@ -153,6 +156,9 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertIntToString: INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertIntToVariant: + INSTR_DUMP << "\t" << "ConvertIntToVariant" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ConvertNumberToBool: INSTR_DUMP << "\t" << "ConvertNumberToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; @@ -162,6 +168,9 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertNumberToString: INSTR_DUMP << "\t" << "ConvertNumberToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertNumberToVariant: + INSTR_DUMP << "\t" << "ConvertNumberToVariant" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ConvertStringToBool: INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; @@ -177,24 +186,39 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertStringToColor: INSTR_DUMP << "\t" << "ConvertStringToColor" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertStringToVariant: + INSTR_DUMP << "\t" << "ConvertStringToVariant" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ConvertUrlToBool: INSTR_DUMP << "\t" << "ConvertUrlToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::ConvertUrlToString: INSTR_DUMP << "\t" << "ConvertUrlToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertUrlToVariant: + INSTR_DUMP << "\t" << "ConvertUrlToVariant" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ConvertColorToBool: INSTR_DUMP << "\t" << "ConvertColorToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::ConvertColorToString: INSTR_DUMP << "\t" << "ConvertColorToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertColorToVariant: + INSTR_DUMP << "\t" << "ConvertColorToVariant" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ConvertObjectToBool: INSTR_DUMP << "\t" << "ConvertObjectToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertObjectToVariant: + INSTR_DUMP << "\t" << "ConvertObjectToVariant" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ConvertNullToObject: INSTR_DUMP << "\t" << "ConvertNullToObject" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertNullToVariant: + INSTR_DUMP << "\t" << "ConvertNullToVariant" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ResolveUrl: INSTR_DUMP << "\t" << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h index 310bfbaff5..6eb9efa50f 100644 --- a/src/qml/qml/v4/qv4instruction_p.h +++ b/src/qml/qml/v4/qv4instruction_p.h @@ -83,23 +83,31 @@ QT_BEGIN_NAMESPACE F(ConvertBoolToInt, unaryop) \ F(ConvertBoolToNumber, unaryop) \ F(ConvertBoolToString, unaryop) \ + F(ConvertBoolToVariant, unaryop) \ F(ConvertIntToBool, unaryop) \ F(ConvertIntToNumber, unaryop) \ F(ConvertIntToString, unaryop) \ + F(ConvertIntToVariant, unaryop) \ F(ConvertNumberToBool, unaryop) \ F(ConvertNumberToInt, unaryop) \ F(ConvertNumberToString, unaryop) \ + F(ConvertNumberToVariant, unaryop) \ F(ConvertStringToBool, unaryop) \ F(ConvertStringToInt, unaryop) \ F(ConvertStringToNumber, unaryop) \ F(ConvertStringToUrl, unaryop) \ F(ConvertStringToColor, unaryop) \ + F(ConvertStringToVariant, unaryop) \ F(ConvertUrlToBool, unaryop) \ F(ConvertUrlToString, unaryop) \ + F(ConvertUrlToVariant, unaryop) \ F(ConvertColorToBool, unaryop) \ F(ConvertColorToString, unaryop) \ + F(ConvertColorToVariant, unaryop) \ F(ConvertObjectToBool, unaryop) \ + F(ConvertObjectToVariant, unaryop) \ F(ConvertNullToObject, unaryop) \ + F(ConvertNullToVariant, unaryop) \ F(ResolveUrl, unaryop) \ F(MathSinNumber, unaryop) \ F(MathCosNumber, unaryop) \ diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp index ba0faec80e..45e909f54b 100644 --- a/src/qml/qml/v4/qv4ir.cpp +++ b/src/qml/qml/v4/qv4ir.cpp @@ -63,6 +63,8 @@ const char *typeName(Type t) case SGAnchorLineType: return "SGAnchorLine"; case AttachType: return "AttachType"; case ObjectType: return "object"; + case VariantType: return "variant"; + case VarType: return "var"; case BoolType: return "bool"; case IntType: return "int"; case FloatType: return "float"; diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h index 26bd43c406..254b810403 100644 --- a/src/qml/qml/v4/qv4ir_p.h +++ b/src/qml/qml/v4/qv4ir_p.h @@ -146,6 +146,8 @@ enum Type { SGAnchorLineType, AttachType, ObjectType, + VariantType, + VarType, FirstNumberType, BoolType = FirstNumberType, diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp index 31ed9a5a6a..82da09f485 100644 --- a/src/qml/qml/v4/qv4irbuilder.cpp +++ b/src/qml/qml/v4/qv4irbuilder.cpp @@ -116,8 +116,16 @@ bool QV4IRBuilder::operator()(QQmlJS::IR::Function *function, //_block->MOVE(_block->TEMP(IR::InvalidType), r.code); if (r.code) { - const QMetaObject *m = 0; - const IR::Type targetType = irTypeFromVariantType(m_expression->property->type, m_engine, m); + IR::Type targetType = IR::InvalidType; + + // This is the only operation where variant is supported: + QQmlPropertyData *data = &m_expression->property->core; + if (data->propType == QMetaType::QVariant) { + targetType = (data->isVMEProperty() ? IR::VarType : IR::VariantType); + } else { + targetType = irTypeFromVariantType(data->propType, m_engine, 0); + } + if (targetType != r.type()) { IR::Expr *x = _block->TEMP(targetType); _block->MOVE(x, r, true); diff --git a/src/qml/qml/v8/qjsconverter_impl_p.h b/src/qml/qml/v8/qjsconverter_impl_p.h index c2775df7f5..ab004a543e 100644 --- a/src/qml/qml/v8/qjsconverter_impl_p.h +++ b/src/qml/qml/v8/qjsconverter_impl_p.h @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qjsconverter_p.h" +#include <stdlib.h> #ifndef QJSCONVERTER_IMPL_P_H #define QJSCONVERTER_IMPL_P_H diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index 9a5aaca6e4..176d4fb76f 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -301,8 +301,8 @@ static v8::Handle<v8::Value> GenericValueGetter(v8::Local<v8::String>, const v8: #define FAST_GETTER_FUNCTION(property, cpptype) \ (property->hasAccessors()?((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Accessor>):(property->isDirect()?((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Direct>):((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Indirect>))) -static quint32 toStringHash = -1; -static quint32 destroyHash = -1; +static quint32 toStringHash = quint32(-1); +static quint32 destroyHash = quint32(-1); void QV8QObjectWrapper::init(QV8Engine *engine) { diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro index 157cfe97c0..3e3adaba99 100644 --- a/src/qmltest/qmltest.pro +++ b/src/qmltest/qmltest.pro @@ -4,7 +4,7 @@ TARGET = QtQuickTest QPRO_PWD = $$PWD CONFIG += module -CONFIG += dll warn_on declarative_debug +CONFIG += dll warn_on MODULE_PRI += ../../modules/qt_qmltest.pri QT += testlib testlib-private qml quick gui @@ -33,4 +33,4 @@ HEADERS += \ $$PWD/qtestoptions_p.h -DEFINES += QT_BUILD_QUICK_TEST_LIB
\ No newline at end of file +DEFINES += QT_BUILD_QUICK_TEST_LIB QT_QML_DEBUG_NO_WARNING
\ No newline at end of file diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index 3f08c8f056..a288531beb 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -330,6 +330,7 @@ void QQuickCanvasPrivate::init(QQuickCanvas *c) Q_Q(QQuickCanvas); rootItem = new QQuickRootItem; + QQmlEngine::setObjectOwnership(rootItem, QQmlEngine::CppOwnership); QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem); rootItemPrivate->canvas = q; rootItemPrivate->canvasRefCount = 1; diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index 1fab4a8c99..0518fccd10 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -92,7 +92,7 @@ public: } qreal size() const { - return view->flow() == QQuickGridView::LeftToRight ? view->cellHeight() : view->cellWidth(); + return view->flow() == QQuickGridView::FlowLeftToRight ? view->cellHeight() : view->cellWidth(); } qreal sectionSize() const { @@ -100,14 +100,14 @@ public: } qreal rowPos() const { - if (view->flow() == QQuickGridView::LeftToRight) - return itemY(); + if (view->flow() == QQuickGridView::FlowLeftToRight) + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -view->cellHeight()-itemY() : itemY()); else return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -view->cellWidth()-itemX() : itemX()); } qreal colPos() const { - if (view->flow() == QQuickGridView::LeftToRight) { + if (view->flow() == QQuickGridView::FlowLeftToRight) { if (view->effectiveLayoutDirection() == Qt::RightToLeft) { qreal colSize = view->cellWidth(); int columns = view->width()/colSize; @@ -116,12 +116,19 @@ public: return itemX(); } } else { - return itemY(); + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) { + return -view->cellHeight() - itemY(); + } else { + return itemY(); + } } } qreal endRowPos() const { - if (view->flow() == QQuickGridView::LeftToRight) { - return itemY() + view->cellHeight(); + if (view->flow() == QQuickGridView::FlowLeftToRight) { + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) + return -itemY(); + else + return itemY() + view->cellHeight(); } else { if (view->effectiveLayoutDirection() == Qt::RightToLeft) return -itemX(); @@ -141,19 +148,24 @@ public: private: QPointF pointForPosition(qreal col, qreal row) const { - if (view->effectiveLayoutDirection() == Qt::RightToLeft) { - if (view->flow() == QQuickGridView::LeftToRight) { + qreal x; + qreal y; + if (view->flow() == QQuickGridView::FlowLeftToRight) { + x = col; + y = row; + if (view->effectiveLayoutDirection() == Qt::RightToLeft) { int columns = view->width()/view->cellWidth(); - return QPointF(view->cellWidth() * (columns-1) - col, row); - } else { - return QPointF(-view->cellWidth() - row, col); + x = view->cellWidth() * (columns-1) - col; } } else { - if (view->flow() == QQuickGridView::LeftToRight) - return QPointF(col, row); - else - return QPointF(row, col); + x = row; + y = col; + if (view->effectiveLayoutDirection() == Qt::RightToLeft) + x = -view->cellWidth() - row; } + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) + y = -view->cellHeight() - y; + return QPointF(x, y); } }; @@ -166,7 +178,6 @@ class QQuickGridViewPrivate : public QQuickItemViewPrivate public: virtual Qt::Orientation layoutOrientation() const; virtual bool isContentFlowReversed() const; - bool isRightToLeftTopToBottom() const; virtual qreal positionAt(int index) const; virtual qreal endPositionAt(int index) const; @@ -180,6 +191,8 @@ public: qreal snapPosAt(qreal pos) const; FxViewItem *snapItemAt(qreal pos) const; int snapIndex() const; + qreal contentXForPosition(qreal pos) const; + qreal contentYForPosition(qreal pos) const; void resetColumns(); @@ -229,7 +242,7 @@ public: QSmoothedAnimation *highlightYAnimator; QQuickGridViewPrivate() - : flow(QQuickGridView::LeftToRight) + : flow(QQuickGridView::FlowLeftToRight) , cellWidth(100), cellHeight(100), columns(1) , snapMode(QQuickGridView::NoSnap) , highlightXAnimator(0), highlightYAnimator(0) @@ -243,18 +256,15 @@ public: Qt::Orientation QQuickGridViewPrivate::layoutOrientation() const { - return flow == QQuickGridView::LeftToRight ? Qt::Vertical : Qt::Horizontal; + return flow == QQuickGridView::FlowLeftToRight ? Qt::Vertical : Qt::Horizontal; } bool QQuickGridViewPrivate::isContentFlowReversed() const { - return isRightToLeftTopToBottom(); -} - -bool QQuickGridViewPrivate::isRightToLeftTopToBottom() const -{ Q_Q(const QQuickGridView); - return flow == QQuickGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft; + + return (flow == QQuickGridView::FlowLeftToRight && verticalLayoutDirection == QQuickItemView::BottomToTop) + || (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft); } void QQuickGridViewPrivate::changedVisibleIndex(int newIndex) @@ -265,16 +275,8 @@ void QQuickGridViewPrivate::changedVisibleIndex(int newIndex) void QQuickGridViewPrivate::setPosition(qreal pos) { Q_Q(QQuickGridView); - if (flow == QQuickGridView::LeftToRight) { - q->QQuickFlickable::setContentY(pos); - q->QQuickFlickable::setContentX(0); - } else { - if (q->effectiveLayoutDirection() == Qt::LeftToRight) - q->QQuickFlickable::setContentX(pos); - else - q->QQuickFlickable::setContentX(-pos-size()); - q->QQuickFlickable::setContentY(0); - } + q->QQuickFlickable::setContentX(contentXForPosition(pos)); + q->QQuickFlickable::setContentY(contentYForPosition(pos)); } qreal QQuickGridViewPrivate::originPosition() const @@ -306,10 +308,10 @@ qreal QQuickGridViewPrivate::endPositionAt(int index) const } qreal QQuickGridViewPrivate::rowSize() const { - return flow == QQuickGridView::LeftToRight ? cellHeight : cellWidth; + return flow == QQuickGridView::FlowLeftToRight ? cellHeight : cellWidth; } qreal QQuickGridViewPrivate::colSize() const { - return flow == QQuickGridView::LeftToRight ? cellWidth : cellHeight; + return flow == QQuickGridView::FlowLeftToRight ? cellWidth : cellHeight; } qreal QQuickGridViewPrivate::colPosAt(int modelIndex) const @@ -375,12 +377,12 @@ qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const snapPos -= highlightStart; qreal maxExtent; qreal minExtent; - if (isRightToLeftTopToBottom()) { + if (isContentFlowReversed()) { maxExtent = q->minXExtent()-size(); minExtent = q->maxXExtent()-size(); } else { - maxExtent = flow == QQuickGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent(); - minExtent = flow == QQuickGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent(); + maxExtent = flow == QQuickGridView::FlowLeftToRight ? -q->maxYExtent() : -q->maxXExtent(); + minExtent = flow == QQuickGridView::FlowLeftToRight ? -q->minYExtent() : -q->minXExtent(); } if (snapPos > maxExtent) snapPos = maxExtent; @@ -421,10 +423,49 @@ int QQuickGridViewPrivate::snapIndex() const return index; } +qreal QQuickGridViewPrivate::contentXForPosition(qreal pos) const +{ + Q_Q(const QQuickGridView); + if (flow == QQuickGridView::FlowLeftToRight) { + // vertical scroll + if (q->effectiveLayoutDirection() == Qt::LeftToRight) { + return 0; + } else { + qreal colSize = cellWidth; + int columns = q->width()/colSize; + return -q->width() + (cellWidth * columns); + } + } else { + // horizontal scroll + if (q->effectiveLayoutDirection() == Qt::LeftToRight) + return pos; + else + return -pos - q->width(); + } +} + +qreal QQuickGridViewPrivate::contentYForPosition(qreal pos) const +{ + Q_Q(const QQuickGridView); + if (flow == QQuickGridView::FlowLeftToRight) { + // vertical scroll + if (verticalLayoutDirection == QQuickItemView::TopToBottom) + return pos; + else + return -pos - q->height(); + } else { + // horizontal scroll + if (verticalLayoutDirection == QQuickItemView::TopToBottom) + return 0; + else + return -q->height(); + } +} + void QQuickGridViewPrivate::resetColumns() { Q_Q(QQuickGridView); - qreal length = flow == QQuickGridView::LeftToRight ? q->width() : q->height(); + qreal length = flow == QQuickGridView::FlowLeftToRight ? q->width() : q->height(); columns = (int)qMax((length + colSize()/2) / colSize(), qreal(1.)); } @@ -641,15 +682,22 @@ void QQuickGridViewPrivate::repositionPackageItemAt(QQuickItem *item, int index) { Q_Q(QQuickGridView); qreal pos = position(); - if (flow == QQuickGridView::LeftToRight) { - if (item->y() + item->height() > pos && item->y() < pos + q->height()) - item->setPos(QPointF(colPosAt(index), rowPosAt(index))); + if (flow == QQuickGridView::FlowLeftToRight) { + if (item->y() + item->height() > pos && item->y() < pos + q->height()) { + qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom) + ? rowPosAt(index) + : -rowPosAt(index) - item->height(); + item->setPos(QPointF(colPosAt(index), y)); + } } else { if (item->x() + item->width() > pos && item->x() < pos + q->width()) { - if (isRightToLeftTopToBottom()) - item->setPos(QPointF(-rowPosAt(index)-item->width(), colPosAt(index))); + qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom) + ? colPosAt(index) + : -colPosAt(index) - item->height(); + if (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft) + item->setPos(QPointF(-rowPosAt(index)-item->width(), y)); else - item->setPos(QPointF(rowPosAt(index), colPosAt(index))); + item->setPos(QPointF(rowPosAt(index), y)); } } } @@ -744,14 +792,14 @@ qreal QQuickGridViewPrivate::headerSize() const { if (!header) return 0.0; - return flow == QQuickGridView::LeftToRight ? header->item->height() : header->item->width(); + return flow == QQuickGridView::FlowLeftToRight ? header->item->height() : header->item->width(); } qreal QQuickGridViewPrivate::footerSize() const { if (!footer) return 0.0; - return flow == QQuickGridView::LeftToRight? footer->item->height() : footer->item->width(); + return flow == QQuickGridView::FlowLeftToRight? footer->item->height() : footer->item->width(); } bool QQuickGridViewPrivate::showHeaderForIndex(int index) const @@ -781,17 +829,23 @@ void QQuickGridViewPrivate::updateFooter() qreal colOffset = 0; qreal rowOffset = 0; if (q->effectiveLayoutDirection() == Qt::RightToLeft) { - if (flow == QQuickGridView::TopToBottom) - rowOffset = gridItem->item->width() - cellWidth; + if (flow == QQuickGridView::FlowTopToBottom) + rowOffset += gridItem->item->width() - cellWidth; + else + colOffset += gridItem->item->width() - cellWidth; + } + if (verticalLayoutDirection == QQuickItemView::BottomToTop) { + if (flow == QQuickGridView::FlowTopToBottom) + colOffset += gridItem->item->height() - cellHeight; else - colOffset = gridItem->item->width() - cellWidth; + rowOffset += gridItem->item->height() - cellHeight; } if (visibleItems.count()) { qreal endPos = lastPosition(); if (findLastVisibleIndex() == model->count()-1) { gridItem->setPosition(colOffset, endPos + rowOffset); } else { - qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size(); + qreal visiblePos = isContentFlowReversed() ? -position() : position() + size(); if (endPos <= visiblePos || gridItem->endPosition() <= endPos + rowOffset) gridItem->setPosition(colOffset, endPos + rowOffset); } @@ -820,23 +874,29 @@ void QQuickGridViewPrivate::updateHeader() qreal colOffset = 0; qreal rowOffset = -headerSize(); if (q->effectiveLayoutDirection() == Qt::RightToLeft) { - if (flow == QQuickGridView::TopToBottom) - rowOffset += gridItem->item->width()-cellWidth; + if (flow == QQuickGridView::FlowTopToBottom) + rowOffset += gridItem->item->width() - cellWidth; + else + colOffset += gridItem->item->width() - cellWidth; + } + if (verticalLayoutDirection == QQuickItemView::BottomToTop) { + if (flow == QQuickGridView::FlowTopToBottom) + colOffset += gridItem->item->height() - cellHeight; else - colOffset = gridItem->item->width()-cellWidth; + rowOffset += gridItem->item->height() - cellHeight; } if (visibleItems.count()) { qreal startPos = originPosition(); if (visibleIndex == 0) { gridItem->setPosition(colOffset, startPos + rowOffset); } else { - qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position(); - qreal headerPos = isRightToLeftTopToBottom() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos(); + qreal tempPos = isContentFlowReversed() ? -position()-size() : position(); + qreal headerPos = isContentFlowReversed() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos(); if (tempPos <= startPos || headerPos > startPos + rowOffset) gridItem->setPosition(colOffset, startPos + rowOffset); } } else { - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) gridItem->setPosition(colOffset, rowOffset); else gridItem->setPosition(colOffset, -headerSize()); @@ -861,7 +921,7 @@ void QQuickGridViewPrivate::initializeCurrentItem() void QQuickGridViewPrivate::fixupPosition() { moveReason = Other; - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) fixupY(); else fixupX(); @@ -869,17 +929,17 @@ void QQuickGridViewPrivate::fixupPosition() void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) { - if ((flow == QQuickGridView::TopToBottom && &data == &vData) - || (flow == QQuickGridView::LeftToRight && &data == &hData)) + if ((flow == QQuickGridView::FlowTopToBottom && &data == &vData) + || (flow == QQuickGridView::FlowLeftToRight && &data == &hData)) return; fixupMode = moveReason == Mouse ? fixupMode : Immediate; - qreal viewPos = isRightToLeftTopToBottom() ? -position()-size() : position(); + qreal viewPos = isContentFlowReversed() ? -position()-size() : position(); bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange; if (snapMode != QQuickGridView::NoSnap) { - qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position(); + qreal tempPosition = isContentFlowReversed() ? -position()-size() : position(); if (snapMode == QQuickGridView::SnapOneRow && moveReason == Mouse) { // if we've been dragged < rowSize()/2 then bias towards the next row qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); @@ -888,7 +948,7 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte bias = rowSize()/2; else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2) bias = -rowSize()/2; - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) bias = -bias; tempPosition -= bias; } @@ -909,15 +969,15 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte if (topItem && (isInBounds || strictHighlightRange)) { qreal headerPos = header ? static_cast<FxGridItemSG*>(header)->rowPos() : 0; if (topItem->index == 0 && header && tempPosition+highlightRangeStart < headerPos+headerSize()/2 && !strictHighlightRange) { - pos = isRightToLeftTopToBottom() ? - headerPos + highlightRangeStart - size() : headerPos - highlightRangeStart; + pos = isContentFlowReversed() ? - headerPos + highlightRangeStart - size() : headerPos - highlightRangeStart; } else { - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent); else pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent); } } else if (bottomItem && isInBounds) { - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent); else pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent); @@ -945,7 +1005,7 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte viewPos = pos + rowSize() - highlightRangeEnd; if (viewPos > pos - highlightRangeStart) viewPos = pos - highlightRangeStart; - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) viewPos = -viewPos-size(); timeline.reset(data.move); if (viewPos != position()) { @@ -977,7 +1037,7 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte return; } qreal maxDistance = 0; - qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value(); + qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value(); // -ve velocity means list is moving up/left if (velocity > 0) { if (data.move.value() < minExtent) { @@ -985,7 +1045,7 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0; - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) bias = -bias; data.flickTarget = -snapPosAt(-dataValue - bias); maxDistance = qAbs(data.flickTarget - data.move.value()); @@ -1002,7 +1062,7 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0; - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) bias = -bias; data.flickTarget = -snapPosAt(-dataValue + bias); maxDistance = qAbs(data.flickTarget - data.move.value()); @@ -1034,10 +1094,10 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte if (v > 0) dist = -dist; if (snapMode != QQuickGridView::SnapOneRow) { - qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist; + qreal distTemp = isContentFlowReversed() ? -dist : dist; data.flickTarget = -snapPosAt(-dataValue + distTemp); } - data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget; + data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget; if (overShoot) { if (data.flickTarget >= minExtent) { overshootDist = overShootDistance(vSize); @@ -1159,6 +1219,60 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte to set this property to true in order to clip the items that are partially or fully outside the view. + + \section1 GridView layouts + + The layout of the items in a GridView can be controlled by these properties: + + \list + \li \l flow - controls whether items flow from left to right (as a series of rows) + or from top to bottom (as a series of columns). This value can be either + GridView.LeftToRight or GridView.TopToBottom. + \li \l layoutDirection - controls the horizontal layout direction: that is, whether items + are laid out from the left side of the view to the right, or vice-versa. This value can + be either Qt.LeftToRight or Qt.RightToLeft. + \li \l verticalLayoutDirection - controls the vertical layout direction: that is, whether items + are laid out from the top of the view down towards the bottom of the view, or vice-versa. + This value can be either GridView.TopToBottom or GridView.BottomToTop. + \endlist + + By default, a GridView flows from left to right, and items are laid out from left to right + horizontally, and from top to bottom vertically. + + These properties can be combined to produce a variety of layouts, as shown in the table below. + The GridViews in the first row all have a \l flow value of GridView.LeftToRight, but use + different combinations of horizontal and vertical layout directions (specified by \l layoutDirection + and \l verticalLayoutDirection respectively). Similarly, the GridViews in the second row below + all have a \l flow value of GridView.TopToBottom, but use different combinations of horizontal and + vertical layout directions to lay out their items in different ways. + + \table + \header + \li {4, 1} + \bold GridViews with GridView.LeftToRight flow + \row + \li \bold (H) Left to right \bold (V) Top to bottom + \image gridview-layout-lefttoright-ltr-ttb.png + \li \bold (H) Right to left \bold (V) Top to bottom + \image gridview-layout-lefttoright-rtl-ttb.png + \li \bold (H) Left to right \bold (V) Bottom to top + \image gridview-layout-lefttoright-ltr-btt.png + \li \bold (H) Right to left \bold (V) Bottom to top + \image gridview-layout-lefttoright-rtl-btt.png + \header + \li {4, 1} + \bold GridViews with GridView.TopToBottom flow + \row + \li \bold (H) Left to right \bold (V) Top to bottom + \image gridview-layout-toptobottom-ltr-ttb.png + \li \bold (H) Right to left \bold (V) Top to bottom + \image gridview-layout-toptobottom-rtl-ttb.png + \li \bold (H) Left to right \bold (V) Bottom to top + \image gridview-layout-toptobottom-ltr-btt.png + \li \bold (H) Right to left \bold (V) Bottom to top + \image gridview-layout-toptobottom-rtl-btt.png + \endtable + \sa {declarative/modelviews/gridview}{GridView example} */ @@ -1380,6 +1494,8 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight) \b Note: If GridView::flow is set to GridView.LeftToRight, this is not to be confused if GridView::layoutDirection is set to Qt.RightToLeft. The GridView.LeftToRight flow value simply indicates that the flow is horizontal. + + \sa GridView::effectiveLayoutDirection, GridView::verticalLayoutDirection */ @@ -1393,6 +1509,21 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight) \sa GridView::layoutDirection, {LayoutMirroring}{LayoutMirroring} */ + +/*! + \qmlproperty enumeration QtQuick2::GridView::verticalLayoutDirection + This property holds the vertical layout direction of the grid. + + Possible values: + + \list + \li GridView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view. + \li GridView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view. + \endlist + + \sa GridView::layoutDirection +*/ + /*! \qmlproperty bool QtQuick2::GridView::keyNavigationWraps This property holds whether the grid wraps key navigation @@ -1461,7 +1592,7 @@ void QQuickGridView::setFlow(Flow flow) Q_D(QQuickGridView); if (d->flow != flow) { d->flow = flow; - if (d->flow == LeftToRight) { + if (d->flow == FlowLeftToRight) { setContentWidth(-1); setFlickableDirection(VerticalFlick); } else { @@ -1877,14 +2008,19 @@ void QQuickGridView::viewportMoved() return; d->inViewportMoved = true; - if (yflick()) - d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter; - else if (d->isRightToLeftTopToBottom()) - d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore; - else - d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter; + if (yflick()) { + if (d->isContentFlowReversed()) + d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore; + else + d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter; + } else { + if (d->isContentFlowReversed()) + d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore; + else + d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter; + } - d->refill(); + d->refillOrLayout(); // Set visibility of items to eliminate cost of items outside the visible area. qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position(); @@ -1904,7 +2040,7 @@ void QQuickGridView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->position(); - qreal viewPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size() : d->position(); + qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position(); if (pos > viewPos + d->highlightRangeEnd - d->highlight->size()) pos = viewPos + d->highlightRangeEnd - d->highlight->size(); if (pos < viewPos + d->highlightRangeStart) @@ -1923,7 +2059,7 @@ void QQuickGridView::viewportMoved() if (idx >= 0 && idx != d->currentIndex) { d->updateCurrent(idx); if (d->currentItem && static_cast<FxGridItemSG*>(d->currentItem)->colPos() != static_cast<FxGridItemSG*>(d->highlight)->colPos() && d->autoHighlight) { - if (d->flow == LeftToRight) + if (d->flow == FlowLeftToRight) d->highlightXAnimator->to = d->currentItem->itemX(); else d->highlightYAnimator->to = d->currentItem->itemY(); @@ -1970,6 +2106,16 @@ void QQuickGridView::geometryChanged(const QRectF &newGeometry, const QRectF &ol { Q_D(QQuickGridView); d->resetColumns(); + + if (newGeometry.width() != oldGeometry.width() + && newGeometry.height() != oldGeometry.height()) { + d->setPosition(d->position()); + } else if (newGeometry.width() != oldGeometry.width()) { + QQuickFlickable::setContentX(d->contentXForPosition(d->position())); + } else if (newGeometry.height() != oldGeometry.height()) { + QQuickFlickable::setContentY(d->contentYForPosition(d->position())); + } + QQuickItemView::geometryChanged(newGeometry, oldGeometry); } @@ -1990,15 +2136,29 @@ void QQuickGridView::moveCurrentIndexUp() const int count = d->model ? d->model->count() : 0; if (!count) return; - if (d->flow == QQuickGridView::LeftToRight) { - if (currentIndex() >= d->columns || d->wrap) { - int index = currentIndex() - d->columns; - setCurrentIndex((index >= 0 && index < count) ? index : count-1); + if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) { + if (d->flow == QQuickGridView::FlowLeftToRight) { + if (currentIndex() >= d->columns || d->wrap) { + int index = currentIndex() - d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } + } else { + if (currentIndex() > 0 || d->wrap) { + int index = currentIndex() - 1; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } } } else { - if (currentIndex() > 0 || d->wrap) { - int index = currentIndex() - 1; - setCurrentIndex((index >= 0 && index < count) ? index : count-1); + if (d->flow == QQuickGridView::FlowLeftToRight) { + if (currentIndex() < count - d->columns || d->wrap) { + int index = currentIndex()+d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } + } else { + if (currentIndex() < count - 1 || d->wrap) { + int index = currentIndex() + 1; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } } } } @@ -2018,15 +2178,30 @@ void QQuickGridView::moveCurrentIndexDown() const int count = d->model ? d->model->count() : 0; if (!count) return; - if (d->flow == QQuickGridView::LeftToRight) { - if (currentIndex() < count - d->columns || d->wrap) { - int index = currentIndex()+d->columns; - setCurrentIndex((index >= 0 && index < count) ? index : 0); + + if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) { + if (d->flow == QQuickGridView::FlowLeftToRight) { + if (currentIndex() < count - d->columns || d->wrap) { + int index = currentIndex()+d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } + } else { + if (currentIndex() < count - 1 || d->wrap) { + int index = currentIndex() + 1; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } } } else { - if (currentIndex() < count - 1 || d->wrap) { - int index = currentIndex() + 1; - setCurrentIndex((index >= 0 && index < count) ? index : 0); + if (d->flow == QQuickGridView::FlowLeftToRight) { + if (currentIndex() >= d->columns || d->wrap) { + int index = currentIndex() - d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } + } else { + if (currentIndex() > 0 || d->wrap) { + int index = currentIndex() - 1; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } } } } @@ -2047,7 +2222,7 @@ void QQuickGridView::moveCurrentIndexLeft() if (!count) return; if (effectiveLayoutDirection() == Qt::LeftToRight) { - if (d->flow == QQuickGridView::LeftToRight) { + if (d->flow == QQuickGridView::FlowLeftToRight) { if (currentIndex() > 0 || d->wrap) { int index = currentIndex() - 1; setCurrentIndex((index >= 0 && index < count) ? index : count-1); @@ -2059,7 +2234,7 @@ void QQuickGridView::moveCurrentIndexLeft() } } } else { - if (d->flow == QQuickGridView::LeftToRight) { + if (d->flow == QQuickGridView::FlowLeftToRight) { if (currentIndex() < count - 1 || d->wrap) { int index = currentIndex() + 1; setCurrentIndex((index >= 0 && index < count) ? index : 0); @@ -2090,7 +2265,7 @@ void QQuickGridView::moveCurrentIndexRight() if (!count) return; if (effectiveLayoutDirection() == Qt::LeftToRight) { - if (d->flow == QQuickGridView::LeftToRight) { + if (d->flow == QQuickGridView::FlowLeftToRight) { if (currentIndex() < count - 1 || d->wrap) { int index = currentIndex() + 1; setCurrentIndex((index >= 0 && index < count) ? index : 0); @@ -2102,7 +2277,7 @@ void QQuickGridView::moveCurrentIndexRight() } } } else { - if (d->flow == QQuickGridView::LeftToRight) { + if (d->flow == QQuickGridView::FlowLeftToRight) { if (currentIndex() > 0 || d->wrap) { int index = currentIndex() - 1; setCurrentIndex((index >= 0 && index < count) ? index : count-1); @@ -2146,7 +2321,7 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert & } } - qreal tempPos = isRightToLeftTopToBottom() ? -position()-size()+q->width()+1 : position(); + qreal tempPos = isContentFlowReversed() ? -position()-size()+q->width()+1 : position(); qreal colPos = 0; qreal rowPos = 0; int colNum = 0; diff --git a/src/quick/items/qquickgridview_p.h b/src/quick/items/qquickgridview_p.h index ac3c8f097d..789c6411a5 100644 --- a/src/quick/items/qquickgridview_p.h +++ b/src/quick/items/qquickgridview_p.h @@ -69,13 +69,17 @@ class Q_AUTOTEST_EXPORT QQuickGridView : public QQuickItemView Q_CLASSINFO("DefaultProperty", "data") public: + enum Flow { + FlowLeftToRight = LeftToRight, + FlowTopToBottom = TopToBottom + }; + QQuickGridView(QQuickItem *parent=0); ~QQuickGridView(); virtual void setHighlightFollowsCurrentItem(bool); virtual void setHighlightMoveDuration(int); - enum Flow { LeftToRight, TopToBottom }; Flow flow() const; void setFlow(Flow); diff --git a/src/quick/items/qquickimplicitsizeitem_p.h b/src/quick/items/qquickimplicitsizeitem_p.h index a6d58325d8..be2b479d7a 100644 --- a/src/quick/items/qquickimplicitsizeitem_p.h +++ b/src/quick/items/qquickimplicitsizeitem_p.h @@ -49,7 +49,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE class QQuickImplicitSizeItemPrivate; -class Q_AUTOTEST_EXPORT QQuickImplicitSizeItem : public QQuickItem +class Q_QUICK_EXPORT QQuickImplicitSizeItem : public QQuickItem { Q_OBJECT Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged) diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 209d30aa74..e70e923c4d 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -442,7 +442,7 @@ void QQuickItemView::setCacheBuffer(int b) d->buffer = b; if (isComponentComplete()) { d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter; - d->refill(); + d->refillOrLayout(); } emit cacheBufferChanged(); } @@ -475,6 +475,21 @@ Qt::LayoutDirection QQuickItemView::effectiveLayoutDirection() const return d->layoutDirection; } +QQuickItemView::VerticalLayoutDirection QQuickItemView::verticalLayoutDirection() const +{ + Q_D(const QQuickItemView); + return d->verticalLayoutDirection; +} + +void QQuickItemView::setVerticalLayoutDirection(VerticalLayoutDirection layoutDirection) +{ + Q_D(QQuickItemView); + if (d->verticalLayoutDirection != layoutDirection) { + d->verticalLayoutDirection = layoutDirection; + d->regenerate(); + emit verticalLayoutDirectionChanged(); + } +} QQmlComponent *QQuickItemView::header() const { @@ -818,7 +833,7 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) FxViewItem *item = visibleItem(idx); qreal maxExtent; if (layoutOrientation() == Qt::Vertical) - maxExtent = -q->maxYExtent(); + maxExtent = isContentFlowReversed() ? q->minYExtent()-size(): -q->maxYExtent(); else maxExtent = isContentFlowReversed() ? q->minXExtent()-size(): -q->maxXExtent(); if (!item) { @@ -864,7 +879,7 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) pos = qMin(pos, maxExtent); qreal minExtent; if (layoutOrientation() == Qt::Vertical) - minExtent = -q->minYExtent(); + minExtent = isContentFlowReversed() ? q->maxYExtent()-size(): -q->minYExtent(); else minExtent = isContentFlowReversed() ? q->maxXExtent()-size(): -q->minXExtent(); pos = qMax(pos, minExtent); @@ -948,6 +963,89 @@ int QQuickItemViewPrivate::findMoveKeyIndex(QQuickChangeSet::MoveKey key, const return -1; } +qreal QQuickItemViewPrivate::minExtentForAxis(const AxisData &axisData, bool forXAxis) const +{ + Q_Q(const QQuickItemView); + + qreal highlightStart; + qreal highlightEnd; + qreal endPositionFirstItem = 0; + qreal extent = -startPosition() + axisData.startMargin; + if (isContentFlowReversed()) { + if (model && model->count()) + endPositionFirstItem = positionAt(model->count()-1); + else + extent += headerSize(); + highlightStart = highlightRangeEndValid ? size() - highlightRangeEnd : size(); + highlightEnd = highlightRangeStartValid ? size() - highlightRangeStart : size(); + extent += footerSize(); + qreal maxExtentAlongAxis = forXAxis ? q->maxXExtent() : q->maxYExtent(); + if (extent < maxExtentAlongAxis) + extent = maxExtentAlongAxis; + } else { + endPositionFirstItem = endPositionAt(0); + highlightStart = highlightRangeStart; + highlightEnd = highlightRangeEnd; + extent += headerSize(); + } + if (haveHighlightRange && highlightRange == QQuickItemView::StrictlyEnforceRange) { + extent += highlightStart; + FxViewItem *firstItem = visibleItem(0); + if (firstItem) + extent -= firstItem->sectionSize(); + extent = isContentFlowReversed() + ? qMin(extent, endPositionFirstItem + highlightEnd) + : qMax(extent, -(endPositionFirstItem - highlightEnd)); + } + return extent; +} + +qreal QQuickItemViewPrivate::maxExtentForAxis(const AxisData &axisData, bool forXAxis) const +{ + Q_Q(const QQuickItemView); + + qreal highlightStart; + qreal highlightEnd; + qreal lastItemPosition = 0; + qreal extent = 0; + if (isContentFlowReversed()) { + highlightStart = highlightRangeEndValid ? size() - highlightRangeEnd : size(); + highlightEnd = highlightRangeStartValid ? size() - highlightRangeStart : size(); + lastItemPosition = endPosition(); + } else { + highlightStart = highlightRangeStart; + highlightEnd = highlightRangeEnd; + if (model && model->count()) + lastItemPosition = positionAt(model->count()-1); + } + if (!model || !model->count()) { + if (!isContentFlowReversed()) + maxExtent = header ? -headerSize() : 0; + extent += forXAxis ? q->width() : q->height(); + } else if (haveHighlightRange && highlightRange == QQuickItemView::StrictlyEnforceRange) { + extent = -(lastItemPosition - highlightStart); + if (highlightEnd != highlightStart) { + extent = isContentFlowReversed() + ? qMax(extent, -(endPosition() - highlightEnd)) + : qMin(extent, -(endPosition() - highlightEnd)); + } + } else { + extent = -(endPosition() - (forXAxis ? q->width() : q->height())); + } + if (isContentFlowReversed()) { + extent -= headerSize(); + extent -= axisData.endMargin; + } else { + extent -= footerSize(); + extent -= axisData.endMargin; + qreal minExtentAlongAxis = forXAxis ? q->minXExtent() : q->minYExtent(); + if (extent > minExtentAlongAxis) + extent = minExtentAlongAxis; + } + + return extent; +} + // for debugging only void QQuickItemViewPrivate::checkVisible() const { @@ -1075,7 +1173,7 @@ void QQuickItemView::animStopped() { Q_D(QQuickItemView); d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter; - d->refill(); + d->refillOrLayout(); if (d->haveHighlightRange && d->highlightRange == QQuickItemView::StrictlyEnforceRange) d->updateHighlight(); } @@ -1119,12 +1217,17 @@ void QQuickItemView::trackedPositionChanged() toItemEndPos -= startOffset; } else if (d->showFooterForIndex(d->currentIndex)) { qreal endOffset = d->footerSize(); - if (d->layoutOrientation() == Qt::Vertical) - endOffset += d->vData.endMargin; - else if (d->isContentFlowReversed()) - endOffset += d->hData.startMargin; - else - endOffset += d->hData.endMargin; + if (d->layoutOrientation() == Qt::Vertical) { + if (d->isContentFlowReversed()) + endOffset += d->vData.startMargin; + else + endOffset += d->vData.endMargin; + } else { + if (d->isContentFlowReversed()) + endOffset += d->hData.startMargin; + else + endOffset += d->hData.endMargin; + } trackedPos += endOffset; trackedEndPos += endOffset; toItemPos += endOffset; @@ -1166,7 +1269,6 @@ void QQuickItemView::geometryChanged(const QRectF &newGeometry, const QRectF &ol QQuickFlickable::geometryChanged(newGeometry, oldGeometry); } - qreal QQuickItemView::minYExtent() const { Q_D(const QQuickItemView); @@ -1174,15 +1276,7 @@ qreal QQuickItemView::minYExtent() const return QQuickFlickable::minYExtent(); if (d->vData.minExtentDirty) { - d->minExtent = d->vData.startMargin-d->startPosition(); - if (d->header) - d->minExtent += d->headerSize(); - if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->minExtent += d->highlightRangeStart; - if (d->visibleItem(0)) - d->minExtent -= d->visibleItem(0)->sectionSize(); - d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd)); - } + d->minExtent = d->minExtentForAxis(d->vData, false); d->vData.minExtentDirty = false; } @@ -1196,25 +1290,10 @@ qreal QQuickItemView::maxYExtent() const return height(); if (d->vData.maxExtentDirty) { - if (!d->model || !d->model->count()) { - d->maxExtent = d->header ? -d->headerSize() : 0; - d->maxExtent += height(); - } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart); - if (d->highlightRangeEnd != d->highlightRangeStart) - d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd)); - } else { - d->maxExtent = -(d->endPosition() - height()); - } - - if (d->footer) - d->maxExtent -= d->footerSize(); - d->maxExtent -= d->vData.endMargin; - qreal minY = minYExtent(); - if (d->maxExtent > minY) - d->maxExtent = minY; + d->maxExtent = d->maxExtentForAxis(d->vData, false); d->vData.maxExtentDirty = false; } + return d->maxExtent; } @@ -1225,35 +1304,7 @@ qreal QQuickItemView::minXExtent() const return QQuickFlickable::minXExtent(); if (d->hData.minExtentDirty) { - d->minExtent = -d->startPosition() + d->hData.startMargin; - qreal highlightStart; - qreal highlightEnd; - qreal endPositionFirstItem = 0; - if (d->isContentFlowReversed()) { - if (d->model && d->model->count()) - endPositionFirstItem = d->positionAt(d->model->count()-1); - else if (d->header) - d->minExtent += d->headerSize(); - highlightStart = d->highlightRangeEndValid ? d->size() - d->highlightRangeEnd : d->size(); - highlightEnd = d->highlightRangeStartValid ? d->size() - d->highlightRangeStart : d->size(); - if (d->footer) - d->minExtent += d->footerSize(); - qreal maxX = maxXExtent(); - if (d->minExtent < maxX) - d->minExtent = maxX; - } else { - endPositionFirstItem = d->endPositionAt(0); - highlightStart = d->highlightRangeStart; - highlightEnd = d->highlightRangeEnd; - if (d->header) - d->minExtent += d->headerSize(); - } - if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->minExtent += highlightStart; - d->minExtent = d->isContentFlowReversed() - ? qMin(d->minExtent, endPositionFirstItem + highlightEnd) - : qMax(d->minExtent, -(endPositionFirstItem - highlightEnd)); - } + d->minExtent = d->minExtentForAxis(d->hData, true); d->hData.minExtentDirty = false; } @@ -1267,46 +1318,7 @@ qreal QQuickItemView::maxXExtent() const return width(); if (d->hData.maxExtentDirty) { - qreal highlightStart; - qreal highlightEnd; - qreal lastItemPosition = 0; - d->maxExtent = 0; - if (d->isContentFlowReversed()) { - highlightStart = d->highlightRangeEndValid ? d->size() - d->highlightRangeEnd : d->size(); - highlightEnd = d->highlightRangeStartValid ? d->size() - d->highlightRangeStart : d->size(); - lastItemPosition = d->endPosition(); - } else { - highlightStart = d->highlightRangeStart; - highlightEnd = d->highlightRangeEnd; - if (d->model && d->model->count()) - lastItemPosition = d->positionAt(d->model->count()-1); - } - if (!d->model || !d->model->count()) { - if (!d->isContentFlowReversed()) - d->maxExtent = d->header ? -d->headerSize() : 0; - d->maxExtent += width(); - } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->maxExtent = -(lastItemPosition - highlightStart); - if (highlightEnd != highlightStart) { - d->maxExtent = d->isContentFlowReversed() - ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd)) - : qMin(d->maxExtent, -(d->endPosition() - highlightEnd)); - } - } else { - d->maxExtent = -(d->endPosition() - width()); - } - if (d->isContentFlowReversed()) { - if (d->header) - d->maxExtent -= d->headerSize(); - d->maxExtent -= d->hData.endMargin; - } else { - if (d->footer) - d->maxExtent -= d->footerSize(); - d->maxExtent -= d->hData.endMargin; - qreal minX = minXExtent(); - if (d->maxExtent > minX) - d->maxExtent = minX; - } + d->maxExtent = d->maxExtentForAxis(d->hData, true); d->hData.maxExtentDirty = false; } @@ -1338,6 +1350,15 @@ qreal QQuickItemView::xOrigin() const return -minXExtent() + d->hData.startMargin; } +qreal QQuickItemView::yOrigin() const +{ + Q_D(const QQuickItemView); + if (d->isContentFlowReversed()) + return -maxYExtent() + d->size() - d->vData.endMargin; + else + return -minYExtent() + d->vData.startMargin; +} + void QQuickItemView::updatePolish() { Q_D(QQuickItemView); @@ -1385,7 +1406,7 @@ void QQuickItemView::componentComplete() QQuickItemViewPrivate::QQuickItemViewPrivate() : itemCount(0) , buffer(0), bufferMode(BufferBefore | BufferAfter) - , layoutDirection(Qt::LeftToRight) + , layoutDirection(Qt::LeftToRight), verticalLayoutDirection(QQuickItemView::TopToBottom) , moveReason(Other) , visibleIndex(0) , currentIndex(-1), currentItem(0) @@ -1442,13 +1463,17 @@ qreal QQuickItemViewPrivate::endPosition() const qreal QQuickItemViewPrivate::contentStartOffset() const { qreal pos = -headerSize(); - if (layoutOrientation() == Qt::Vertical) - pos -= vData.startMargin; - else if (isContentFlowReversed()) - pos -= hData.endMargin; - else - pos -= hData.startMargin; - + if (layoutOrientation() == Qt::Vertical) { + if (isContentFlowReversed()) + pos -= vData.endMargin; + else + pos -= vData.startMargin; + } else { + if (isContentFlowReversed()) + pos -= hData.endMargin; + else + pos -= hData.startMargin; + } return pos; } @@ -1777,7 +1802,7 @@ void QQuickItemViewPrivate::layout() bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult, ChangeResult *totalRemovalResult) { Q_Q(QQuickItemView); - if (!q->isComponentComplete() || (!currentChanges.hasPendingChanges() && !bufferedChanges.hasPendingChanges() && !runDelayedRemoveTransition) || disableLayout) + if (!q->isComponentComplete() || !hasPendingChanges() || disableLayout) return false; disableLayout = true; diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index f252fb58f1..89e59306f9 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -70,6 +70,7 @@ class Q_AUTOTEST_EXPORT QQuickItemView : public QQuickFlickable Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged) Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged) + Q_PROPERTY(VerticalLayoutDirection verticalLayoutDirection READ verticalLayoutDirection WRITE setVerticalLayoutDirection NOTIFY verticalLayoutDirectionChanged) Q_PROPERTY(QQmlComponent *header READ header WRITE setHeader NOTIFY headerChanged) Q_PROPERTY(QQuickItem *headerItem READ headerItem NOTIFY headerItemChanged) @@ -95,8 +96,25 @@ class Q_AUTOTEST_EXPORT QQuickItemView : public QQuickFlickable Q_ENUMS(HighlightRangeMode) Q_ENUMS(PositionMode) + Q_ENUMS(VerticalLayoutDirection) + Q_ENUMS(LayoutDirection) public: + // this holds all layout enum values so they can be referred to by other enums + // to ensure consistent values - e.g. QML references to GridView.TopToBottom flow + // and GridView.TopToBottom vertical layout direction should have same value + enum LayoutDirection { + LeftToRight = Qt::LeftToRight, + RightToLeft = Qt::RightToLeft, + VerticalTopToBottom, + VerticalBottomToTop + }; + + enum VerticalLayoutDirection { + TopToBottom = VerticalTopToBottom, + BottomToTop = VerticalBottomToTop + }; + QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent = 0); ~QQuickItemView(); @@ -123,6 +141,9 @@ public: void setLayoutDirection(Qt::LayoutDirection); Qt::LayoutDirection effectiveLayoutDirection() const; + VerticalLayoutDirection verticalLayoutDirection() const; + void setVerticalLayoutDirection(VerticalLayoutDirection layoutDirection); + QQmlComponent *footer() const; void setFooter(QQmlComponent *); QQuickItem *footerItem() const; @@ -189,6 +210,7 @@ public: virtual void setContentX(qreal pos); virtual void setContentY(qreal pos); virtual qreal xOrigin() const; + virtual qreal yOrigin() const; signals: void modelChanged(); @@ -202,6 +224,7 @@ signals: void layoutDirectionChanged(); void effectiveLayoutDirectionChanged(); + void verticalLayoutDirectionChanged(); void headerChanged(); void footerChanged(); diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index e352c461d6..8fc83a99e3 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -204,6 +204,10 @@ public: void updateUnrequestedPositions(); void updateVisibleIndex(); void positionViewAtIndex(int index, int mode); + + qreal minExtentForAxis(const AxisData &axisData, bool forXAxis) const; + qreal maxExtentForAxis(const AxisData &axisData, bool forXAxis) const; + void applyPendingChanges(); bool applyModelChanges(ChangeResult *insertionResult, ChangeResult *removalResult); bool applyRemovalChange(const QQuickChangeSet::Remove &removal, ChangeResult *changeResult, int *removedCount); @@ -229,12 +233,26 @@ public: hData.markExtentsDirty(); } + bool hasPendingChanges() const { + return currentChanges.hasPendingChanges() + || bufferedChanges.hasPendingChanges() + ||runDelayedRemoveTransition; + } + + void refillOrLayout() { + if (hasPendingChanges()) + layout(); + else + refill(); + } + QQmlGuard<QQuickVisualModel> model; QVariant modelVariant; int itemCount; int buffer; int bufferMode; Qt::LayoutDirection layoutDirection; + QQuickItemView::VerticalLayoutDirection verticalLayoutDirection; MovementReason moveReason; diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index 9e17385c46..0ec87ba51c 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -147,11 +147,11 @@ public: QQuickItem *item; QQuickItemViewTransitionJob *transition; QQuickItemViewTransitioner::TransitionType nextTransitionType; - bool isTransitionTarget; - bool nextTransitionToSet; - bool nextTransitionFromSet; - bool lastMovedToSet; - bool prepared; + bool isTransitionTarget : 1; + bool nextTransitionToSet : 1; + bool nextTransitionFromSet : 1; + bool lastMovedToSet : 1; + bool prepared : 1; private: friend class QQuickItemViewTransitioner; diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 1cc2637fe6..df50d3eb8c 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -73,6 +73,7 @@ public: virtual Qt::Orientation layoutOrientation() const; virtual bool isContentFlowReversed() const; bool isRightToLeft() const; + bool isBottomToTop() const; virtual qreal positionAt(int index) const; virtual qreal endPositionAt(int index) const; @@ -265,7 +266,7 @@ public: qreal position() const { if (section()) { if (view->orientation() == QQuickListView::Vertical) - return section()->y(); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -section()->height()-section()->y() : section()->y()); else return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section()->width()-section()->x() : section()->x()); } else { @@ -274,7 +275,7 @@ public: } qreal itemPosition() const { if (view->orientation() == QQuickListView::Vertical) - return itemY(); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -item->height()-itemY() : itemY()); else return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX()); } @@ -294,7 +295,9 @@ public: } qreal endPosition() const { if (view->orientation() == QQuickListView::Vertical) { - return itemY() + item->height(); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop + ? -itemY() + : itemY() + item->height()); } else { return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemX() @@ -305,7 +308,10 @@ public: // position the section immediately even if there is a transition if (section()) { if (view->orientation() == QQuickListView::Vertical) { - section()->setY(pos); + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) + section()->setY(-section()->height()-pos); + else + section()->setY(pos); } else { if (view->effectiveLayoutDirection() == Qt::RightToLeft) section()->setX(-section()->width()-pos); @@ -331,9 +337,15 @@ public: private: QPointF pointForPosition(qreal pos) const { if (view->orientation() == QQuickListView::Vertical) { - if (section()) - pos += section()->height(); - return QPointF(itemX(), pos); + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) { + if (section()) + pos += section()->height(); + return QPointF(itemX(), -item->height() - pos); + } else { + if (section()) + pos += section()->height(); + return QPointF(itemX(), pos); + } } else { if (view->effectiveLayoutDirection() == Qt::RightToLeft) { if (section()) @@ -352,7 +364,7 @@ private: bool QQuickListViewPrivate::isContentFlowReversed() const { - return isRightToLeft(); + return isRightToLeft() || isBottomToTop(); } Qt::Orientation QQuickListViewPrivate::layoutOrientation() const @@ -366,6 +378,11 @@ bool QQuickListViewPrivate::isRightToLeft() const return orient == QQuickListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft; } +bool QQuickListViewPrivate::isBottomToTop() const +{ + return orient == QQuickListView::Vertical && verticalLayoutDirection == QQuickItemView::BottomToTop; +} + // Returns the item before modelIndex, if created. // May return an item marked for removal. FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const @@ -391,7 +408,10 @@ void QQuickListViewPrivate::setPosition(qreal pos) { Q_Q(QQuickListView); if (orient == QQuickListView::Vertical) { - q->QQuickFlickable::setContentY(pos); + if (isBottomToTop()) + q->QQuickFlickable::setContentY(-pos-size()); + else + q->QQuickFlickable::setContentY(pos); } else { if (isRightToLeft()) q->QQuickFlickable::setContentX(-pos-size()); @@ -797,8 +817,12 @@ void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index) Q_Q(QQuickListView); qreal pos = position(); if (orient == QQuickListView::Vertical) { - if (item->y() + item->height() > pos && item->y() < pos + q->height()) - item->setY(positionAt(index)); + if (item->y() + item->height() > pos && item->y() < pos + q->height()) { + if (isBottomToTop()) + item->setY(-positionAt(index)-item->height()); + else + item->setY(positionAt(index)); + } } else { if (item->x() + item->width() > pos && item->x() < pos + q->width()) { if (isRightToLeft()) @@ -880,7 +904,7 @@ void QQuickListViewPrivate::updateHighlight() if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) { // auto-update highlight FxListItemSG *listItem = static_cast<FxListItemSG*>(currentItem); - highlightPosAnimator->to = isRightToLeft() + highlightPosAnimator->to = isContentFlowReversed() ? -listItem->itemPosition()-listItem->itemSize() : listItem->itemPosition(); highlightSizeAnimator->to = listItem->itemSize(); @@ -987,8 +1011,8 @@ void QQuickListViewPrivate::updateStickySections() || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem)) return; - bool isRtl = isRightToLeft(); - qreal viewPos = isRightToLeft() ? -position()-size() : position(); + bool isFlowReversed = isContentFlowReversed(); + qreal viewPos = isFlowReversed ? -position()-size() : position(); QQuickItem *sectionItem = 0; QQuickItem *lastSectionItem = 0; int index = 0; @@ -1000,14 +1024,14 @@ void QQuickListViewPrivate::updateStickySections() qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width(); bool visTop = true; if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart) - visTop = isRtl ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos; + visTop = isFlowReversed ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos; bool visBot = true; if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) - visBot = isRtl ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size(); + visBot = isFlowReversed ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size(); section->setVisible(visBot && visTop); if (visTop && !sectionItem) sectionItem = section; - if (isRtl) { + if (isFlowReversed) { if (-sectionPos <= viewPos + size()) lastSectionItem = section; } else { @@ -1031,17 +1055,18 @@ void QQuickListViewPrivate::updateStickySections() return; qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width(); - bool atBeginning = orient == QQuickListView::Vertical ? vData.atBeginning : (isRightToLeft() ? hData.atEnd : hData.atBeginning); + bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning); + currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos)); - qreal pos = isRtl ? position() + size() - sectionSize : viewPos; + qreal pos = isFlowReversed ? position() + size() - sectionSize : viewPos; if (sectionItem) { qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x(); - pos = isRtl ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize); + pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize); } if (header) - pos = isRtl ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos); + pos = isFlowReversed ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos); if (footer) - pos = isRtl ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos); + pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos); if (orient == QQuickListView::Vertical) currentSectionItem->setY(pos); else @@ -1065,13 +1090,13 @@ void QQuickListViewPrivate::updateStickySections() qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width(); nextSectionItem->setVisible(!nextSection.isEmpty()); - qreal pos = isRtl ? position() : viewPos + size() - sectionSize; + qreal pos = isFlowReversed ? position() : viewPos + size() - sectionSize; if (lastSectionItem) { qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x(); - pos = isRtl ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize); + pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize); } if (header) - pos = isRtl ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos); + pos = isFlowReversed ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos); if (orient == QQuickListView::Vertical) nextSectionItem->setY(pos); else @@ -1162,7 +1187,7 @@ void QQuickListViewPrivate::updateCurrentSection() // section when that changes. Clearing lastVisibleSection will also // force searching. QString lastSection = currentSection; - qreal endPos = isRightToLeft() ? -position() : position() + size(); + qreal endPos = isContentFlowReversed() ? -position() : position() + size(); if (nextSectionItem && !inlineSections) endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width(); while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) { @@ -1341,10 +1366,10 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte fixupMode = moveReason == Mouse ? fixupMode : Immediate; bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange; - qreal viewPos = isRightToLeft() ? -position()-size() : position(); + qreal viewPos = isContentFlowReversed() ? -position()-size() : position(); if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) { - qreal tempPosition = isRightToLeft() ? -position()-size() : position(); + qreal tempPosition = isContentFlowReversed() ? -position()-size() : position(); if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) { // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); @@ -1353,7 +1378,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte bias = averageSize/2; else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2) bias = -averageSize/2; - if (isRightToLeft()) + if (isContentFlowReversed()) bias = -bias; tempPosition -= bias; } @@ -1373,15 +1398,15 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte bool isInBounds = -position() > maxExtent && -position() <= minExtent; if (topItem && (isInBounds || strictHighlightRange)) { if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) { - pos = isRightToLeft() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart; + pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart; } else { - if (isRightToLeft()) + if (isContentFlowReversed()) pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent); else pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent); } } else if (bottomItem && isInBounds) { - if (isRightToLeft()) + if (isContentFlowReversed()) pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent); else pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent); @@ -1408,7 +1433,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd; if (viewPos > pos - highlightRangeStart) viewPos = pos - highlightRangeStart; - if (isRightToLeft()) + if (isContentFlowReversed()) viewPos = -viewPos-size(); timeline.reset(data.move); @@ -1441,7 +1466,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte return; } qreal maxDistance = 0; - qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value(); + qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value(); // -ve velocity means list is moving up/left if (velocity > 0) { @@ -1450,7 +1475,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); qreal bias = dist < averageSize/2 ? averageSize/2 : 0; - if (isRightToLeft()) + if (isContentFlowReversed()) bias = -bias; data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart; maxDistance = qAbs(data.flickTarget - data.move.value()); @@ -1467,7 +1492,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); qreal bias = -dist < averageSize/2 ? averageSize/2 : 0; - if (isRightToLeft()) + if (isContentFlowReversed()) bias = -bias; data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart; maxDistance = qAbs(data.flickTarget - data.move.value()); @@ -1505,10 +1530,10 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte dist = -dist; if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) { if (snapMode != QQuickListView::SnapOneItem) { - qreal distTemp = isRightToLeft() ? -dist : dist; + qreal distTemp = isContentFlowReversed() ? -dist : dist; data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart; } - data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; + data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget; if (overShoot) { if (data.flickTarget >= minExtent) { overshootDist = overShootDistance(vSize); @@ -1561,9 +1586,9 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // reevaluate the target boundary. qreal newtarget = data.flickTarget; if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) { - qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; + qreal tempFlickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget; newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart; - newtarget = isRightToLeft() ? -newtarget+size() : newtarget; + newtarget = isContentFlowReversed() ? -newtarget+size() : newtarget; } if (velocity < 0 && newtarget <= maxExtent) newtarget = maxExtent - overshootDist; @@ -1655,6 +1680,45 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte to set \e {clip: true} in order to have the out of view items clipped nicely. + + \section1 ListView layouts + + The layout of the items in a ListView can be controlled by these properties: + + \list + \li \l orientation - controls whether items flow horizontally or vertically. + This value can be either Qt.Horizontal or Qt.Vertical. + \li \l layoutDirection - controls the horizontal layout direction for a + horizontally-oriented view: that is, whether items are laid out from the left side of + the view to the right, or vice-versa. This value can be either Qt.LeftToRight or Qt.RightToLeft. + \li \l verticalLayoutDirection - controls the vertical layout direction for a vertically-oriented + view: that is, whether items are laid out from the top of the view down towards the bottom of + the view, or vice-versa. This value can be either ListView.TopToBottom or ListView.BottomToTop. + \endlist + + By default, a ListView has a vertical orientation, and items are laid out from top to bottom. The + table below shows the different layouts that a ListView can have, depending on the values of + the properties listed above. + + \table + \header + \li {2, 1} + \bold ListViews with Qt.Vertical orientation + \row + \li Top to bottom + \image listview-layout-toptobottom.png + \li Bottom to top + \image listview-layout-bottomtotop.png + \header + \li {2, 1} + \bold ListViews with Qt.Horizontal orientation + \row + \li Left to right + \image listview-layout-lefttoright.png + \li Right to left + \image listview-layout-righttoleft.png + \endtable + \sa {QML Data Models}, GridView, {declarative/modelviews/listview}{ListView examples} */ QQuickListView::QQuickListView(QQuickItem *parent) @@ -1956,7 +2020,7 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation) /*! \qmlproperty enumeration QtQuick2::ListView::layoutDirection - This property holds the layout direction of the horizontal list. + This property holds the layout direction of a horizontally-oriented list. Possible values: @@ -1965,13 +2029,15 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation) \li Qt.RightToLeft - Items will be laid out from right to let. \endlist - \sa ListView::effectiveLayoutDirection + Setting this property has no effect if the \l orientation is Qt.Vertical. + + \sa ListView::effectiveLayoutDirection, ListView::verticalLayoutDirection */ /*! \qmlproperty enumeration QtQuick2::ListView::effectiveLayoutDirection - This property holds the effective layout direction of the horizontal list. + This property holds the effective layout direction of a horizontally-oriented list. When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts, the visual layout direction of the horizontal list will be mirrored. However, the @@ -1980,6 +2046,24 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation) \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring} */ + +/*! + \qmlproperty enumeration QtQuick2::ListView::verticalLayoutDirection + This property holds the layout direction of a vertically-oriented list. + + Possible values: + + \list + \li ListView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view. + \li ListView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view. + \endlist + + Setting this property has no effect if the \l orientation is Qt.Horizontal. + + \sa ListView::layoutDirection +*/ + + /*! \qmlproperty bool QtQuick2::ListView::keyNavigationWraps This property holds whether the list wraps key navigation. @@ -2550,14 +2634,19 @@ void QQuickListView::viewportMoved() return; d->inViewportMoved = true; - if (yflick()) - d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter; - else if (d->isRightToLeft()) - d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore; - else - d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter; + if (yflick()) { + if (d->isBottomToTop()) + d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore; + else + d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter; + } else { + if (d->isRightToLeft()) + d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore; + else + d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter; + } - d->refill(); + d->refillOrLayout(); // Set visibility of items to eliminate cost of items outside the visible area. qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position(); @@ -2575,7 +2664,7 @@ void QQuickListView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->position(); - qreal viewPos = d->isRightToLeft() ? -d->position()-d->size() : d->position(); + qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position(); if (pos > viewPos + d->highlightRangeEnd - d->highlight->size()) pos = viewPos + d->highlightRangeEnd - d->highlight->size(); if (pos < viewPos + d->highlightRangeStart) @@ -2641,7 +2730,8 @@ void QQuickListView::keyPressEvent(QKeyEvent *event) if (d->model && d->model->count() && d->interactive) { if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left) || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right) - || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Up)) { + || (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Up) + || (d->orient == QQuickListView::Vertical && d->isBottomToTop() && event->key() == Qt::Key_Down)) { if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) { decrementCurrentIndex(); event->accept(); @@ -2652,7 +2742,8 @@ void QQuickListView::keyPressEvent(QKeyEvent *event) } } else if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right) || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left) - || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Down)) { + || (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Down) + || (d->orient == QQuickListView::Vertical && d->isBottomToTop() && event->key() == Qt::Key_Up)) { if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) { incrementCurrentIndex(); event->accept(); @@ -2670,10 +2761,14 @@ void QQuickListView::keyPressEvent(QKeyEvent *event) void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { Q_D(QQuickListView); - if (d->isRightToLeft() && d->orient == QQuickListView::Horizontal) { + if (d->isRightToLeft()) { // maintain position relative to the right edge int dx = newGeometry.width() - oldGeometry.width(); setContentX(contentX() - dx); + } else if (d->isBottomToTop()) { + // maintain position relative to the bottom edge + int dy = newGeometry.height() - oldGeometry.height(); + setContentY(contentY() - dy); } QQuickItemView::geometryChanged(newGeometry, oldGeometry); } @@ -2740,7 +2835,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert & int modelIndex = change.index; int count = change.count; - qreal tempPos = isRightToLeft() ? -position()-size() : position(); + qreal tempPos = isContentFlowReversed() ? -position()-size() : position(); int index = visibleItems.count() ? mapFromModel(modelIndex) : 0; if (index < 0) { diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index 32f12fad30..541bb34a2e 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -45,6 +45,7 @@ #include <QtQuick/qquickitem.h> #include <QtQuick/qsgmaterial.h> +#include <private/qtquickglobal_p.h> #include <private/qsgadaptationlayer_p.h> #include <private/qquickshadereffectnode_p.h> #include "qquickshadereffectmesh_p.h" @@ -63,7 +64,7 @@ class QSignalMapper; class QQuickCustomMaterialShader; // Common class for QQuickShaderEffect and QQuickCustomParticle. -struct QQuickShaderEffectCommon +struct Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectCommon { typedef QQuickShaderEffectMaterialKey Key; typedef QQuickShaderEffectMaterial::UniformData UniformData; @@ -90,7 +91,7 @@ struct QQuickShaderEffectCommon }; -class Q_AUTOTEST_EXPORT QQuickShaderEffect : public QQuickItem +class Q_QUICK_EXPORT QQuickShaderEffect : public QQuickItem { Q_OBJECT Q_PROPERTY(QByteArray fragmentShader READ fragmentShader WRITE setFragmentShader NOTIFY fragmentShaderChanged) diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h index 1bbce86426..2b2aab5365 100644 --- a/src/quick/items/qquickshadereffectnode_p.h +++ b/src/quick/items/qquickshadereffectnode_p.h @@ -46,6 +46,7 @@ #include <QtQuick/qsgmaterial.h> #include <QtQuick/qsgtextureprovider.h> #include <QtQuick/qquickitem.h> +#include <private/qtquickglobal_p.h> #include <QtCore/qsharedpointer.h> #include <QtCore/qpointer.h> @@ -73,7 +74,7 @@ uint qHash(const QQuickShaderEffectMaterialKey &key); class QQuickCustomMaterialShader; class QQuickShaderEffectNode; -class QQuickShaderEffectMaterial : public QSGMaterial +class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectMaterial : public QSGMaterial { public: struct UniformData @@ -127,7 +128,7 @@ protected: class QSGShaderEffectMesh; -class QQuickShaderEffectNode : public QObject, public QSGGeometryNode +class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectNode : public QObject, public QSGGeometryNode { Q_OBJECT public: diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp index 900cb84de8..8904a83176 100644 --- a/src/quick/items/qquickspriteengine.cpp +++ b/src/quick/items/qquickspriteengine.cpp @@ -621,7 +621,7 @@ uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a lis m_advanceTime.start(); m_addAdvance = true; if (m_stateUpdates.isEmpty()) - return -1; + return uint(-1); return m_stateUpdates.first().first; } diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h index 00cefbfbc0..f6ef79ca50 100644 --- a/src/quick/items/qquickspriteengine_p.h +++ b/src/quick/items/qquickspriteengine_p.h @@ -50,14 +50,15 @@ #include <QQmlListProperty> #include <QImage> #include <QPair> -#include <QtQuick/private/qquickpixmapcache_p.h> +#include <private/qquickpixmapcache_p.h> +#include <private/qtquickglobal_p.h> QT_BEGIN_HEADER QT_BEGIN_NAMESPACE class QQuickSprite; -class Q_AUTOTEST_EXPORT QQuickStochasticState : public QObject //Currently for internal use only - Sprite and ParticleGroup +class Q_QUICK_PRIVATE_EXPORT QQuickStochasticState : public QObject //Currently for internal use only - Sprite and ParticleGroup { Q_OBJECT Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged) @@ -173,7 +174,7 @@ private: bool m_randomStart; }; -class Q_AUTOTEST_EXPORT QQuickStochasticEngine : public QObject +class Q_QUICK_PRIVATE_EXPORT QQuickStochasticEngine : public QObject { Q_OBJECT //TODO: Optimize single state case? @@ -252,7 +253,7 @@ protected: bool m_addAdvance; }; -class QQuickSpriteEngine : public QQuickStochasticEngine +class Q_QUICK_PRIVATE_EXPORT QQuickSpriteEngine : public QQuickStochasticEngine { Q_OBJECT Q_PROPERTY(QQmlListProperty<QQuickSprite> sprites READ sprites) diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 24dd10ac9f..f34c062c98 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -382,6 +382,22 @@ void QQuickText::imageDownloadFinished() } } +void QQuickTextPrivate::updateBaseline(qreal baseline, qreal dy) +{ + Q_Q(QQuickText); + + qreal yoff = 0; + + if (q->heightValid()) { + if (vAlign == QQuickText::AlignBottom) + yoff = dy; + else if (vAlign == QQuickText::AlignVCenter) + yoff = dy/2; + } + + q->setBaselineOffset(baseline + yoff); +} + void QQuickTextPrivate::updateSize() { Q_Q(QQuickText); @@ -398,9 +414,19 @@ void QQuickTextPrivate::updateSize() return; } - QFontMetricsF fm(font); - if (text.isEmpty()) { - qreal fontHeight = fm.height(); + if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) { + // How much more expensive is it to just do a full layout on an empty string here? + // There may be subtle differences in the height and baseline calculations between + // QTextLayout and QFontMetrics and the number of variables that can affect the size + // and position of a line is increasing. + QFontMetricsF fm(font); + qreal fontHeight = qCeil(fm.height()); // QScriptLine and therefore QTextLine rounds up + if (!richText) { // line height, so we will as well. + fontHeight = lineHeightMode() == QQuickText::FixedHeight + ? lineHeight() + : fontHeight * lineHeight(); + } + updateBaseline(fm.ascent(), q->height() - fontHeight); q->setImplicitSize(0, fontHeight); layedOutTextRect = QRectF(0, 0, 0, fontHeight); emit q->contentSizeChanged(); @@ -411,7 +437,6 @@ void QQuickTextPrivate::updateSize() qreal naturalWidth = 0; - qreal dy = q->height(); QSizeF size(0, 0); QSizeF previousSize = layedOutTextRect.size(); #if defined(Q_OS_MAC) @@ -420,14 +445,15 @@ void QQuickTextPrivate::updateSize() //setup instance of QTextLayout for all cases other than richtext if (!richText) { - QRectF textRect = setupTextLayout(&naturalWidth); + qreal baseline = 0; + QRectF textRect = setupTextLayout(&naturalWidth, &baseline); if (internalWidthUpdate) // probably the result of a binding loop, but by letting it return; // get this far we'll get a warning to that effect if it is. layedOutTextRect = textRect; size = textRect.size(); - dy -= size.height(); + updateBaseline(baseline, q->height() - size.height()); } else { singleline = false; // richtext can't elide or be optimized for single-line case ensureDoc(); @@ -458,20 +484,13 @@ void QQuickTextPrivate::updateSize() extra->doc->setTextWidth(q->width()); else extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) - dy -= extra->doc->size().height(); QSizeF dsize = extra->doc->size(); layedOutTextRect = QRectF(QPointF(0,0), dsize); size = QSizeF(extra->doc->idealWidth(),dsize.height()); - } - qreal yoff = 0; - if (q->heightValid()) { - if (vAlign == QQuickText::AlignBottom) - yoff = dy; - else if (vAlign == QQuickText::AlignVCenter) - yoff = dy/2; + QFontMetricsF fm(font); + updateBaseline(fm.ascent(), q->height() - size.height()); } - q->setBaselineOffset(fm.ascent() + yoff); //### need to comfirm cost of always setting these for richText internalWidthUpdate = true; @@ -669,7 +688,7 @@ QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QT already absolutely positioned horizontally). */ -QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) +QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *const baseline) { Q_Q(QQuickText); layout.setCacheEnabled(true); @@ -712,9 +731,10 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) internalWidthUpdate = wasInLayout; } - QFontMetrics fm(font); + QFontMetricsF fm(font); qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : fm.height() * lineHeight(); - return QRect(0, 0, 0, height); + *baseline = fm.ascent(); + return QRectF(0, 0, 0, height); } qreal lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX; @@ -893,12 +913,13 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) QTextLayout widthLayout(layoutText.mid(characterCount), scaledFont); widthLayout.setTextOption(layout.textOption()); + widthLayout.beginLayout(); for (; unwrappedLineCount <= maxLineCount; ++unwrappedLineCount) { QTextLine line = widthLayout.createLine(); if (!line.isValid()) break; } - + widthLayout.endLayout(); *naturalWidth = qMax(*naturalWidth, widthLayout.maximumWidth()); } @@ -1024,6 +1045,12 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) elideLayout = 0; } + QTextLine firstLine = visibleCount == 1 && elideLayout + ? elideLayout->lineAt(0) + : layout.lineAt(0); + Q_ASSERT(firstLine.isValid()); + *baseline = firstLine.y() + firstLine.ascent(); + if (!customLayout) br.setHeight(height); diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index d73c6e1a10..e643d1dfb9 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -245,7 +245,7 @@ private: }; class QTextLine; -class Q_AUTOTEST_EXPORT QQuickTextLine : public QObject +class Q_QUICK_EXPORT QQuickTextLine : public QObject { Q_OBJECT Q_PROPERTY(int number READ number) diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index 0425c37406..cfa37789cc 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -75,6 +75,7 @@ public: ~QQuickTextPrivate(); void init(); + void updateBaseline(qreal baseline, qreal dy); void updateSize(); void updateLayout(); bool determineHorizontalAlignment(); @@ -163,7 +164,7 @@ public: void ensureDoc(); - QRectF setupTextLayout(qreal *const naturalWidth); + QRectF setupTextLayout(qreal *const naturalWidth, qreal * const baseline); void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0); bool isLinkActivatedConnected(); QString anchorAt(const QPointF &pos); diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 739b5f859b..f63e6a7523 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -46,7 +46,6 @@ #include <qcoreapplication.h> #include <qfont.h> -#include <qpainter.h> #include <qevent.h> #include <qdebug.h> #include <qdrag.h> @@ -60,8 +59,6 @@ #include "qtextlist.h" #include "qtextdocumentwriter.h" #include "private/qtextcursor_p.h" -#include "qpagedpaintdevice.h" -#include "private/qpagedpaintdevice_p.h" #include <qtextformat.h> #include <qdatetime.h> @@ -429,8 +426,11 @@ void QQuickTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldS void QQuickTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /*=false*/) { Q_Q(QQuickTextControl); - if (forceEmitSelectionChanged) + if (forceEmitSelectionChanged) { + if (hasFocus) + qGuiApp->inputMethod()->update(Qt::ImCurrentSelection); emit q->selectionChanged(); + } bool current = cursor.hasSelection(); if (current == lastSelectionState) @@ -438,8 +438,11 @@ void QQuickTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged / lastSelectionState = current; emit q->copyAvailable(current); - if (!forceEmitSelectionChanged) + if (!forceEmitSelectionChanged) { + if (hasFocus) + qGuiApp->inputMethod()->update(Qt::ImCurrentSelection); emit q->selectionChanged(); + } emit q->cursorRectangleChanged(); } diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h index be3f7f7ccf..aae9e12dad 100644 --- a/src/quick/items/qquicktextcontrol_p.h +++ b/src/quick/items/qquicktextcontrol_p.h @@ -74,7 +74,6 @@ class QQuickTextControlPrivate; class QAbstractScrollArea; class QEvent; class QTimerEvent; -class QPagedPaintDevice; class Q_AUTOTEST_EXPORT QQuickTextControl : public QObject { @@ -122,7 +121,6 @@ public: virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const; virtual QRectF blockBoundingRect(const QTextBlock &block) const; - QAbstractTextDocumentLayout::PaintContext getPaintContext() const; public Q_SLOTS: void setPlainText(const QString &text); diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp index d075d3b64b..45a379a1c0 100644 --- a/src/quick/items/qquickwindowmanager.cpp +++ b/src/quick/items/qquickwindowmanager.cpp @@ -404,7 +404,7 @@ void QQuickRenderThreadSingleContextWindowManager::handleAddedWindow(QQuickCanva CanvasData *data = new CanvasData; data->sizeWasChanged = false; data->windowSize = canvas->size(); - data->isVisible = canvas->visible(); + data->isVisible = canvas->isVisible(); m_rendered_windows[canvas] = data; isExternalUpdatePending = true; @@ -516,7 +516,7 @@ void QQuickRenderThreadSingleContextWindowManager::canvasVisibilityChanged() CanvasTracker &t = const_cast<CanvasTracker &>(m_tracked_windows.at(i)); QQuickCanvas *win = t.canvas; - Q_ASSERT(win->visible() || QQuickCanvasPrivate::get(win)->renderWithoutShowing || t.toBeRemoved); + Q_ASSERT(win->isVisible() || QQuickCanvasPrivate::get(win)->renderWithoutShowing || t.toBeRemoved); bool canvasVisible = win->width() > 0 && win->height() > 0; anyoneShowing |= (canvasVisible && !t.toBeRemoved); @@ -1121,7 +1121,7 @@ void QQuickRenderThreadSingleContextWindowManager::wakeup() { lockInGui(); isExternalUpdatePending = true; - if (isRenderBlocked || isPostingSyncEvent) + if (isRenderBlocked) wake(); unlockInGui(); } @@ -1173,11 +1173,11 @@ void QQuickTrivialWindowManager::renderCanvas(QQuickCanvas *canvas) CanvasData &data = const_cast<CanvasData &>(m_windows[canvas]); QQuickCanvas *masterCanvas = 0; - if (!canvas->visible()) { + if (!canvas->isVisible()) { // Find a "proper surface" to bind... for (QHash<QQuickCanvas *, CanvasData>::const_iterator it = m_windows.constBegin(); it != m_windows.constEnd() && !masterCanvas; ++it) { - if (it.key()->visible()) + if (it.key()->isVisible()) masterCanvas = it.key(); } } else { @@ -1211,7 +1211,7 @@ void QQuickTrivialWindowManager::renderCanvas(QQuickCanvas *canvas) data.grabOnly = false; } - if (alsoSwap && canvas->visible()) { + if (alsoSwap && canvas->isVisible()) { gl->swapBuffers(canvas); cd->fireFrameSwapped(); } diff --git a/src/quick/quick.pro b/src/quick/quick.pro index 0f0120ee79..87d4c90509 100644 --- a/src/quick/quick.pro +++ b/src/quick/quick.pro @@ -22,7 +22,6 @@ load(qt_module_config) include(util/util.pri) include(scenegraph/scenegraph.pri) include(items/items.pri) -include(particles/particles.pri) include(designer/designer.pri) HEADERS += \ diff --git a/src/quick/scenegraph/coreapi/qsgdefaultrenderer_p.h b/src/quick/scenegraph/coreapi/qsgdefaultrenderer_p.h index 3896d03a80..e7cd1b0465 100644 --- a/src/quick/scenegraph/coreapi/qsgdefaultrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgdefaultrenderer_p.h @@ -51,7 +51,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QSGDefaultRenderer : public QSGRenderer +class Q_QUICK_EXPORT QSGDefaultRenderer : public QSGRenderer { Q_OBJECT public: diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h index 3a3d87a233..a11ec42976 100644 --- a/src/quick/scenegraph/coreapi/qsggeometry.h +++ b/src/quick/scenegraph/coreapi/qsggeometry.h @@ -56,7 +56,7 @@ class Q_QUICK_EXPORT QSGGeometry { public: - struct Attribute + struct Q_QUICK_EXPORT Attribute { int position; int tupleSize; diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h index 9d2402d727..3dced9cfa9 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h @@ -108,7 +108,7 @@ public: qreal determinant() const { return m_current_determinant; } void setProjectionMatrixToDeviceRect(); - void setProjectionMatrixToRect(const QRectF &rect); + virtual void setProjectionMatrixToRect(const QRectF &rect); void setProjectionMatrix(const QMatrix4x4 &matrix); QMatrix4x4 projectionMatrix() const { return m_projection_matrix; } bool isMirrored() const { return m_mirrored; } diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp index fc1e6ec89f..badbf51240 100644 --- a/src/quick/util/qquickanimation.cpp +++ b/src/quick/util/qquickanimation.cpp @@ -231,6 +231,11 @@ void QQuickAbstractAnimation::setRunning(bool r) d->commence(); emit started(); } else { + if (d->paused) { + d->paused = false; //reset paused state to false when stopped + emit pausedChanged(d->paused); + } + if (d->animationInstance) { if (d->alwaysRunToEnd) { if (d->loopCount != 1) @@ -260,6 +265,7 @@ void QQuickAbstractAnimation::setRunning(bool r) bool QQuickAbstractAnimation::isPaused() const { Q_D(const QQuickAbstractAnimation); + Q_ASSERT((d->paused && d->running) || !d->paused); return d->paused; } @@ -269,6 +275,11 @@ void QQuickAbstractAnimation::setPaused(bool p) if (d->paused == p) return; + if (!d->running) { + qmlInfo(this) << "setPaused() cannot be used when animation isn't running."; + return; + } + if (d->group || d->disableUserControl) { qmlInfo(this) << "setPaused() cannot be used on non-root animation nodes."; return; @@ -445,8 +456,8 @@ void QQuickAbstractAnimation::start() \qmlmethod QtQuick2::Animation::pause() \brief Pauses the animation. - If the animation is already paused, calling this method has no effect. The - \c paused property will be true following a call to \c pause(). + If the animation is already paused or not \c running, calling this method has no effect. + The \c paused property will be true following a call to \c pause(). */ void QQuickAbstractAnimation::pause() { @@ -457,8 +468,8 @@ void QQuickAbstractAnimation::pause() \qmlmethod QtQuick2::Animation::resume() \brief Resumes a paused animation. - If the animation is not paused, calling this method has no effect. The - \c paused property will be false following a call to \c resume(). + If the animation is not paused or not \c running, calling this method has no effect. + The \c paused property will be false following a call to \c resume(). */ void QQuickAbstractAnimation::resume() { @@ -469,8 +480,8 @@ void QQuickAbstractAnimation::resume() \qmlmethod QtQuick2::Animation::stop() \brief Stops the animation. - If the animation is not running, calling this method has no effect. The - \c running property will be false following a call to \c stop(). + If the animation is not running, calling this method has no effect. Both the + \c running and \c paused properties will be false following a call to \c stop(). Normally \c stop() stops the animation immediately, and the animation has no further influence on property values. In this example animation diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp index 5d9a2880d2..0f6ccb238b 100644 --- a/src/quick/util/qquicktransition.cpp +++ b/src/quick/util/qquicktransition.cpp @@ -96,34 +96,6 @@ QT_BEGIN_NAMESPACE \sa {QML Animation and Transitions}, {declarative/animation/states}{states example}, {qmlstates}{States}, {QtQml} */ -QQuickTransitionInstance::QQuickTransitionInstance() - : m_anim(0) -{ -} - -QQuickTransitionInstance::~QQuickTransitionInstance() -{ - delete m_anim; -} - -void QQuickTransitionInstance::start() -{ - if (m_anim) - m_anim->start(); -} - -void QQuickTransitionInstance::stop() -{ - if (m_anim) - m_anim->stop(); -} - -bool QQuickTransitionInstance::isRunning() const -{ - return m_anim && m_anim->state() == QAbstractAnimationJob::Running; -} - - //ParallelAnimationWrapper allows us to do a "callback" when the animation finishes, rather than connecting //and disconnecting signals and slots frequently class ParallelAnimationWrapper : public QParallelAnimationGroupJob @@ -136,21 +108,32 @@ protected: virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState); }; -class QQuickTransitionPrivate : public QObjectPrivate +class QQuickTransitionPrivate : public QObjectPrivate, QAnimationJobChangeListener { Q_DECLARE_PUBLIC(QQuickTransition) public: QQuickTransitionPrivate() - : fromState(QLatin1String("*")), toState(QLatin1String("*")), - reversed(false), reversible(false), enabled(true) + : fromState(QLatin1String("*")), toState(QLatin1String("*")) + , runningInstanceCount(0), state(QAbstractAnimationJob::Stopped) + , reversed(false), reversible(false), enabled(true) { } + void removeStateChangeListener(QAbstractAnimationJob *anim) + { + if (anim) + anim->removeAnimationChangeListener(this, QAbstractAnimationJob::StateChange); + } + QString fromState; QString toState; + quint32 runningInstanceCount; + QAbstractAnimationJob::State state; bool reversed; bool reversible; bool enabled; +protected: + virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State, QAbstractAnimationJob::State); static void append_animation(QQmlListProperty<QQuickAbstractAnimation> *list, QQuickAbstractAnimation *a); static int animation_count(QQmlListProperty<QQuickAbstractAnimation> *list); @@ -187,6 +170,21 @@ void QQuickTransitionPrivate::clear_animations(QQmlListProperty<QQuickAbstractAn } } +void QQuickTransitionPrivate::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State) +{ + Q_Q(QQuickTransition); + + if (newState == QAbstractAnimationJob::Running) { + if (!runningInstanceCount) + emit q->runningChanged(); + runningInstanceCount++; + } else if (newState == QAbstractAnimationJob::Stopped) { + runningInstanceCount--; + if (!runningInstanceCount) + emit q->runningChanged(); + } +} + void ParallelAnimationWrapper::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) { QParallelAnimationGroupJob::updateState(newState, oldState); @@ -198,6 +196,34 @@ void ParallelAnimationWrapper::updateState(QAbstractAnimationJob::State newState } } +QQuickTransitionInstance::QQuickTransitionInstance(QQuickTransitionPrivate *transition, QAbstractAnimationJob *anim) + : m_transition(transition) + , m_anim(anim) +{ +} + +QQuickTransitionInstance::~QQuickTransitionInstance() +{ + m_transition->removeStateChangeListener(m_anim); + delete m_anim; +} + +void QQuickTransitionInstance::start() +{ + if (m_anim) + m_anim->start(); +} + +void QQuickTransitionInstance::stop() +{ + if (m_anim) + m_anim->stop(); +} + +bool QQuickTransitionInstance::isRunning() const +{ + return m_anim && m_anim->state() == QAbstractAnimationJob::Running; +} QQuickTransition::QQuickTransition(QObject *parent) : QObject(*(new QQuickTransitionPrivate), parent) @@ -240,8 +266,8 @@ QQuickTransitionInstance *QQuickTransition::prepare(QQuickStateOperation::Action group->setDirection(d->reversed ? QAbstractAnimationJob::Backward : QAbstractAnimationJob::Forward); - QQuickTransitionInstance *wrapper = new QQuickTransitionInstance; - wrapper->m_anim = group; + group->addAnimationChangeListener(d, QAbstractAnimationJob::StateChange); + QQuickTransitionInstance *wrapper = new QQuickTransitionInstance(d, group); return wrapper; } @@ -386,6 +412,20 @@ void QQuickTransition::setEnabled(bool enabled) } /*! + \qmlproperty bool QtQuick2::Transition::running + + This property holds whether the transition is currently running. + + This property is read only. +*/ +bool QQuickTransition::running() const +{ + Q_D(const QQuickTransition); + return d->runningInstanceCount; +} + + +/*! \qmlproperty list<Animation> QtQuick2::Transition::animations \default diff --git a/src/quick/util/qquicktransition_p.h b/src/quick/util/qquicktransition_p.h index ebd82fde2c..976439c236 100644 --- a/src/quick/util/qquicktransition_p.h +++ b/src/quick/util/qquicktransition_p.h @@ -43,6 +43,7 @@ #define QQUICKTRANSITION_H #include "qquickstate_p.h" +#include <private/qabstractanimationjob_p.h> #include <qqml.h> #include <QtCore/qobject.h> @@ -55,12 +56,11 @@ class QQuickAbstractAnimation; class QQuickTransitionPrivate; class QQuickTransitionManager; class QQuickTransition; -class QAbstractAnimationJob; class Q_QUICK_EXPORT QQuickTransitionInstance { public: - QQuickTransitionInstance(); + QQuickTransitionInstance(QQuickTransitionPrivate *transition, QAbstractAnimationJob *anim); ~QQuickTransitionInstance(); void start(); @@ -69,6 +69,7 @@ public: bool isRunning() const; private: + QQuickTransitionPrivate *m_transition; QAbstractAnimationJob *m_anim; friend class QQuickTransition; }; @@ -81,6 +82,7 @@ class Q_QUICK_EXPORT QQuickTransition : public QObject Q_PROPERTY(QString from READ fromState WRITE setFromState NOTIFY fromChanged) Q_PROPERTY(QString to READ toState WRITE setToState NOTIFY toChanged) Q_PROPERTY(bool reversible READ reversible WRITE setReversible NOTIFY reversibleChanged) + Q_PROPERTY(bool running READ running NOTIFY runningChanged) Q_PROPERTY(QQmlListProperty<QQuickAbstractAnimation> animations READ animations) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_CLASSINFO("DefaultProperty", "animations") @@ -102,6 +104,8 @@ public: bool enabled() const; void setEnabled(bool enabled); + bool running() const; + QQmlListProperty<QQuickAbstractAnimation> animations(); QQuickTransitionInstance *prepare(QQuickStateOperation::ActionList &actions, @@ -116,6 +120,7 @@ Q_SIGNALS: void toChanged(); void reversibleChanged(); void enabledChanged(); + void runningChanged(); }; QT_END_NAMESPACE diff --git a/src/src.pro b/src/src.pro index 0246eea409..7631910c3c 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS += qml quick plugins +SUBDIRS += qml quick particles plugins contains(QT_CONFIG, qmltest): SUBDIRS += qmltest diff --git a/sync.profile b/sync.profile index e03ca08883..39978aee02 100644 --- a/sync.profile +++ b/sync.profile @@ -1,6 +1,7 @@ %modules = ( # path to module name map "QtQml" => "$basedir/src/qml", "QtQuick" => "$basedir/src/quick", + "QtQuickParticles" => "$basedir/src/particles", "QtQuickTest" => "$basedir/src/qmltest", "QtQmlDevTools" => "$basedir/src/qmldevtools", "QtDeclarative" => "$basedir/src/compatibility", @@ -18,10 +19,12 @@ "network" => "#include <QtNetwork/QtNetwork>\n", "testlib" => "#include <QtTest/QtTest>\n", "qml" => "#include <QtQml/QtQml>\n", + "quick" => "#include <QtQuick/QtQuick>\n", ); %modulepris = ( "QtQml" => "$basedir/modules/qt_qml.pri", "QtQuick" => "$basedir/modules/qt_quick.pri", + "QtQuickParticles" => "$basedir/modules/qt_quickparticles.pri", "QtQuickTest" => "$basedir/modules/qt_qmltest.pri", "QtQmlDevTools" => "$basedir/modules/qt_qmldevtools.pri", "QtDeclarative" => "$basedir/modules/qt_declarative.pri", @@ -220,7 +223,7 @@ # - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch) # %dependencies = ( - "qtbase" => "refs/heads/api_changes", + "qtbase" => "refs/heads/master", "qtxmlpatterns" => "refs/heads/master", "qtjsbackend" => "refs/heads/master", ); diff --git a/tests/auto/particles/particles.pro b/tests/auto/particles/particles.pro index d376b9305e..265a1eabc7 100644 --- a/tests/auto/particles/particles.pro +++ b/tests/auto/particles/particles.pro @@ -7,6 +7,7 @@ PRIVATETESTS += \ qquickcustomaffector \ qquickcustomparticle \ qquickellipseextruder \ + qquickgroupgoal \ qquickfriction \ qquickgravity \ qquickimageparticle \ @@ -18,6 +19,7 @@ PRIVATETESTS += \ qquickpointattractor \ qquickpointdirection \ qquickrectangleextruder \ + qquickspritegoal \ qquicktargetdirection \ qquicktrailemitter \ qquickturbulence \ diff --git a/tests/auto/particles/qquickage/qquickage.pro b/tests/auto/particles/qquickage/qquickage.pro index 8e5c2f0e33..71ea279ada 100644 --- a/tests/auto/particles/qquickage/qquickage.pro +++ b/tests/auto/particles/qquickage/qquickage.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickangleddirection/qquickangleddirection.pro b/tests/auto/particles/qquickangleddirection/qquickangleddirection.pro index df8d460d3e..0462fff1bd 100644 --- a/tests/auto/particles/qquickangleddirection/qquickangleddirection.pro +++ b/tests/auto/particles/qquickangleddirection/qquickangleddirection.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickcumulativedirection/qquickcumulativedirection.pro b/tests/auto/particles/qquickcumulativedirection/qquickcumulativedirection.pro index 4ea8739c21..e3f79d47fb 100644 --- a/tests/auto/particles/qquickcumulativedirection/qquickcumulativedirection.pro +++ b/tests/auto/particles/qquickcumulativedirection/qquickcumulativedirection.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickcustomaffector/qquickcustomaffector.pro b/tests/auto/particles/qquickcustomaffector/qquickcustomaffector.pro index 0855187d47..41ceb8c1fc 100644 --- a/tests/auto/particles/qquickcustomaffector/qquickcustomaffector.pro +++ b/tests/auto/particles/qquickcustomaffector/qquickcustomaffector.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickcustomparticle/data/deleteSourceItem.qml b/tests/auto/particles/qquickcustomparticle/data/deleteSourceItem.qml new file mode 100644 index 0000000000..a68373e7e4 --- /dev/null +++ b/tests/auto/particles/qquickcustomparticle/data/deleteSourceItem.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + color: "black" + width: 320 + height: 320 + + ParticleSystem { + id: sys + objectName: "system" + anchors.fill: parent + + CustomParticle { + id: cp + property variant source + } + + Emitter{ + //0,0 position + size: 32 + emitRate: 1000 + lifeSpan: 500 + } + } + + ShaderEffectSource { + id: doomedses + hideSource: true + sourceItem: Image { + id: doomed + source: "../../shared/star.png" + } + } + + function setDeletedSourceItem() { + doomed.destroy(); + cp.source = doomedses; + } +} diff --git a/tests/auto/particles/qquickcustomparticle/qquickcustomparticle.pro b/tests/auto/particles/qquickcustomparticle/qquickcustomparticle.pro index d5c21abef3..0ee7fc9863 100644 --- a/tests/auto/particles/qquickcustomparticle/qquickcustomparticle.pro +++ b/tests/auto/particles/qquickcustomparticle/qquickcustomparticle.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp index a54e10afc6..a81edca35e 100644 --- a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp +++ b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp @@ -55,6 +55,7 @@ public: private slots: void initTestCase(); void test_basic(); + void test_deleteSourceItem(); }; void tst_qquickcustomparticle::initTestCase() @@ -94,6 +95,20 @@ void tst_qquickcustomparticle::test_basic() QVERIFY(oneNonZero);//Zero is a valid value, but it also needs to be set to a random number } +void tst_qquickcustomparticle::test_deleteSourceItem() +{ + // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash + QQuickView* view = createView(testFileUrl("deleteSourceItem.qml"), 600); + QVERIFY(view); + QObject *obj = view->rootObject(); + QVERIFY(obj); + QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); + ensureAnimTime(200, system->m_animation); + QMetaObject::invokeMethod(obj, "setDeletedSourceItem"); + ensureAnimTime(200, system->m_animation); + delete view; +} + QTEST_MAIN(tst_qquickcustomparticle); #include "tst_qquickcustomparticle.moc" diff --git a/tests/auto/particles/qquickellipseextruder/qquickellipseextruder.pro b/tests/auto/particles/qquickellipseextruder/qquickellipseextruder.pro index 33241a4792..9e6b95339f 100644 --- a/tests/auto/particles/qquickellipseextruder/qquickellipseextruder.pro +++ b/tests/auto/particles/qquickellipseextruder/qquickellipseextruder.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickfriction/qquickfriction.pro b/tests/auto/particles/qquickfriction/qquickfriction.pro index 36cf9aaa60..3bc61942d7 100644 --- a/tests/auto/particles/qquickfriction/qquickfriction.pro +++ b/tests/auto/particles/qquickfriction/qquickfriction.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickgravity/qquickgravity.pro b/tests/auto/particles/qquickgravity/qquickgravity.pro index 331def26b5..03610742c0 100644 --- a/tests/auto/particles/qquickgravity/qquickgravity.pro +++ b/tests/auto/particles/qquickgravity/qquickgravity.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro b/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro index f7f09ed9d0..9ae573fe13 100644 --- a/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro +++ b/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private testlib +QT += core-private gui-private v8-private qml-private testlib quick-private quickparticles-private diff --git a/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro b/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro index 226d844263..57909444af 100644 --- a/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro +++ b/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro @@ -6,4 +6,4 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro b/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro index ec7fa48e26..047af9faf8 100644 --- a/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro +++ b/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquicklineextruder/qquicklineextruder.pro b/tests/auto/particles/qquicklineextruder/qquicklineextruder.pro index a1297b1e26..83ff8eddcf 100644 --- a/tests/auto/particles/qquicklineextruder/qquicklineextruder.pro +++ b/tests/auto/particles/qquicklineextruder/qquicklineextruder.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickmaskextruder/qquickmaskextruder.pro b/tests/auto/particles/qquickmaskextruder/qquickmaskextruder.pro index 99f50a286d..90cf2da4a3 100644 --- a/tests/auto/particles/qquickmaskextruder/qquickmaskextruder.pro +++ b/tests/auto/particles/qquickmaskextruder/qquickmaskextruder.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickparticlegroup/qquickparticlegroup.pro b/tests/auto/particles/qquickparticlegroup/qquickparticlegroup.pro index c5c908e305..4fa17e2ce0 100644 --- a/tests/auto/particles/qquickparticlegroup/qquickparticlegroup.pro +++ b/tests/auto/particles/qquickparticlegroup/qquickparticlegroup.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickparticlesystem/qquickparticlesystem.pro b/tests/auto/particles/qquickparticlesystem/qquickparticlesystem.pro index 2179ae3ae9..e8cc4f2cbd 100644 --- a/tests/auto/particles/qquickparticlesystem/qquickparticlesystem.pro +++ b/tests/auto/particles/qquickparticlesystem/qquickparticlesystem.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickpointattractor/qquickpointattractor.pro b/tests/auto/particles/qquickpointattractor/qquickpointattractor.pro index 43c8022b0a..07dd50369e 100644 --- a/tests/auto/particles/qquickpointattractor/qquickpointattractor.pro +++ b/tests/auto/particles/qquickpointattractor/qquickpointattractor.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickpointdirection/qquickpointdirection.pro b/tests/auto/particles/qquickpointdirection/qquickpointdirection.pro index 71b21e5f56..e9c73305e1 100644 --- a/tests/auto/particles/qquickpointdirection/qquickpointdirection.pro +++ b/tests/auto/particles/qquickpointdirection/qquickpointdirection.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickrectangleextruder/qquickrectangleextruder.pro b/tests/auto/particles/qquickrectangleextruder/qquickrectangleextruder.pro index 5e595204cc..e968c4a1f7 100644 --- a/tests/auto/particles/qquickrectangleextruder/qquickrectangleextruder.pro +++ b/tests/auto/particles/qquickrectangleextruder/qquickrectangleextruder.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickspritegoal/data/basic.qml b/tests/auto/particles/qquickspritegoal/data/basic.qml index 622f6bdd70..23effe3a68 100644 --- a/tests/auto/particles/qquickspritegoal/data/basic.qml +++ b/tests/auto/particles/qquickspritegoal/data/basic.qml @@ -57,12 +57,12 @@ Rectangle { name: "happy" source: "../../shared/squarefacesprite.png" frames: 6 - duration: 120 + frameDuration: 120 }, Sprite { name: "twoHappy" source: "../../shared/squarefacesprite.png" frames: 3 - duration: 240 + frameDuration: 240 }] } diff --git a/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro b/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro index cfe932aabd..a5f491aedc 100644 --- a/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro +++ b/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private testlib +QT += core-private gui-private v8-private qml-private testlib quick-private quickparticles-private diff --git a/tests/auto/particles/qquicktargetdirection/qquicktargetdirection.pro b/tests/auto/particles/qquicktargetdirection/qquicktargetdirection.pro index b7ba905f2e..2d2751e5ab 100644 --- a/tests/auto/particles/qquicktargetdirection/qquicktargetdirection.pro +++ b/tests/auto/particles/qquicktargetdirection/qquicktargetdirection.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquicktrailemitter/qquicktrailemitter.pro b/tests/auto/particles/qquicktrailemitter/qquicktrailemitter.pro index 5a76e2fba4..a5d823911c 100644 --- a/tests/auto/particles/qquicktrailemitter/qquicktrailemitter.pro +++ b/tests/auto/particles/qquicktrailemitter/qquicktrailemitter.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickturbulence/qquickturbulence.pro b/tests/auto/particles/qquickturbulence/qquickturbulence.pro index 3bfb94addf..5ccf83b337 100644 --- a/tests/auto/particles/qquickturbulence/qquickturbulence.pro +++ b/tests/auto/particles/qquickturbulence/qquickturbulence.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/particles/qquickwander/qquickwander.pro b/tests/auto/particles/qquickwander/qquickwander.pro index 1cd4269074..65075e5417 100644 --- a/tests/auto/particles/qquickwander/qquickwander.pro +++ b/tests/auto/particles/qquickwander/qquickwander.pro @@ -6,5 +6,5 @@ macx:CONFIG -= app_bundle include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private gui-private v8-private qml-private quick-private quickparticles-private testlib diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/test.qml b/tests/auto/qml/debugger/qqmldebugjs/data/test.qml index 200f26b1c3..e6c6faa912 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/data/test.qml +++ b/tests/auto/qml/debugger/qqmldebugjs/data/test.qml @@ -50,5 +50,11 @@ Item { var c var d = 12 } + function foo() { + var a = [1, 2] + var b = {a: "hello", d: 1 } + var c + var d = 12 + } } diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp index 8293ec6cda..b93be16e0e 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp @@ -107,7 +107,6 @@ const char *GARBAGECOLLECTOR = "gc"; const char *CONNECT = "connect"; const char *INTERRUPT = "interrupt"; -const char *BREAKAFTERCOMPILE = "breakaftercompile"; const char *REQUEST = "request"; const char *IN = "in"; @@ -173,7 +172,6 @@ private slots: void connect(); void interrupt(); - void breakAfterCompile(); void getVersion(); void getVersionWhenAttaching(); @@ -270,7 +268,6 @@ public: void connect(); void interrupt(); - void breakAfterCompile(bool enabled); void continueDebugging(StepAction stepAction, int stepCount = 1); void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap()); @@ -301,7 +298,6 @@ signals: void enabled(); void connected(); void interruptRequested(); - void breakAfterCompileRequested(); void result(); void stopped(); void scriptsResult(); @@ -334,14 +330,6 @@ void QJSDebugClient::interrupt() sendMessage(packMessage(INTERRUPT)); } -void QJSDebugClient::breakAfterCompile(bool enabled) -{ - QByteArray request; - QDataStream rs(&request, QIODevice::WriteOnly); - rs << enabled; - sendMessage(packMessage(BREAKAFTERCOMPILE, request)); -} - void QJSDebugClient::continueDebugging(StepAction action, int count) { // { "seq" : <number>, @@ -957,9 +945,6 @@ void QJSDebugClient::messageReceived(const QByteArray &data) emit stopped(); } - } else if (type == BREAKAFTERCOMPILE) { - emit breakAfterCompileRequested(); - } } } @@ -1074,18 +1059,6 @@ void tst_QQmlDebugJS::interrupt() QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested()))); } -void tst_QQmlDebugJS::breakAfterCompile() -{ - //void breakAfterCompile(bool enabled) - - QVERIFY(init()); - client->breakAfterCompile(true); - client->connect(); - - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(breakAfterCompileRequested()))); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); -} - void tst_QQmlDebugJS::getVersion() { //void version() @@ -1146,9 +1119,9 @@ void tst_QQmlDebugJS::listBreakpoints() { //void listBreakpoints() - int sourceLine1 = 47; - int sourceLine2 = 48; - int sourceLine3 = 49; + int sourceLine1 = 53; + int sourceLine2 = 54; + int sourceLine3 = 55; QVERIFY(init()); client->connect(); diff --git a/tests/auto/qml/debugger/qv8profilerservice/qv8profilerservice.pro b/tests/auto/qml/debugger/qv8profilerservice/qv8profilerservice.pro index 5088953c92..13d39c0225 100644 --- a/tests/auto/qml/debugger/qv8profilerservice/qv8profilerservice.pro +++ b/tests/auto/qml/debugger/qv8profilerservice/qv8profilerservice.pro @@ -13,3 +13,5 @@ OTHER_FILES += data/test.qml CONFIG += parallel_test declarative_debug QT += qml testlib + +macx:CONFIG += insignificant_test # QTBUG-25288 diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h index 2ea295b822..4350056caf 100644 --- a/tests/auto/qml/debugger/shared/debugutil_p.h +++ b/tests/auto/qml/debugger/shared/debugutil_p.h @@ -48,6 +48,7 @@ #include <QThread> #include <QTest> #include <QProcess> +#include <QMutex> #include <QtQml/qqmlengine.h> diff --git a/tests/auto/qml/v4/data/variantHandling.qml b/tests/auto/qml/v4/data/variantHandling.qml new file mode 100644 index 0000000000..3d48eef57e --- /dev/null +++ b/tests/auto/qml/v4/data/variantHandling.qml @@ -0,0 +1,67 @@ +import QtQuick 2.0 + +QtObject { + property bool pBool: true + property int pInt: 666 + property real pReal: 3.1415927 + property string pString: 'foo' + property url pUrl: 'http://tools.ietf.org/html/rfc3986#section-1.1.2' + property color pColor: Qt.rgba(1, 0, 0, 0.5) + property QtObject pObject: QtObject { property string foo: 'bar' } + + // Test assignment to variant + property variant pBoolVar: pBool + property variant pIntVar: pInt + property variant pRealVar: pReal + property variant pStringVar: pString + property variant pUrlVar: pUrl + property variant pColorVar: pColor + property variant pObjectVar: pObject + property variant pNullVar: null + property variant pVarVar: pUrlVar + + // Test equivalence + property bool boolConversionSuccess: (pBoolVar == true) + property bool intConversionSuccess: (pIntVar == 666) + property bool realConversionSuccess: (pRealVar == 3.1415927) + property bool stringConversionSuccess: (pStringVar == 'foo') + + property url comparisonUrl: 'http://tools.ietf.org/html/rfc3986#section-1.1.2' + property bool urlConversionSuccess: (pUrlVar == comparisonUrl) + + property color comparisonColor: Qt.rgba(1, 0, 0, 0.5) + property bool colorConversionSuccess: (pColorVar == comparisonColor) + + property bool objectConversionSuccess: (pObjectVar == pObject) + property bool nullConversionSuccess: (pNullVar == null) + + property bool variantConversionSuccess: (pVarVar == comparisonUrl) + + // Operations are not handled by V4 - they should pass through correctly + property variant pVarNot: !pBoolVar + property variant pVarComplement: ~pIntVar + property variant pVarEqual: (pBoolVar == pBoolVar) + property variant pVarLiteralEqual: (pBoolVar == true) + property variant pVarUnequal: (pUrlVar == pColorVar) + property variant pVarComparison: (pIntVar <= pIntVar) + property variant pVarShift: (pIntVar >> 1) + + Component.onCompleted: { + if (!boolConversionSuccess) console.warn('QV4: bool conversion failed'); + if (!intConversionSuccess) console.warn('QV4: int conversion failed'); + if (!realConversionSuccess) console.warn('QV4: real conversion failed'); + if (!stringConversionSuccess) console.warn('QV4: string conversion failed'); + if (!urlConversionSuccess) console.warn('QV4: url conversion failed'); + if (!colorConversionSuccess) console.warn('QV4: color conversion failed'); + if (!objectConversionSuccess) console.warn('QV4: object conversion failed'); + if (!nullConversionSuccess) console.warn('QV4: null conversion failed'); + if (!variantConversionSuccess) console.warn('QV4: variant conversion failed'); + if (pVarNot != false) console.warn('QV4: variant negation impeded'); + if (pVarComplement != ~666) console.warn('QV4: variant complement impeded'); + if (pVarEqual != true) console.warn('QV4: variant equality impeded'); + if (pVarLiteralEqual != true) console.warn('QV4: variant/literal equality impeded'); + if (pVarUnequal != false) console.warn('QV4: variant unequality impeded'); + if (pVarComparison != true) console.warn('QV4: variant comparison impeded'); + if (pVarShift != 333) console.warn('QV4: variant shift impeded'); + } +} diff --git a/tests/auto/qml/v4/tst_v4.cpp b/tests/auto/qml/v4/tst_v4.cpp index dfb7cc48c7..99a4405afa 100644 --- a/tests/auto/qml/v4/tst_v4.cpp +++ b/tests/auto/qml/v4/tst_v4.cpp @@ -150,6 +150,7 @@ void tst_v4::qtscript_data() QTest::newRow("conversion from string") << "conversions.6.qml"; // QTBUG-24706 QTest::newRow("conversion from url") << "conversions.7.qml"; // QTBUG-24706 QTest::newRow("conversion from vec3") << "conversions.8.qml"; + QTest::newRow("variantHandling") << "variantHandling.qml"; } void tst_v4::unnecessaryReeval() @@ -856,23 +857,31 @@ void tst_v4::debuggingDumpInstructions() expectedPreAddress << "\t\tConvertBoolToInt\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertBoolToNumber\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertBoolToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertBoolToVariant\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertIntToBool\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertIntToNumber\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertIntToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertIntToVariant\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertNumberToBool\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertNumberToInt\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertNumberToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertNumberToVariant\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertStringToBool\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertStringToInt\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertStringToNumber\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertStringToUrl\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertStringToColor\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertStringToVariant\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertUrlToBool\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertUrlToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertUrlToVariant\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertColorToBool\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertColorToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertColorToVariant\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertObjectToBool\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertObjectToVariant\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tConvertNullToObject\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertNullToVariant\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tResolveUrl\t\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tMathSinNumber\t\tInput_Reg(0) -> Output_Reg(0)"; expectedPreAddress << "\t\tMathCosNumber\t\tInput_Reg(0) -> Output_Reg(0)"; diff --git a/tests/auto/qmltest/qmltest.pro b/tests/auto/qmltest/qmltest.pro index b1b2ee2228..ca39dacdb9 100644 --- a/tests/auto/qmltest/qmltest.pro +++ b/tests/auto/qmltest/qmltest.pro @@ -9,4 +9,4 @@ importFiles.files = borderimage buttonclick createbenchmark events qqmlbindi importFiles.path = . DEPLOYMENT += importFiles -CONFIG+=insignificant_test
\ No newline at end of file +CONFIG+=insignificant_test # QTBUG-25306 diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp index 166f4b8276..7460263d71 100644 --- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp +++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp @@ -624,6 +624,32 @@ void tst_qquickanimations::resume() QTest::qWait(400); animation.stop(); QVERIFY(rect.x() > x); + + animation.start(); + QVERIFY(animation.isRunning()); + animation.pause(); + QVERIFY(animation.isPaused()); + animation.resume(); + QVERIFY(!animation.isPaused()); + + QSignalSpy spy(&animation, SIGNAL(pausedChanged(bool))); + animation.pause(); + QCOMPARE(spy.count(), 1); + QVERIFY(animation.isPaused()); + animation.stop(); + QVERIFY(!animation.isPaused()); + QCOMPARE(spy.count(), 2); + + qmlRegisterType<QQuickPropertyAnimation>("QtQuick",2,0,"PropertyAnimation"); //make sure QQuickPropertyAnimation has correct qml type name + QByteArray message = "<Unknown File>: QML PropertyAnimation: setPaused() cannot be used when animation isn't running."; + QTest::ignoreMessage(QtWarningMsg, message); + animation.pause(); + QCOMPARE(spy.count(), 2); + QVERIFY(!animation.isPaused()); + animation.resume(); + QVERIFY(!animation.isPaused()); + QVERIFY(!animation.isRunning()); + QCOMPARE(spy.count(), 2); } void tst_qquickanimations::dotProperty() @@ -961,11 +987,12 @@ void tst_qquickanimations::disabledTransition() QCOMPARE(myRect->x(),qreal(200)); trans->setEnabled(true); - + QSignalSpy runningSpy(trans, SIGNAL(runningChanged())); QQuickItemPrivate::get(rect)->setState(""); QCOMPARE(myRect->x(),qreal(200)); QTest::qWait(300); QTIMED_COMPARE(myRect->x(),qreal(100)); + QCOMPARE(runningSpy.count(), 2); //stopped, running, stopped } void tst_qquickanimations::invalidDuration() diff --git a/tests/auto/quick/qquickcanvas/data/ownershipRootItem.qml b/tests/auto/quick/qquickcanvas/data/ownershipRootItem.qml new file mode 100644 index 0000000000..dfc4159f4e --- /dev/null +++ b/tests/auto/quick/qquickcanvas/data/ownershipRootItem.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 as Window + +Window.Window { +RootItemAccessor { + id:accessor + objectName:"accessor" + Component.onCompleted:accessor.rootItem(); +} + +}
\ No newline at end of file diff --git a/tests/auto/quick/qquickcanvas/qquickcanvas.pro b/tests/auto/quick/qquickcanvas/qquickcanvas.pro index 817eb2534f..b9ed73d577 100644 --- a/tests/auto/quick/qquickcanvas/qquickcanvas.pro +++ b/tests/auto/quick/qquickcanvas/qquickcanvas.pro @@ -7,7 +7,7 @@ include (../../shared/util.pri) macx:CONFIG -= app_bundle CONFIG += parallel_test -QT += core-private gui-private qml-private quick-private testlib +QT += core-private gui-private qml-private quick-private v8-private testlib TESTDATA = data/* @@ -15,4 +15,3 @@ OTHER_FILES += \ data/AnimationsWhileHidden.qml \ data/Headless.qml - diff --git a/tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp b/tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp index 7250504e73..ca2165d711 100644 --- a/tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp +++ b/tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp @@ -50,6 +50,7 @@ #include <QtGui/QWindowSystemInterface> #include "../../shared/util.h" #include <QSignalSpy> +#include <private/qquickcanvas_p.h> struct TouchEventData { QEvent::Type type; @@ -108,6 +109,36 @@ static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPoin } \ } + +class RootItemAccessor : public QQuickItem +{ + Q_OBJECT +public: + RootItemAccessor() + : m_rootItemDestroyed(false) + , m_rootItem(0) + { + } + Q_INVOKABLE QQuickItem *rootItem() + { + if (!m_rootItem) { + QQuickCanvasPrivate *c = QQuickCanvasPrivate::get(canvas()); + m_rootItem = c->rootItem; + QObject::connect(m_rootItem, SIGNAL(destroyed()), this, SLOT(rootItemDestroyed())); + } + return m_rootItem; + } + bool isRootItemDestroyed() {return m_rootItemDestroyed;} +public slots: + void rootItemDestroyed() { + m_rootItemDestroyed = true; + } + +private: + bool m_rootItemDestroyed; + QQuickItem *m_rootItem; +}; + class TestTouchItem : public QQuickRectangle { Q_OBJECT @@ -214,6 +245,7 @@ private slots: void ignoreUnhandledMouseEvents(); + void ownershipRootItem(); private: QTouchDevice *touchDevice; }; @@ -234,7 +266,7 @@ void tst_qquickcanvas::touchEvent_basic() QQuickCanvas *canvas = new QQuickCanvas; canvas->resize(250, 250); - canvas->move(100, 100); + canvas->setPos(100, 100); canvas->show(); TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem()); @@ -355,7 +387,7 @@ void tst_qquickcanvas::touchEvent_propagation() QQuickCanvas *canvas = new QQuickCanvas; canvas->resize(250, 250); - canvas->move(100, 100); + canvas->setPos(100, 100); canvas->show(); TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem()); @@ -483,7 +515,7 @@ void tst_qquickcanvas::touchEvent_cancel() QQuickCanvas *canvas = new QQuickCanvas; canvas->resize(250, 250); - canvas->move(100, 100); + canvas->setPos(100, 100); canvas->show(); TestTouchItem *item = new TestTouchItem(canvas->rootItem()); @@ -529,7 +561,7 @@ void tst_qquickcanvas::mouseFiltering() QQuickCanvas *canvas = new QQuickCanvas; canvas->resize(250, 250); - canvas->move(100, 100); + canvas->setPos(100, 100); canvas->show(); TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem()); @@ -586,7 +618,7 @@ void tst_qquickcanvas::clearColor() //### Can we examine rendering to make sure it is really blue? QQuickCanvas *canvas = new QQuickCanvas; canvas->resize(250, 250); - canvas->move(100, 100); + canvas->setPos(100, 100); canvas->setClearColor(Qt::blue); canvas->show(); QTest::qWaitForWindowShown(canvas); @@ -620,7 +652,7 @@ void tst_qquickcanvas::multipleWindows() c->setPos(100 + i * 30, 100 + i * 20); c->show(); windows << c; - QVERIFY(c->visible()); + QVERIFY(c->isVisible()); } // move them @@ -647,15 +679,15 @@ void tst_qquickcanvas::animationsWhileHidden() QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created); QVERIFY(canvas); - QVERIFY(canvas->visible()); + QVERIFY(canvas->isVisible()); // Now hide the window and verify that it went off screen canvas->hide(); QTest::qWait(10); - QVERIFY(!canvas->visible()); + QVERIFY(!canvas->isVisible()); // Running animaiton should cause it to become visible again shortly. - QTRY_VERIFY(canvas->visible()); + QTRY_VERIFY(canvas->isVisible()); delete canvas; } @@ -672,7 +704,7 @@ void tst_qquickcanvas::headless() QVERIFY(canvas); QTest::qWaitForWindowShown(canvas); - QVERIFY(canvas->visible()); + QVERIFY(canvas->isVisible()); QSignalSpy initialized(canvas, SIGNAL(sceneGraphInitialized())); QSignalSpy invalidated(canvas, SIGNAL(sceneGraphInvalidated())); @@ -770,6 +802,28 @@ void tst_qquickcanvas::ignoreUnhandledMouseEvents() delete canvas; } + +void tst_qquickcanvas::ownershipRootItem() +{ + qmlRegisterType<RootItemAccessor>("QtQuick", 2, 0, "RootItemAccessor"); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("ownershipRootItem.qml")); + QObject* created = component.create(); + + QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created); + QVERIFY(canvas); + QTest::qWaitForWindowShown(canvas); + + RootItemAccessor* accessor = canvas->findChild<RootItemAccessor*>("accessor"); + QVERIFY(accessor); + engine.collectGarbage(); + + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + QVERIFY(!accessor->isRootItemDestroyed()); +} QTEST_MAIN(tst_qquickcanvas) #include "tst_qquickcanvas.moc" diff --git a/tests/auto/quick/qquickgridview/data/gridview1.qml b/tests/auto/quick/qquickgridview/data/gridview1.qml index 4bf6f0b952..1424955689 100644 --- a/tests/auto/quick/qquickgridview/data/gridview1.qml +++ b/tests/auto/quick/qquickgridview/data/gridview1.qml @@ -26,8 +26,9 @@ Rectangle { text: index } Text { - x: 40 + x: 30 text: wrapper.x + ", " + wrapper.y + font.pixelSize: 12 } Text { y: 20 @@ -58,12 +59,11 @@ Rectangle { height: 320 cellWidth: 80 cellHeight: 60 - flow: (testTopToBottom == false) ? GridView.LeftToRight : GridView.TopToBottom - layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight model: testModel delegate: myDelegate header: root.showHeader ? headerFooter : null footer: root.showFooter ? headerFooter : null cacheBuffer: root.cacheBuffer + focus: true } } diff --git a/tests/auto/quick/qquickgridview/data/headerfooter.qml b/tests/auto/quick/qquickgridview/data/headerfooter.qml index 322cfed388..f0f73a0dac 100644 --- a/tests/auto/quick/qquickgridview/data/headerfooter.qml +++ b/tests/auto/quick/qquickgridview/data/headerfooter.qml @@ -2,24 +2,22 @@ import QtQuick 2.0 GridView { id: view - property bool horizontal: false - property bool rtl: false + width: 240 height: 320 model: testModel - - flow: horizontal ? GridView.TopToBottom : GridView.LeftToRight + header: Rectangle { objectName: "header" - width: horizontal ? 20 : view.width - height: horizontal ? view.height : 20 + width: flow == GridView.TopToBottom ? 20 : view.width + height: flow == GridView.TopToBottom ? view.height : 20 color: "red" } footer: Rectangle { objectName: "footer" - width: horizontal ? 30 : view.width - height: horizontal ? view.height : 30 + width: flow == GridView.TopToBottom ? 30 : view.width + height: flow == GridView.TopToBottom ? view.height : 30 color: "blue" } @@ -27,5 +25,4 @@ GridView { cellHeight: 80; delegate: Text { width: 80; height: 80; text: index + "(" + x + ")" } - layoutDirection: rtl ? Qt.RightToLeft : Qt.LeftToRight } diff --git a/tests/auto/quick/qquickgridview/data/layouts.qml b/tests/auto/quick/qquickgridview/data/layouts.qml new file mode 100644 index 0000000000..e00351f1bf --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/layouts.qml @@ -0,0 +1,62 @@ +import QtQuick 2.0 + +Rectangle { + id: root + width: 240 + height: 320 + + property bool showHeader: false + property bool showFooter: false + + Component { + id: myDelegate + Rectangle { + id: wrapper + objectName: "wrapper" + width: 80 + height: 60 + border.width: 1 + Text { text: index } + Text { + x: 30 + text: wrapper.x + ", " + wrapper.y + font.pixelSize: 12 + } + Text { + y: 20 + id: textName + objectName: "textName" + text: name + } + Text { + y: 40 + id: textNumber + objectName: "textNumber" + text: number + } + + property string theName: name + color: GridView.isCurrentItem ? "lightsteelblue" : "white" + } + } + + Component { + id: headerFooter + Rectangle { width: 30; height: 320; color: "blue" } + } + + GridView { + objectName: "grid" + width: 240 + height: 320 + cellWidth: 80 + cellHeight: 60 + flow: (testTopToBottom == false) ? GridView.LeftToRight : GridView.TopToBottom + layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight + verticalLayoutDirection: (testBottomToTop == true) ? GridView.BottomToTop : GridView.TopToBottom + model: testModel + delegate: myDelegate + header: root.showHeader ? headerFooter : null + footer: root.showFooter ? headerFooter : null + } +} diff --git a/tests/auto/quick/qquickgridview/data/resizegrid.qml b/tests/auto/quick/qquickgridview/data/resizegrid.qml new file mode 100644 index 0000000000..7ea2f120e8 --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/resizegrid.qml @@ -0,0 +1,51 @@ +import QtQuick 2.0 + +Rectangle { + id: root + + Component { + id: myDelegate + Rectangle { + id: wrapper + objectName: "wrapper" + width: 80 + height: 60 + border.width: 1 + Text { text: index } + Text { + x: 30 + text: wrapper.x + ", " + wrapper.y + font.pixelSize: 12 + } + Text { + y: 20 + id: textName + objectName: "textName" + text: name + } + color: GridView.isCurrentItem ? "lightsteelblue" : "white" + } + } + + // the grid is specifically placed inside another item to test a bug where + // resizing from anchor changes did not update the content pos correctly + Item { + anchors.fill: parent + + GridView { + clip: true + objectName: "grid" + anchors.fill: parent + cellWidth: 80 + cellHeight: 60 + + flow: (testTopToBottom == false) ? GridView.LeftToRight : GridView.TopToBottom + layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight + verticalLayoutDirection: (testBottomToTop == true) ? GridView.BottomToTop : GridView.TopToBottom + model: testModel + delegate: myDelegate + } + + } +} + diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 22c9004ccc..bc0108c842 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -58,8 +58,10 @@ #include "../shared/visualtestutil.h" #include <QtGui/qguiapplication.h> -Q_DECLARE_METATYPE(Qt::LayoutDirection) Q_DECLARE_METATYPE(QQuickGridView::Flow) +Q_DECLARE_METATYPE(Qt::LayoutDirection) +Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection) +Q_DECLARE_METATYPE(Qt::Key) using namespace QQuickViewTestUtil; using namespace QQuickVisualTestUtil; @@ -76,25 +78,29 @@ private slots: void init(); void items(); void changed(); - void inserted(); - void inserted_more(); - void inserted_more_data(); + void inserted_basic(); + void inserted_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom); + void inserted_defaultLayout_data(); void insertBeforeVisible(); void insertBeforeVisible_data(); - void removed(); - void removed_more(); - void removed_more_data(); + void removed_basic(); + void removed_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom); + void removed_defaultLayout_data(); void addOrRemoveBeforeVisible(); void addOrRemoveBeforeVisible_data(); void clear(); - void moved(); - void moved_data(); - void multipleChanges(); - void multipleChanges_data(); + void moved_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom); + void moved_defaultLayout_data(); + void multipleChanges_condensed() { multipleChanges(true); } + void multipleChanges_condensed_data() { multipleChanges_data(); } + void multipleChanges_uncondensed() { multipleChanges(false); } + void multipleChanges_uncondensed_data() { multipleChanges_data(); } void swapWithFirstItem(); void changeFlow(); void currentIndex(); void noCurrentIndex(); + void keyNavigation(); + void keyNavigation_data(); void defaultValues(); void properties(); void propertyChanges(); @@ -114,7 +120,11 @@ private slots: void header(); void header_data(); void headerFooter(); + void headerFooter_data(); + void resetModel_headerFooter(); void resizeViewAndRepaint(); + void resizeGrid(); + void resizeGrid_data(); void changeColumnCount(); void indexAt_itemAt_data(); void indexAt_itemAt(); @@ -148,12 +158,117 @@ private slots: void multipleTransitions_data(); void multipleDisplaced(); + void inserted_leftToRight_RtL_TtB(); + void inserted_leftToRight_RtL_TtB_data(); + void inserted_leftToRight_LtR_BtT(); + void inserted_leftToRight_LtR_BtT_data(); + void inserted_leftToRight_RtL_BtT(); + void inserted_leftToRight_RtL_BtT_data(); + void inserted_topToBottom_LtR_TtB(); + void inserted_topToBottom_LtR_TtB_data(); + void inserted_topToBottom_RtL_TtB(); + void inserted_topToBottom_RtL_TtB_data(); + void inserted_topToBottom_LtR_BtT(); + void inserted_topToBottom_LtR_BtT_data(); + void inserted_topToBottom_RtL_BtT(); + void inserted_topToBottom_RtL_BtT_data(); + + void removed_leftToRight_RtL_TtB(); + void removed_leftToRight_RtL_TtB_data(); + void removed_leftToRight_LtR_BtT(); + void removed_leftToRight_LtR_BtT_data(); + void removed_leftToRight_RtL_BtT(); + void removed_leftToRight_RtL_BtT_data(); + void removed_topToBottom_LtR_TtB(); + void removed_topToBottom_LtR_TtB_data(); + void removed_topToBottom_RtL_TtB(); + void removed_topToBottom_RtL_TtB_data(); + void removed_topToBottom_LtR_BtT(); + void removed_topToBottom_LtR_BtT_data(); + void removed_topToBottom_RtL_BtT(); + void removed_topToBottom_RtL_BtT_data(); + + void moved_leftToRight_RtL_TtB(); + void moved_leftToRight_RtL_TtB_data(); + void moved_leftToRight_LtR_BtT(); + void moved_leftToRight_LtR_BtT_data(); + void moved_leftToRight_RtL_BtT(); + void moved_leftToRight_RtL_BtT_data(); + void moved_topToBottom_LtR_TtB(); + void moved_topToBottom_LtR_TtB_data(); + void moved_topToBottom_RtL_TtB(); + void moved_topToBottom_RtL_TtB_data(); + void moved_topToBottom_LtR_BtT(); + void moved_topToBottom_LtR_BtT_data(); + void moved_topToBottom_RtL_BtT(); + void moved_topToBottom_RtL_BtT_data(); + private: QList<int> toIntList(const QVariantList &list); void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes); void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes); void matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems); + void multipleChanges(bool condensed); + void multipleChanges_data(); + + QPointF expectedItemPos(QQuickGridView *grid, int index, qreal rowOffset = 0) { + qreal x; + qreal y; + if (grid->flow() == QQuickGridView::FlowLeftToRight) { + int columns = grid->width() / grid->cellWidth(); + x = (index % columns) * grid->cellWidth(); + y = (index / columns) * grid->cellHeight(); + if (grid->effectiveLayoutDirection() == Qt::RightToLeft) { + int col = (index % columns) * grid->cellWidth(); + x = grid->cellWidth() * (columns - 1) - col; + } + + qreal offset = grid->cellHeight() * rowOffset; + if (grid->verticalLayoutDirection() == QQuickItemView::TopToBottom) + y += offset; + else + y = -grid->cellHeight() - y - offset; + } else { + int rows = grid->height() / grid->cellHeight(); + x = (index / rows) * grid->cellWidth(); + y = (index % rows) * grid->cellHeight(); + if (grid->effectiveLayoutDirection() == Qt::RightToLeft) + x = -x - grid->cellWidth(); + + qreal offset = grid->cellWidth() * rowOffset; + if (grid->effectiveLayoutDirection() == Qt::RightToLeft) + x -= offset; + else + x += offset; + if (grid->verticalLayoutDirection() == QQuickItemView::BottomToTop) + y = -grid->cellHeight() - y; + } + return QPointF(x, y); + } + + // Sets contentY (or contentX in TopToBottom flow) according to given row offset + // (in LeftToRight flow) or col offset (in TopToBottom). + bool setContentPos(QQuickGridView *gridview, qreal rowOrColOffset) { + bool contentPosChanged = (rowOrColOffset != 0); + qreal contentOffset = gridview->flow() == QQuickGridView::FlowLeftToRight + ? rowOrColOffset * gridview->cellHeight() + : rowOrColOffset * gridview->cellWidth(); + + if (gridview->flow() == QQuickGridView::FlowLeftToRight) { + if (gridview->verticalLayoutDirection() == QQuickItemView::BottomToTop) + contentOffset = -gridview->height() - contentOffset; + } else { + if (gridview->effectiveLayoutDirection() == Qt::RightToLeft) + contentOffset = -gridview->width() - contentOffset; + } + if (gridview->flow() == QQuickGridView::FlowLeftToRight) + gridview->setContentY(contentOffset); + else + gridview->setContentX(contentOffset); + return contentPosChanged; + } + #ifdef SHARE_VIEWS QQuickView *getView() { if (m_view) { @@ -217,8 +332,6 @@ void tst_QQuickGridView::items() QQmlContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(testFileUrl("gridview1.qml")); qApp->processEvents(); @@ -267,8 +380,6 @@ void tst_QQuickGridView::changed() QQmlContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(testFileUrl("gridview1.qml")); qApp->processEvents(); @@ -290,7 +401,7 @@ void tst_QQuickGridView::changed() delete canvas; } -void tst_QQuickGridView::inserted() +void tst_QQuickGridView::inserted_basic() { QQuickView *canvas = createView(); canvas->show(); @@ -300,11 +411,7 @@ void tst_QQuickGridView::inserted() model.addItem("John", "2345"); model.addItem("Bob", "54321"); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); qApp->processEvents(); @@ -370,12 +477,16 @@ void tst_QQuickGridView::inserted() delete canvas; } -void tst_QQuickGridView::inserted_more() +void tst_QQuickGridView::inserted_defaultLayout(QQuickGridView::Flow flow, + Qt::LayoutDirection horizLayout, + QQuickItemView::VerticalLayoutDirection verticalLayout) { - QFETCH(qreal, contentY); + QFETCH(qreal, contentYRowOffset); QFETCH(int, insertIndex); QFETCH(int, insertCount); - QFETCH(qreal, itemsOffsetAfterMove); + QFETCH(int, insertIndex_ttb); + QFETCH(int, insertCount_ttb); + QFETCH(qreal, rowOffsetAfterMove); QaimModel model; for (int i = 0; i < 30; i++) @@ -384,10 +495,10 @@ void tst_QQuickGridView::inserted_more() QQuickView *canvas = getView(); QQmlContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - - canvas->setSource(testFileUrl("gridview1.qml")); + ctxt->setContextProperty("testTopToBottom", flow == QQuickGridView::FlowTopToBottom); + ctxt->setContextProperty("testRightToLeft", horizLayout == Qt::RightToLeft); + ctxt->setContextProperty("testBottomToTop", verticalLayout == QQuickGridView::BottomToTop); + canvas->setSource(testFileUrl("layouts.qml")); canvas->show(); qApp->processEvents(); @@ -396,8 +507,12 @@ void tst_QQuickGridView::inserted_more() QQuickItem *contentItem = gridview->contentItem(); QTRY_VERIFY(contentItem != 0); - gridview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + if (flow == QQuickGridView::FlowTopToBottom) { + insertIndex = insertIndex_ttb; + insertCount = insertCount_ttb; + } + if (setContentPos(gridview, contentYRowOffset)) + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); QList<QPair<QString, QString> > newData; for (int i=0; i<insertCount; i++) @@ -408,137 +523,152 @@ void tst_QQuickGridView::inserted_more() // check visibleItems.first() is in correct position QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0); QVERIFY(item0); - QCOMPARE(item0->y(), 0.0); + QPointF firstPos(0, 0); + if (horizLayout == Qt::RightToLeft) + firstPos.rx() = flow == QQuickGridView::FlowLeftToRight ? gridview->width() - gridview->cellWidth() : -gridview->cellWidth(); + if (verticalLayout == QQuickItemView::BottomToTop) + firstPos.ry() -= gridview->cellHeight(); + QCOMPARE(item0->pos(), firstPos); QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); int firstVisibleIndex = -1; for (int i=0; i<items.count(); i++) { - if (items[i]->y() >= contentY) { - QQmlExpression e(qmlContext(items[i]), items[i], "index"); - firstVisibleIndex = e.evaluate().toInt(); + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + if (item && item->isVisible()) { + firstVisibleIndex = i; break; } } QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); // Confirm items positioned correctly and indexes correct - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); - QQuickText *name; - QQuickText *number; - for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); - - QCOMPARE(item->x(), (i%3)*80.0); - QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove); - - name = findItem<QQuickText>(contentItem, "textName", i); + QCOMPARE(item->pos(), expectedItemPos(gridview, i, rowOffsetAfterMove)); + QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); QVERIFY(name != 0); QCOMPARE(name->text(), model.name(i)); - number = findItem<QQuickText>(contentItem, "textNumber", i); - QVERIFY(number != 0); - QCOMPARE(number->text(), model.number(i)); } releaseView(canvas); } -void tst_QQuickGridView::inserted_more_data() +void tst_QQuickGridView::inserted_defaultLayout_data() { - QTest::addColumn<qreal>("contentY"); + QTest::addColumn<qreal>("contentYRowOffset"); QTest::addColumn<int>("insertIndex"); QTest::addColumn<int>("insertCount"); - QTest::addColumn<qreal>("itemsOffsetAfterMove"); + QTest::addColumn<int>("insertIndex_ttb"); + QTest::addColumn<int>("insertCount_ttb"); + QTest::addColumn<qreal>("rowOffsetAfterMove"); QTest::newRow("add 1, before visible items") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 5 << 1 + << 9 << 1 << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row // new 1st visible item is at 0 QTest::newRow("add 2, before visible items") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 5 << 2 + << 9 << 2 << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row QTest::newRow("add 3, before visible items") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 5 << 3 - << -60.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move + << 9 << 5 + << -1.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move QTest::newRow("add 5, before visible items") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 5 << 5 - << -60.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos, + << 9 << 7 + << -1.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos, // grid is rearranged and first visible moves forward within its row QTest::newRow("add 6, before visible items") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 5 << 6 - << -60.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move + << 9 << 10 + << -1.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move QTest::newRow("add 1, at start of visible, content at start") << 0.0 << 0 << 1 + << 0 << 1 << 0.0; QTest::newRow("add multiple, at start of visible, content at start") << 0.0 << 0 << 3 + << 0 << 5 << 0.0; QTest::newRow("add 1, at start of visible, content not at start") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 6 << 1 + << 10 << 1 << 0.0; QTest::newRow("add multiple, at start of visible, content not at start") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 6 << 3 + << 10 << 5 << 0.0; QTest::newRow("add 1, at end of visible, content at start") << 0.0 << 17 << 1 + << 14 << 1 << 0.0; - QTest::newRow("add 1, at end of visible, content at start") + QTest::newRow("add row, at end of visible, content at start") << 0.0 << 17 << 3 + << 14 << 5 << 0.0; QTest::newRow("add 1, at end of visible, content not at start") - << 120.0 // show 6-23 - << 23 << 1 + << 2.0 // show 6-23 + << 17+6 << 1 + << 14+10 << 1 << 0.0; QTest::newRow("add multiple, at end of visible, content not at start") - << 120.0 // show 6-23 - << 23 << 3 + << 2.0 // show 6-23 + << 17+6 << 3 + << 14+10 << 5 << 0.0; QTest::newRow("add 1, after visible, content at start") << 0.0 << 20 << 1 + << 18 << 1 << 0.0; - QTest::newRow("add 1, after visible, content at start") + QTest::newRow("add row, after visible, content at start") << 0.0 << 20 << 3 + << 18 << 5 << 0.0; QTest::newRow("add 1, after visible, content not at start") - << 120.0 // show 6-23 - << 24 << 1 + << 2.0 // show 6-23 + << 20+6 << 1 + << 18+10 << 1 << 0.0; QTest::newRow("add multiple, after visible, content not at start") - << 120.0 // show 6-23 - << 24 << 3 + << 2.0 // show 6-23 + << 20+6 << 3 + << 18+10 << 3 << 0.0; } @@ -557,8 +687,6 @@ void tst_QQuickGridView::insertBeforeVisible() QQmlContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(testFileUrl("gridview1.qml")); canvas->show(); qApp->processEvents(); @@ -633,7 +761,7 @@ void tst_QQuickGridView::insertBeforeVisible_data() QTest::newRow("insert multiple at 1, 500 buffer") << 1 << 6 << 500; } -void tst_QQuickGridView::removed() +void tst_QQuickGridView::removed_basic() { QQuickView *canvas = createView(); canvas->show(); @@ -642,11 +770,7 @@ void tst_QQuickGridView::removed() for (int i = 0; i < 40; i++) model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); qApp->processEvents(); @@ -778,16 +902,19 @@ void tst_QQuickGridView::removed() delete canvas; } -void tst_QQuickGridView::removed_more() +void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow, + Qt::LayoutDirection horizLayout, + QQuickItemView::VerticalLayoutDirection verticalLayout) { - QFETCH(qreal, contentY); + QFETCH(qreal, contentYRowOffset); QFETCH(int, removeIndex); QFETCH(int, removeCount); - QFETCH(qreal, itemsOffsetAfterMove); + QFETCH(int, removeIndex_ttb); + QFETCH(int, removeCount_ttb); + QFETCH(qreal, rowOffsetAfterMove); QFETCH(QString, firstVisible); + QFETCH(QString, firstVisible_ttb); - QQuickText *name; - QQuickText *number; QQuickView *canvas = getView(); QaimModel model; @@ -796,9 +923,10 @@ void tst_QQuickGridView::removed_more() QQmlContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - canvas->setSource(testFileUrl("gridview1.qml")); + ctxt->setContextProperty("testTopToBottom", flow == QQuickGridView::FlowTopToBottom); + ctxt->setContextProperty("testRightToLeft", horizLayout == Qt::RightToLeft); + ctxt->setContextProperty("testBottomToTop", verticalLayout == QQuickGridView::BottomToTop); + canvas->setSource(testFileUrl("layouts.qml")); canvas->show(); qApp->processEvents(); @@ -807,8 +935,13 @@ void tst_QQuickGridView::removed_more() QQuickItem *contentItem = gridview->contentItem(); QTRY_VERIFY(contentItem != 0); - gridview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + if (flow == QQuickGridView::FlowTopToBottom) { + removeIndex = removeIndex_ttb; + removeCount = removeCount_ttb; + firstVisible = firstVisible_ttb; + } + if (setContentPos(gridview, contentYRowOffset)) + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); model.removeItems(removeIndex, removeCount); QTRY_COMPARE(gridview->property("count").toInt(), model.count()); @@ -816,161 +949,183 @@ void tst_QQuickGridView::removed_more() QString firstName; int firstVisibleIndex = -1; QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); + QRectF viewRect(gridview->contentX(), gridview->contentY(), gridview->width(), gridview->height()); for (int i=0; i<items.count(); i++) { - if (items[i]->y() >= contentY) { - QQmlExpression e(qmlContext(items[i]), items[i], "index"); - firstVisibleIndex = e.evaluate().toInt(); - QQmlExpression en(qmlContext(items[i]), items[i], "name"); - firstName = en.evaluate().toString(); - break; + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + if (item) { + QRectF itemRect(item->x(), item->y(), item->width(), item->height()); + if (item->isVisible() && viewRect.intersects(itemRect)) { + firstVisibleIndex = i; + QQmlExpression en(qmlContext(item), item, "name"); + firstName = en.evaluate().toString(); + break; + } } } QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); QCOMPARE(firstName, firstVisible); // Confirm items positioned correctly and indexes correct - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); - for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); - - QTRY_COMPARE(item->x(), (i%3)*80.0); - QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove); - - name = findItem<QQuickText>(contentItem, "textName", i); + QCOMPARE(item->pos(), expectedItemPos(gridview, i, rowOffsetAfterMove)); + QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); - number = findItem<QQuickText>(contentItem, "textNumber", i); - QVERIFY(number != 0); - QTRY_COMPARE(number->text(), model.number(i)); } releaseView(canvas); } -void tst_QQuickGridView::removed_more_data() +void tst_QQuickGridView::removed_defaultLayout_data() { - QTest::addColumn<qreal>("contentY"); + QTest::addColumn<qreal>("contentYRowOffset"); QTest::addColumn<int>("removeIndex"); QTest::addColumn<int>("removeCount"); - QTest::addColumn<qreal>("itemsOffsetAfterMove"); + QTest::addColumn<int>("removeIndex_ttb"); + QTest::addColumn<int>("removeCount_ttb"); + QTest::addColumn<qreal>("rowOffsetAfterMove"); QTest::addColumn<QString>("firstVisible"); + QTest::addColumn<QString>("firstVisible_ttb"); QTest::newRow("remove 1, before visible items") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 2 << 1 - << 0.0 << "Item7"; + << 4 << 1 + << 0.0 << "Item7" << "Item11"; QTest::newRow("remove 1, before visible position") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 3 << 1 - << 0.0 << "Item7"; + << 5 << 1 + << 0.0 << "Item7" << "Item11"; - QTest::newRow("remove multiple, all before visible items") - << 120.0 + QTest::newRow("remove multiple (1 row), all before visible items") + << 2.0 << 1 << 3 - << 60.0 << "Item6"; // removed top row, slide down by 1 row + << 1 << 5 + << 1.0 << "Item6" << "Item10"; // removed top row, slide down by 1 row QTest::newRow("remove multiple, all before visible items, remove item 0") - << 120.0 + << 2.0 << 0 << 4 - << 60.0 << "Item7"; // removed top row, slide down by 1 row + << 0 << 6 + << 1.0 << "Item7" << "Item11"; // removed top row, slide down by 1 row QTest::newRow("remove multiple rows, all before visible items") - << 240.0 // show 12-29 + << 4.0 // show 12-29 << 1 << 7 - << 120.0 << "Item13"; + << 1 << 12 + << 2.0 << "Item13" << "Item17"; QTest::newRow("remove one row before visible, content y not on item border") - << 100.0 + << 1.5 << 0 << 3 - << 60.0 << "Item6"; // 1 row removed + << 0 << 5 + << 1.0 << "Item3" << "Item5"; // 1 row removed QTest::newRow("remove mix of visible/non-visible") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 2 << 3 - << 60.0 << "Item6"; // 1 row removed + << 4 << 3 + << 1.0 << "Item6" << "Item8"; // 1 row removed // remove 3,4,5 before the visible pos, first row moves down to just before the visible pos, // items 6,7 are removed from view, item 8 slides up to original pos of item 6 (120px) QTest::newRow("remove multiple, mix of items from before and within visible items") - << 120.0 + << 2.0 << 3 << 5 - << 60.0 << "Item8"; // adjust for the 1 row removed before the visible + << 5 << 7 + << 1.0 << "Item8" << "Item12"; // adjust for the 1 row removed before the visible QTest::newRow("remove multiple, mix of items from before and within visible items, remove item 0") - << 120.0 + << 2.0 << 0 << 8 - << 60.0 * 2 << "Item8"; // adjust for the 2 rows removed before the visible + << 0 << 12 + << 1.0 * 2 << "Item8" << "Item12"; // adjust for the 2 rows removed before the visible QTest::newRow("remove 1, from start of visible, content at start") << 0.0 << 0 << 1 - << 0.0 << "Item1"; + << 0 << 1 + << 0.0 << "Item1" << "Item1"; QTest::newRow("remove multiple, from start of visible, content at start") << 0.0 << 0 << 3 - << 0.0 << "Item3"; + << 0 << 5 + << 0.0 << "Item3" << "Item5"; QTest::newRow("remove 1, from start of visible, content not at start") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 4 << 1 - << 0.0 << "Item7"; + << 7 << 1 + << 0.0 << "Item7" << "Item11"; QTest::newRow("remove multiple, from start of visible, content not at start") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 4 << 3 - << 0.0 << "Item9"; + << 7 << 5 + << 0.0 << "Item9" << "Item15"; QTest::newRow("remove 1, from middle of visible, content at start") << 0.0 << 10 << 1 - << 0.0 << "Item0"; + << 12 << 1 + << 0.0 << "Item0" << "Item0"; QTest::newRow("remove multiple, from middle of visible, content at start") << 0.0 << 10 << 5 - << 0.0 << "Item0"; + << 12 << 5 + << 0.0 << "Item0" << "Item0"; QTest::newRow("remove 1, from middle of visible, content not at start") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 10 << 1 - << 0.0 << "Item6"; + << 12 << 1 + << 0.0 << "Item6" << "Item10"; QTest::newRow("remove multiple, from middle of visible, content not at start") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 10 << 5 - << 0.0 << "Item6"; + << 12 << 7 + << 0.0 << "Item6" << "Item10"; QTest::newRow("remove 1, after visible, content at start") << 0.0 << 16 << 1 - << 0.0 << "Item0"; + << 15 << 1 + << 0.0 << "Item0" << "Item0"; QTest::newRow("remove multiple, after visible, content at start") << 0.0 << 16 << 5 - << 0.0 << "Item0"; + << 15 << 7 + << 0.0 << "Item0" << "Item0"; QTest::newRow("remove 1, after visible, content not at start") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 16+4 << 1 - << 0.0 << "Item6"; + << 15+10 << 1 + << 0.0 << "Item6" << "Item10"; QTest::newRow("remove multiple, after visible, content not at start") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 16+4 << 5 - << 0.0 << "Item6"; + << 15+10 << 7 + << 0.0 << "Item6" << "Item10"; QTest::newRow("remove multiple, mix of items from within and after visible items") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 20 << 5 - << 0.0 << "Item6"; + << 22 << 7 + << 0.0 << "Item6" << "Item10"; } void tst_QQuickGridView::addOrRemoveBeforeVisible() @@ -988,10 +1143,7 @@ void tst_QQuickGridView::addOrRemoveBeforeVisible() for (int i = 0; i < 30; i++) model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); @@ -1067,11 +1219,7 @@ void tst_QQuickGridView::clear() for (int i = 0; i < 30; i++) model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); canvas->show(); qApp->processEvents(); @@ -1098,28 +1246,31 @@ void tst_QQuickGridView::clear() delete canvas; } -void tst_QQuickGridView::moved() +void tst_QQuickGridView::moved_defaultLayout(QQuickGridView::Flow flow, + Qt::LayoutDirection horizLayout, + QQuickItemView::VerticalLayoutDirection verticalLayout) { - QFETCH(qreal, contentY); + QFETCH(qreal, contentYRowOffset); QFETCH(int, from); QFETCH(int, to); QFETCH(int, count); - QFETCH(qreal, itemsOffsetAfterMove); + QFETCH(int, from_ttb); + QFETCH(int, to_ttb); + QFETCH(int, count_ttb); + QFETCH(qreal, rowOffsetAfterMove); - QQuickText *name; - QQuickText *number; QQuickView *canvas = getView(); QaimModel model; for (int i = 0; i < 30; i++) model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); + QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - - canvas->setSource(testFileUrl("gridview1.qml")); + ctxt->setContextProperty("testTopToBottom", flow == QQuickGridView::FlowTopToBottom); + ctxt->setContextProperty("testRightToLeft", horizLayout == Qt::RightToLeft); + ctxt->setContextProperty("testBottomToTop", verticalLayout == QQuickGridView::BottomToTop); + canvas->setSource(testFileUrl("layouts.qml")); canvas->show(); qApp->processEvents(); @@ -1132,32 +1283,41 @@ void tst_QQuickGridView::moved() QQuickItem *currentItem = gridview->currentItem(); QTRY_VERIFY(currentItem != 0); - if (contentY != 0) { - gridview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + if (flow == QQuickGridView::FlowTopToBottom) { + from = from_ttb; + to = to_ttb; + count = count_ttb; } + if (setContentPos(gridview, contentYRowOffset)) + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); model.moveItems(from, to, count); QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); // Confirm items positioned correctly and indexes correct - int firstVisibleIndex = qCeil(contentY / 60.0) * 3; - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); - for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { - if (i >= firstVisibleIndex + 18) // index has moved out of view - continue; + QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); + int firstVisibleIndex = -1; + for (int i=0; i<items.count(); i++) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); - QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); - - QTRY_COMPARE(item->x(), (i%3)*80.0); - QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove); + if (item && item->isVisible()) { + firstVisibleIndex = i; + break; + } + } + QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); - name = findItem<QQuickText>(contentItem, "textName", i); + for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + if (!item && + ( (flow == QQuickGridView::FlowLeftToRight && i >= firstVisibleIndex + (3*6)) + || flow == QQuickGridView::FlowTopToBottom && i >= firstVisibleIndex + (5*3) ) ) { + continue; // index has moved out of view + } + QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); + QCOMPARE(item->pos(), expectedItemPos(gridview, i, rowOffsetAfterMove)); + QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); - number = findItem<QQuickText>(contentItem, "textNumber", i); - QVERIFY(number != 0); - QTRY_COMPARE(number->text(), model.number(i)); // current index should have been updated if (item == currentItem) @@ -1167,13 +1327,16 @@ void tst_QQuickGridView::moved() releaseView(canvas); } -void tst_QQuickGridView::moved_data() +void tst_QQuickGridView::moved_defaultLayout_data() { - QTest::addColumn<qreal>("contentY"); + QTest::addColumn<qreal>("contentYRowOffset"); QTest::addColumn<int>("from"); QTest::addColumn<int>("to"); QTest::addColumn<int>("count"); - QTest::addColumn<qreal>("itemsOffsetAfterMove"); + QTest::addColumn<int>("from_ttb"); + QTest::addColumn<int>("to_ttb"); + QTest::addColumn<int>("count_ttb"); + QTest::addColumn<qreal>("rowOffsetAfterMove"); // model starts with 30 items, each 80x60, in area 240x320 // 18 items should be visible at a time @@ -1185,143 +1348,170 @@ void tst_QQuickGridView::moved_data() QTest::newRow("move 1 forwards, within visible items") << 0.0 << 1 << 8 << 1 + << 2 << 12 << 1 << 0.0; QTest::newRow("move 1 forwards, from non-visible -> visible") - << 120.0 // show 6-23 - << 1 << 23 << 1 + << 2.0 // show 6-23 + << 1 << 8+6 << 1 + << 2 << 12+10 << 1 << 0.0; QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)") - << 120.0 // // show 6-23 + << 2.0 // // show 6-23 << 0 << 6 << 1 + << 0 << 10 << 1 << 0.0; QTest::newRow("move 1 forwards, from visible -> non-visible") << 0.0 << 1 << 20 << 1 + << 1 << 20 << 1 << 0.0; QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)") << 0.0 << 0 << 20 << 1 + << 0 << 20 << 1 << 0.0; QTest::newRow("move 1 backwards, within visible items") << 0.0 << 10 << 5 << 1 + << 10 << 5 << 1 << 0.0; QTest::newRow("move 1 backwards, within visible items (to first index)") << 0.0 << 10 << 0 << 1 + << 10 << 0 << 1 << 0.0; QTest::newRow("move 1 backwards, from non-visible -> visible") << 0.0 << 28 << 8 << 1 + << 28 << 8 << 1 << 0.0; QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)") << 0.0 << 29 << 14 << 1 + << 29 << 14 << 1 << 0.0; QTest::newRow("move 1 backwards, from visible -> non-visible") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 7 << 1 << 1 + << 10 << 1 << 1 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 7 << 0 << 1 + << 10 << 0 << 1 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move QTest::newRow("move multiple forwards, within visible items") << 0.0 << 0 << 5 << 3 + << 0 << 7 << 5 << 0.0; QTest::newRow("move multiple backwards, within visible items (move first item)") << 0.0 << 10 << 0 << 3 + << 12 << 0 << 5 << 0.0; QTest::newRow("move multiple forwards, before visible items") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 3 << 4 << 3 // 3, 4, 5 move to after 6 - << 60.0; // row of 3,4,5 has moved down + << 5 << 6 << 5 + << 1.0; // row of 3,4,5 has moved down QTest::newRow("move multiple forwards, from non-visible -> visible") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 1 << 6 << 3 - << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is + << 1 << 10 << 5 + << 1.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 0 << 6 << 3 - << 60.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row + << 0 << 10 << 5 + << 1.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row QTest::newRow("move multiple forwards, mix of non-visible/visible") - << 120.0 + << 2.0 << 3 << 16 << 6 - << 60.0; // top two rows removed, third row is now the first visible + << 5 << 18 << 10 + << 1.0; // top two rows removed, third row is now the first visible QTest::newRow("move multiple forwards, to bottom of view") << 0.0 << 5 << 13 << 5 + << 1 << 8 << 6 << 0.0; QTest::newRow("move multiple forwards, to bottom of view, first row -> last") << 0.0 << 0 << 15 << 3 + << 0 << 10 << 5 << 0.0; QTest::newRow("move multiple forwards, to bottom of view, content y not 0") - << 120.0 + << 2.0 << 5+4 << 13+4 << 5 + << 11 << 19 << 6 << 0.0; QTest::newRow("move multiple forwards, from visible -> non-visible") << 0.0 << 1 << 16 << 3 + << 1 << 18 << 5 << 0.0; QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)") << 0.0 << 0 << 16 << 3 + << 1 << 18 << 5 << 0.0; QTest::newRow("move multiple backwards, within visible items") << 0.0 << 4 << 1 << 3 + << 7 << 1 << 5 << 0.0; QTest::newRow("move multiple backwards, from non-visible -> visible") << 0.0 << 20 << 4 << 3 + << 20 << 4 << 5 << 0.0; QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)") << 0.0 << 27 << 10 << 3 + << 25 << 8 << 5 << 0.0; QTest::newRow("move multiple backwards, from visible -> non-visible") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 16 << 1 << 3 - << -60.0; // to minimize movement, items are added above visible area, all items move up by 1 row + << 17 << 1 << 5 + << -1.0; // to minimize movement, items are added above visible area, all items move up by 1 row QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)") - << 120.0 // show 6-23 + << 2.0 // show 6-23 << 16 << 0 << 3 - << -60.0; // 16,17,18 move to above item 0, all items move up by 1 row + << 17 << 0 << 5 + << -1.0; // 16,17,18 move to above item 0, all items move up by 1 row } -void tst_QQuickGridView::multipleChanges() +void tst_QQuickGridView::multipleChanges(bool condensed) { QFETCH(int, startCount); QFETCH(QList<ListChange>, changes); @@ -1334,11 +1524,7 @@ void tst_QQuickGridView::multipleChanges() for (int i = 0; i < startCount; i++) model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); canvas->show(); qApp->processEvents(); @@ -1359,26 +1545,26 @@ void tst_QQuickGridView::multipleChanges() } case ListChange::Removed: model.removeItems(changes[i].index, changes[i].count); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); break; case ListChange::Moved: model.moveItems(changes[i].index, changes[i].to, changes[i].count); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); break; case ListChange::SetCurrent: gridview->setCurrentIndex(changes[i].index); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); break; case ListChange::SetContentY: gridview->setContentY(changes[i].pos); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); break; } + if (condensed) { + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + } } + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); - QTRY_COMPARE(gridview->count(), newCount); + QCOMPARE(gridview->count(), newCount); QCOMPARE(gridview->count(), model.count()); - QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex); + QCOMPARE(gridview->currentIndex(), newCurrentIndex); QQuickText *name; QQuickText *number; @@ -1547,6 +1733,28 @@ void tst_QQuickGridView::multipleChanges_data() << ListChange::remove(0, 5) << ListChange::insert(0, 5) ) << 5 << -1; + + QTest::newRow("remove, scroll") << 30 << (QList<ListChange>() + << ListChange::remove(20, 5) + << ListChange::setContentY(20) + ) << 25 << 0; + + QTest::newRow("insert, scroll") << 10 << (QList<ListChange>() + << ListChange::insert(9, 5) + << ListChange::setContentY(20) + ) << 15 << 0; + + QTest::newRow("move, scroll") << 20 << (QList<ListChange>() + << ListChange::move(15, 8, 3) + << ListChange::setContentY(0) + ) << 20 << 0; + + QTest::newRow("clear, insert, scroll") << 30 << (QList<ListChange>() + << ListChange::setContentY(20) + << ListChange::remove(0, 30) + << ListChange::insert(0, 2) + << ListChange::setContentY(0) + ) << 2 << 0; } @@ -1559,11 +1767,7 @@ void tst_QQuickGridView::swapWithFirstItem() for (int i = 0; i < 30; i++) model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); canvas->show(); qApp->processEvents(); @@ -1610,57 +1814,11 @@ void tst_QQuickGridView::currentIndex() QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y()); QCOMPARE(gridview->contentY(), 400.0); - gridview->moveCurrentIndexRight(); - QCOMPARE(gridview->currentIndex(), 36); - gridview->moveCurrentIndexDown(); - QCOMPARE(gridview->currentIndex(), 39); - gridview->moveCurrentIndexUp(); - QCOMPARE(gridview->currentIndex(), 36); - gridview->moveCurrentIndexLeft(); - QCOMPARE(gridview->currentIndex(), 35); - - // wait until motion stops - QTRY_VERIFY(gridview->verticalVelocity() == 0.0); - - // no wrap gridview->setCurrentIndex(0); QCOMPARE(gridview->currentIndex(), 0); // confirm that the velocity is updated QTRY_VERIFY(gridview->verticalVelocity() != 0.0); - gridview->moveCurrentIndexUp(); - QCOMPARE(gridview->currentIndex(), 0); - - gridview->moveCurrentIndexLeft(); - QCOMPARE(gridview->currentIndex(), 0); - - gridview->setCurrentIndex(model.count()-1); - QCOMPARE(gridview->currentIndex(), model.count()-1); - - gridview->moveCurrentIndexRight(); - QCOMPARE(gridview->currentIndex(), model.count()-1); - - gridview->moveCurrentIndexDown(); - QCOMPARE(gridview->currentIndex(), model.count()-1); - - // with wrap - gridview->setWrapEnabled(true); - - gridview->setCurrentIndex(0); - QCOMPARE(gridview->currentIndex(), 0); - - gridview->moveCurrentIndexLeft(); - QCOMPARE(gridview->currentIndex(), model.count()-1); - - qApp->processEvents(); - QTRY_COMPARE(gridview->contentY(), 880.0); - - gridview->moveCurrentIndexRight(); - QCOMPARE(gridview->currentIndex(), 0); - - QTRY_COMPARE(gridview->contentY(), 0.0); - - // footer should become visible if it is out of view, and then current index moves to the first row canvas->rootObject()->setProperty("showFooter", true); QTRY_VERIFY(gridview->footerItem()); @@ -1679,78 +1837,6 @@ void tst_QQuickGridView::currentIndex() QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height()); canvas->rootObject()->setProperty("showHeader", false); - - // Test keys - canvas->requestActivateWindow(); - QTest::qWaitForWindowShown(canvas); - QTRY_VERIFY(qGuiApp->focusWindow() == canvas); - - gridview->setCurrentIndex(0); - - QTest::keyClick(canvas, Qt::Key_Down); - QCOMPARE(gridview->currentIndex(), 3); - - QTest::keyClick(canvas, Qt::Key_Up); - QCOMPARE(gridview->currentIndex(), 0); - - // hold down Key_Down - for (int i=0; i<(model.count() / 3) - 1; i++) { - QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true); - QTRY_COMPARE(gridview->currentIndex(), i*3 + 3); - } - QTest::keyRelease(canvas, Qt::Key_Down); - QTRY_COMPARE(gridview->currentIndex(), 57); - QTRY_COMPARE(gridview->contentY(), 880.0); - - // hold down Key_Up - for (int i=(model.count() / 3) - 1; i > 0; i--) { - QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true); - QTRY_COMPARE(gridview->currentIndex(), i*3 - 3); - } - QTest::keyRelease(canvas, Qt::Key_Up); - QTRY_COMPARE(gridview->currentIndex(), 0); - QTRY_COMPARE(gridview->contentY(), 0.0); - - - gridview->setFlow(QQuickGridView::TopToBottom); - - canvas->requestActivateWindow(); - QTest::qWaitForWindowShown(canvas); - QVERIFY(qGuiApp->focusWindow() == canvas); - qApp->processEvents(); - - QTest::keyClick(canvas, Qt::Key_Right); - QCOMPARE(gridview->currentIndex(), 5); - - QTest::keyClick(canvas, Qt::Key_Left); - QCOMPARE(gridview->currentIndex(), 0); - - QTest::keyClick(canvas, Qt::Key_Down); - QCOMPARE(gridview->currentIndex(), 1); - - QTest::keyClick(canvas, Qt::Key_Up); - QCOMPARE(gridview->currentIndex(), 0); - - // hold down Key_Right - for (int i=0; i<(model.count() / 5) - 1; i++) { - QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true); - QTRY_COMPARE(gridview->currentIndex(), i*5 + 5); - } - - QTest::keyRelease(canvas, Qt::Key_Right); - QTRY_COMPARE(gridview->currentIndex(), 55); - QTRY_COMPARE(gridview->contentX(), 720.0); - - // hold down Key_Left - for (int i=(model.count() / 5) - 1; i > 0; i--) { - QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true); - QTRY_COMPARE(gridview->currentIndex(), i*5 - 5); - } - QTest::keyRelease(canvas, Qt::Key_Left); - QTRY_COMPARE(gridview->currentIndex(), 0); - QTRY_COMPARE(gridview->contentX(), 0.0); - - // turn off auto highlight gridview->setHighlightFollowsCurrentItem(false); QVERIFY(gridview->highlightFollowsCurrentItem() == false); @@ -1774,54 +1860,6 @@ void tst_QQuickGridView::currentIndex() QVERIFY(!gridview->highlightItem()); QVERIFY(!gridview->currentItem()); - gridview->setHighlightFollowsCurrentItem(true); - - gridview->setFlow(QQuickGridView::LeftToRight); - gridview->setLayoutDirection(Qt::RightToLeft); - - canvas->requestActivateWindow(); - QTest::qWaitForWindowShown(canvas); - QTRY_VERIFY(qGuiApp->focusWindow() == canvas); - qApp->processEvents(); - - gridview->setCurrentIndex(35); - - QTest::keyClick(canvas, Qt::Key_Right); - QCOMPARE(gridview->currentIndex(), 34); - - QTest::keyClick(canvas, Qt::Key_Down); - QCOMPARE(gridview->currentIndex(), 37); - - QTest::keyClick(canvas, Qt::Key_Up); - QCOMPARE(gridview->currentIndex(), 34); - - QTest::keyClick(canvas, Qt::Key_Left); - QCOMPARE(gridview->currentIndex(), 35); - - - // turn off auto highlight - gridview->setHighlightFollowsCurrentItem(false); - QVERIFY(gridview->highlightFollowsCurrentItem() == false); - QVERIFY(gridview->highlightItem()); - hlPosX = gridview->highlightItem()->x(); - hlPosY = gridview->highlightItem()->y(); - - gridview->setCurrentIndex(5); - QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX); - QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY); - - // insert item before currentIndex - gridview->setCurrentIndex(28); - model.insertItem(0, "Foo", "1111"); - QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29); - - // check removing highlight by setting currentIndex to -1; - gridview->setCurrentIndex(-1); - - QCOMPARE(gridview->currentIndex(), -1); - QVERIFY(!gridview->highlightItem()); - QVERIFY(!gridview->currentItem()); - // moving currentItem out of view should make it invisible gridview->setCurrentIndex(0); QTRY_VERIFY(gridview->currentItem()->isVisible()); @@ -1868,6 +1906,199 @@ void tst_QQuickGridView::noCurrentIndex() delete canvas; } +void tst_QQuickGridView::keyNavigation() +{ + QFETCH(QQuickGridView::Flow, flow); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); + QFETCH(Qt::Key, forwardsKey); + QFETCH(Qt::Key, backwardsKey); + QFETCH(QPointF, contentPosAtFirstItem); + QFETCH(QPointF, contentPosAtLastItem); + QFETCH(int, indexRightOf7); + QFETCH(int, indexLeftOf7); + QFETCH(int, indexUpFrom7); + QFETCH(int, indexDownFrom7); + + QmlListModel model; + for (int i = 0; i < 18; i++) + model.addItem("Item" + QString::number(i), ""); + + QQuickView *canvas = getView(); + canvas->rootContext()->setContextProperty("testModel", &model); + canvas->setSource(testFileUrl("gridview1.qml")); + canvas->show(); + qApp->processEvents(); + + QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + gridview->setFlow(flow); + gridview->setLayoutDirection(layoutDirection); + gridview->setVerticalLayoutDirection(verticalLayoutDirection); + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + + canvas->requestActivateWindow(); + QTRY_VERIFY(qGuiApp->focusWindow() == canvas); + QCOMPARE(gridview->currentIndex(), 0); + + QTest::keyClick(canvas, forwardsKey); + QCOMPARE(gridview->currentIndex(), 1); + + QTest::keyClick(canvas, backwardsKey); + QCOMPARE(gridview->currentIndex(), 0); + + gridview->setCurrentIndex(7); + gridview->moveCurrentIndexRight(); + QCOMPARE(gridview->currentIndex(), indexRightOf7); + gridview->moveCurrentIndexLeft(); + QCOMPARE(gridview->currentIndex(), 7); + gridview->moveCurrentIndexLeft(); + QCOMPARE(gridview->currentIndex(), indexLeftOf7); + gridview->moveCurrentIndexRight(); + QCOMPARE(gridview->currentIndex(), 7); + gridview->moveCurrentIndexUp(); + QCOMPARE(gridview->currentIndex(), indexUpFrom7); + gridview->moveCurrentIndexDown(); + QCOMPARE(gridview->currentIndex(), 7); + gridview->moveCurrentIndexDown(); + QCOMPARE(gridview->currentIndex(), indexDownFrom7); + + gridview->setCurrentIndex(7); + QTest::keyClick(canvas, Qt::Key_Right); + QCOMPARE(gridview->currentIndex(), indexRightOf7); + QTest::keyClick(canvas, Qt::Key_Left); + QCOMPARE(gridview->currentIndex(), 7); + QTest::keyClick(canvas, Qt::Key_Left); + QCOMPARE(gridview->currentIndex(), indexLeftOf7); + QTest::keyClick(canvas, Qt::Key_Right); + QCOMPARE(gridview->currentIndex(), 7); + QTest::keyClick(canvas, Qt::Key_Up); + QCOMPARE(gridview->currentIndex(), indexUpFrom7); + QTest::keyClick(canvas, Qt::Key_Down); + QCOMPARE(gridview->currentIndex(), 7); + QTest::keyClick(canvas, Qt::Key_Down); + QCOMPARE(gridview->currentIndex(), indexDownFrom7); + + // hold down a key to go forwards + gridview->setCurrentIndex(0); + for (int i=0; i<model.count()-1; i++) { +// QTest::qWait(500); + QTest::simulateEvent(canvas, true, forwardsKey, Qt::NoModifier, "", true); + QTRY_COMPARE(gridview->currentIndex(), i+1); + } + QTest::keyRelease(canvas, forwardsKey); + QTRY_COMPARE(gridview->currentIndex(), model.count()-1); + QTRY_COMPARE(gridview->contentX(), contentPosAtLastItem.x()); + QTRY_COMPARE(gridview->contentY(), contentPosAtLastItem.y()); + + // hold down a key to go backwards + for (int i=model.count()-1; i > 0; i--) { + QTest::simulateEvent(canvas, true, backwardsKey, Qt::NoModifier, "", true); + QTRY_COMPARE(gridview->currentIndex(), i-1); + } + QTest::keyRelease(canvas, backwardsKey); + QTRY_COMPARE(gridview->currentIndex(), 0); + QTRY_COMPARE(gridview->contentX(), contentPosAtFirstItem.x()); + QTRY_COMPARE(gridview->contentY(), contentPosAtFirstItem.y()); + + // no wrap + QVERIFY(!gridview->isWrapEnabled()); + QTest::keyClick(canvas, forwardsKey); + QCOMPARE(gridview->currentIndex(), 1); + QTest::keyClick(canvas, backwardsKey); + QCOMPARE(gridview->currentIndex(), 0); + + QTest::keyClick(canvas, backwardsKey); + QCOMPARE(gridview->currentIndex(), 0); + + // with wrap + gridview->setWrapEnabled(true); + QVERIFY(gridview->isWrapEnabled()); + + QTest::keyClick(canvas, backwardsKey); + QCOMPARE(gridview->currentIndex(), model.count()-1); + QTRY_COMPARE(gridview->contentX(), contentPosAtLastItem.x()); + QTRY_COMPARE(gridview->contentY(), contentPosAtLastItem.y()); + + QTest::keyClick(canvas, forwardsKey); + QCOMPARE(gridview->currentIndex(), 0); + QTRY_COMPARE(gridview->contentX(), contentPosAtFirstItem.x()); + QTRY_COMPARE(gridview->contentY(), contentPosAtFirstItem.y()); + + releaseView(canvas); +} + +void tst_QQuickGridView::keyNavigation_data() +{ + QTest::addColumn<QQuickGridView::Flow>("flow"); + QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); + QTest::addColumn<Qt::Key>("forwardsKey"); + QTest::addColumn<Qt::Key>("backwardsKey"); + QTest::addColumn<QPointF>("contentPosAtFirstItem"); + QTest::addColumn<QPointF>("contentPosAtLastItem"); + QTest::addColumn<int>("indexRightOf7"); + QTest::addColumn<int>("indexLeftOf7"); + QTest::addColumn<int>("indexUpFrom7"); + QTest::addColumn<int>("indexDownFrom7"); + + QTest::newRow("LeftToRight, LtR, TtB") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom + << Qt::Key_Right << Qt::Key_Left + << QPointF(0, 0) + << QPointF(0, 40) + << 8 << 6 << 4 << 10; + + QTest::newRow("LeftToRight, RtL, TtB") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom + << Qt::Key_Left << Qt::Key_Right + << QPointF(0, 0) + << QPointF(0, 40) + << 6 << 8 << 4 << 10; + + QTest::newRow("LeftToRight, LtR, BtT") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop + << Qt::Key_Right << Qt::Key_Left + << QPointF(0, -320) + << QPointF(0, -360) + << 8 << 6 << 10 << 4; + + QTest::newRow("LeftToRight, RtL, BtT") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop + << Qt::Key_Left << Qt::Key_Right + << QPointF(0, -320) + << QPointF(0, -360) + << 6 << 8 << 10 << 4; + + QTest::newRow("TopToBottom, LtR, TtB") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom + << Qt::Key_Down << Qt::Key_Up + << QPointF(0, 0) + << QPointF(80, 0) + << 12 << 2 << 6 << 8; + + QTest::newRow("TopToBottom, RtL, TtB") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom + << Qt::Key_Down << Qt::Key_Up + << QPointF(-240, 0) + << QPointF(-320, 0) + << 2 << 12 << 6 << 8; + + QTest::newRow("TopToBottom, LtR, BtT") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop + << Qt::Key_Up << Qt::Key_Down + << QPointF(0, -320) + << QPointF(80, -320) + << 12 << 2 << 8 << 6; + + QTest::newRow("TopToBottom, RtL, BtT") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop + << Qt::Key_Up << Qt::Key_Down + << QPointF(-240, -320) + << QPointF(-320, -320) + << 2 << 12 << 8 << 6; +} + void tst_QQuickGridView::changeFlow() { QQuickView *canvas = createView(); @@ -1880,8 +2111,9 @@ void tst_QQuickGridView::changeFlow() ctxt->setContextProperty("testModel", &model); ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); + ctxt->setContextProperty("testBottomToTop", QVariant(false)); - canvas->setSource(testFileUrl("gridview1.qml")); + canvas->setSource(testFileUrl("layouts.qml")); qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); @@ -2027,15 +2259,15 @@ void tst_QQuickGridView::propertyChanges() QTRY_COMPARE(gridView->isWrapEnabled(), true); QTRY_COMPARE(gridView->cacheBuffer(), 10); - QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight); + QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowLeftToRight); gridView->setWrapEnabled(false); gridView->setCacheBuffer(3); - gridView->setFlow(QQuickGridView::TopToBottom); + gridView->setFlow(QQuickGridView::FlowTopToBottom); QTRY_COMPARE(gridView->isWrapEnabled(), false); QTRY_COMPARE(gridView->cacheBuffer(), 3); - QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom); + QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowTopToBottom); QTRY_COMPARE(keyNavigationWrapsSpy.count(),1); QTRY_COMPARE(cacheBufferSpy.count(),1); @@ -2043,14 +2275,14 @@ void tst_QQuickGridView::propertyChanges() gridView->setWrapEnabled(false); gridView->setCacheBuffer(3); - gridView->setFlow(QQuickGridView::TopToBottom); + gridView->setFlow(QQuickGridView::FlowTopToBottom); QTRY_COMPARE(keyNavigationWrapsSpy.count(),1); QTRY_COMPARE(cacheBufferSpy.count(),1); QTRY_COMPARE(flowSpy.count(),1); - gridView->setFlow(QQuickGridView::LeftToRight); - QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight); + gridView->setFlow(QQuickGridView::FlowLeftToRight); + QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowLeftToRight); gridView->setWrapEnabled(true); gridView->setCacheBuffer(5); @@ -2074,11 +2306,11 @@ void tst_QQuickGridView::propertyChanges() QTRY_COMPARE(layoutSpy.count(),1); QTRY_COMPARE(flowSpy.count(),2); - gridView->setFlow(QQuickGridView::TopToBottom); - QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom); + gridView->setFlow(QQuickGridView::FlowTopToBottom); + QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowTopToBottom); QTRY_COMPARE(flowSpy.count(),3); - gridView->setFlow(QQuickGridView::TopToBottom); + gridView->setFlow(QQuickGridView::FlowTopToBottom); QTRY_COMPARE(flowSpy.count(),3); delete canvas; @@ -2179,8 +2411,9 @@ void tst_QQuickGridView::positionViewAtIndex() ctxt->setContextProperty("testModel", &model); ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); + ctxt->setContextProperty("testBottomToTop", QVariant(false)); - canvas->setSource(testFileUrl("gridview1.qml")); + canvas->setSource(testFileUrl("layouts.qml")); canvas->show(); qApp->processEvents(); @@ -2377,11 +2610,7 @@ void tst_QQuickGridView::snapping() for (int i = 0; i < 40; i++) model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); qApp->processEvents(); @@ -2483,8 +2712,9 @@ void tst_QQuickGridView::positionViewAtIndex_rightToLeft() ctxt->setContextProperty("testModel", &model); ctxt->setContextProperty("testTopToBottom", QVariant(true)); ctxt->setContextProperty("testRightToLeft", QVariant(true)); + ctxt->setContextProperty("testBottomToTop", QVariant(false)); - canvas->setSource(testFileUrl("gridview1.qml")); + canvas->setSource(testFileUrl("layouts.qml")); qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); @@ -2812,8 +3042,8 @@ void tst_QQuickGridView::manualHighlight() QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y()); QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x()); - gridview->setFlow(QQuickGridView::TopToBottom); - QTRY_COMPARE(gridview->flow(), QQuickGridView::TopToBottom); + gridview->setFlow(QQuickGridView::FlowTopToBottom); + QTRY_COMPARE(gridview->flow(), QQuickGridView::FlowTopToBottom); gridview->setCurrentIndex(0); QTRY_COMPARE(gridview->currentIndex(), 0); @@ -2829,10 +3059,10 @@ void tst_QQuickGridView::footer() { QFETCH(QQuickGridView::Flow, flow); QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); QFETCH(QPointF, initialFooterPos); QFETCH(QPointF, changedFooterPos); QFETCH(QPointF, initialContentPos); - QFETCH(QPointF, changedContentPos); QFETCH(QPointF, firstDelegatePos); QFETCH(QPointF, resizeContentPos); @@ -2845,7 +3075,6 @@ void tst_QQuickGridView::footer() QQmlContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); - canvas->setSource(testFileUrl("footer.qml")); qApp->processEvents(); @@ -2853,13 +3082,14 @@ void tst_QQuickGridView::footer() QTRY_VERIFY(gridview != 0); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); + gridview->setVerticalLayoutDirection(verticalLayoutDirection); + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); QQuickItem *contentItem = gridview->contentItem(); QTRY_VERIFY(contentItem != 0); QQuickText *footer = findItem<QQuickText>(contentItem, "footer"); QVERIFY(footer); - QVERIFY(footer == gridview->footerItem()); QCOMPARE(footer->pos(), initialFooterPos); @@ -2867,7 +3097,7 @@ void tst_QQuickGridView::footer() QCOMPARE(footer->height(), 30.); QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos); - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + footer->height()); else QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + footer->width()); @@ -2876,10 +3106,13 @@ void tst_QQuickGridView::footer() QVERIFY(item); QCOMPARE(item->pos(), firstDelegatePos); - if (flow == QQuickGridView::LeftToRight) { + if (flow == QQuickGridView::FlowLeftToRight) { // shrink by one row model.removeItem(2); - QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight()); + if (verticalLayoutDirection == QQuickItemView::TopToBottom) + QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight()); + else + QTRY_COMPARE(footer->y(), initialFooterPos.y() + gridview->cellHeight()); } else { // shrink by one column model.removeItem(2); @@ -2895,10 +3128,12 @@ void tst_QQuickGridView::footer() QPointF posWhenNoItems(0, 0); if (layoutDirection == Qt::RightToLeft) - posWhenNoItems.setX(flow == QQuickGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width()); + posWhenNoItems.setX(flow == QQuickGridView::FlowLeftToRight ? gridview->width() - footer->width() : -footer->width()); + if (verticalLayoutDirection == QQuickItemView::BottomToTop) + posWhenNoItems.setY(-footer->height()); QTRY_COMPARE(footer->pos(), posWhenNoItems); - // if header is present, it's at a negative pos, so the footer should not move + // if header is toggled, it shouldn't affect the footer position canvas->rootObject()->setProperty("showHeader", true); QVERIFY(findItem<QQuickItem>(contentItem, "header") != 0); QTRY_COMPARE(footer->pos(), posWhenNoItems); @@ -2917,13 +3152,14 @@ void tst_QQuickGridView::footer() QVERIFY(!footer); footer = findItem<QQuickText>(contentItem, "footer2"); QVERIFY(footer); - QVERIFY(footer == gridview->footerItem()); QCOMPARE(footer->pos(), changedFooterPos); QCOMPARE(footer->width(), 50.); QCOMPARE(footer->height(), 20.); - QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos); + + // changing the footer shouldn't change the content pos + QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos); item = findItem<QQuickItem>(contentItem, "wrapper", 0); QVERIFY(item); @@ -2941,10 +3177,10 @@ void tst_QQuickGridView::footer_data() { QTest::addColumn<QQuickGridView::Flow>("flow"); QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); QTest::addColumn<QPointF>("initialFooterPos"); QTest::addColumn<QPointF>("changedFooterPos"); QTest::addColumn<QPointF>("initialContentPos"); - QTest::addColumn<QPointF>("changedContentPos"); QTest::addColumn<QPointF>("firstDelegatePos"); QTest::addColumn<QPointF>("resizeContentPos"); @@ -2955,46 +3191,84 @@ void tst_QQuickGridView::footer_data() // view height = 320 // footer below items, bottom left - QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight + QTest::newRow("LeftToRight, LtR, TtB") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60) << QPointF(0, 10 * 60) // 30 items = 10 rows << QPointF(0, 0) << QPointF(0, 0) - << QPointF(0, 0) - << QPointF(0, 10 * 60 - 320 + 10); + << QPointF(0, (10 * 60) - 320 + 10); // footer below items, bottom right - QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft + QTest::newRow("LeftToRight, RtL, TtB") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom << QPointF(240 - 100, 3 * 60) << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers << QPointF(0, 0) - << QPointF(0, 0) << QPointF(240 - 80, 0) - << QPointF(0, 10 * 60 - 320 + 10); - - // footer to right of items - QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight + << QPointF(0, (10 * 60) - 320 + 10); + + // footer above items, top left + QTest::newRow("LeftToRight, LtR, BtT") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, -(3 * 60) - 30) + << QPointF(0, -(10 * 60) - 20) + << QPointF(0, -320) + << QPointF(0, -60) + << QPointF(0, -(10 * 60) - 10); + + // footer above items, top right + QTest::newRow("LeftToRight, RtL, BtT") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop + << QPointF(240 - 100, -(3 * 60) - 30) + << QPointF((240 - 100) + 50, -(10 * 60) - 20) + << QPointF(0, -320) + << QPointF(240 - 80, -60) + << QPointF(0, -(10 * 60) - 10); + + + // footer to right of items, bottom right + QTest::newRow("TopToBottom, LtR, TtB") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom << QPointF(2 * 80, 0) // 2 columns, cell width 80 << QPointF(6 * 80, 0) // 30 items = 6 columns << QPointF(0, 0) << QPointF(0, 0) - << QPointF(0, 0) - << QPointF(6 * 80 - 240 + 40, 0); + << QPointF((6 * 80) - 240 + 40, 0); - // footer to left of items - QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft + // footer to left of items, bottom right + QTest::newRow("TopToBottom, RtL, TtB") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom << QPointF(-(2 * 80) - 100, 0) << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width << QPointF(-240, 0) - << QPointF(-240, 0) // unchanged, footer change doesn't change content pos << QPointF(-80, 0) << QPointF(-(6 * 80) - 40, 0); + + // footer to right of items, top right + QTest::newRow("TopToBottom, LtR, BtT") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(2 * 80, -30) + << QPointF(6 * 80, -20) + << QPointF(0, -320) + << QPointF(0, -60) + << QPointF((6 * 80) - 240 + 40, -320); + + // footer to left of items, top left + QTest::newRow("TopToBottom, RtL, BtT") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop + << QPointF(-(2 * 80) - 100, -30) + << QPointF(-(6 * 80) - 50, -20) + << QPointF(-240, -320) + << QPointF(-80, -60) + << QPointF(-(6 * 80) - 40, -320); } void tst_QQuickGridView::header() { QFETCH(QQuickGridView::Flow, flow); QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); QFETCH(QPointF, initialHeaderPos); QFETCH(QPointF, changedHeaderPos); QFETCH(QPointF, initialContentPos); @@ -3018,6 +3292,7 @@ void tst_QQuickGridView::header() QTRY_VERIFY(gridview != 0); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); + gridview->setVerticalLayoutDirection(verticalLayoutDirection); QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); QQuickItem *contentItem = gridview->contentItem(); @@ -3025,7 +3300,6 @@ void tst_QQuickGridView::header() QQuickText *header = findItem<QQuickText>(contentItem, "header"); QVERIFY(header); - QVERIFY(header == gridview->headerItem()); QCOMPARE(header->pos(), initialHeaderPos); @@ -3033,7 +3307,7 @@ void tst_QQuickGridView::header() QCOMPARE(header->height(), 30.); QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos); - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + header->height()); else QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + header->width()); @@ -3091,6 +3365,7 @@ void tst_QQuickGridView::header() QTRY_VERIFY(gridview != 0); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); + gridview->setVerticalLayoutDirection(verticalLayoutDirection); QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); gridview->setWidth(240); @@ -3105,6 +3380,7 @@ void tst_QQuickGridView::header_data() { QTest::addColumn<QQuickGridView::Flow>("flow"); QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); QTest::addColumn<QPointF>("initialHeaderPos"); QTest::addColumn<QPointF>("changedHeaderPos"); QTest::addColumn<QPointF>("initialContentPos"); @@ -3118,7 +3394,8 @@ void tst_QQuickGridView::header_data() // view width = 240 // header above items, top left - QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight + QTest::newRow("LeftToRight, LtR, TtB") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom << QPointF(0, -30) << QPointF(0, -20) << QPointF(0, -30) @@ -3127,7 +3404,8 @@ void tst_QQuickGridView::header_data() << QPointF(0, -10); // header above items, top right - QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft + QTest::newRow("LeftToRight, RtL, TtB") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom << QPointF(240 - 100, -30) << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers << QPointF(0, -30) @@ -3135,8 +3413,30 @@ void tst_QQuickGridView::header_data() << QPointF(160, 0) << QPointF(0, -10); - // header to left of items - QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight + // header below items, bottom left + QTest::newRow("LeftToRight, LtR, BtT") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, 0) + << QPointF(0, 0) + << QPointF(0, -320 + 30) + << QPointF(0, -320 + 20) + << QPointF(0, -60) + << QPointF(0, -320 + 10); + + // header above items, top right + QTest::newRow("LeftToRight, RtL, BtT") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop + << QPointF(240 - 100, 0) + << QPointF((240 - 100) + 50, 0) + << QPointF(0, -320 + 30) + << QPointF(0, -320 + 20) + << QPointF(160, -60) + << QPointF(0, -320 + 10); + + + // header to left of items, bottom left + QTest::newRow("TopToBottom, LtR, TtB") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom << QPointF(-100, 0) << QPointF(-50, 0) << QPointF(-100, 0) @@ -3144,14 +3444,35 @@ void tst_QQuickGridView::header_data() << QPointF(0, 0) << QPointF(-40, 0); - // header to right of items - QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft + // header to right of items, bottom right + QTest::newRow("TopToBottom, RtL, TtB") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom << QPointF(0, 0) << QPointF(0, 0) << QPointF(-(240 - 100), 0) << QPointF(-(240 - 50), 0) << QPointF(-80, 0) << QPointF(-(240 - 40), 0); + + // header to left of items, top left + QTest::newRow("TopToBottom, LtR, BtT") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(-100, -30) + << QPointF(-50, -20) + << QPointF(-100, -320) + << QPointF(-50, -320) + << QPointF(0, -60) + << QPointF(-40, -320); + + // header to right of items, top right + QTest::newRow("TopToBottom, RtL, BtT") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop + << QPointF(0, -30) + << QPointF(0, -20) + << QPointF(-(240 - 100), -320) + << QPointF(-(240 - 50), -320) + << QPointF(-80, -60) + << QPointF(-(240 - 40), -320); } class GVAccessor : public QQuickGridView @@ -3165,138 +3486,144 @@ public: void tst_QQuickGridView::headerFooter() { - { - // Vertical - QQuickView *canvas = createView(); - - QmlListModel model; - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - - canvas->setSource(testFileUrl("headerfooter.qml")); - qApp->processEvents(); - - QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject()); - QTRY_VERIFY(gridview != 0); - - QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - - QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->y(), -header->height()); - - QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->y(), 0.); - - QCOMPARE(static_cast<GVAccessor*>(gridview)->minY(), header->height()); - QCOMPARE(static_cast<GVAccessor*>(gridview)->maxY(), header->height()); - - delete canvas; - } - { - // Horizontal - QQuickView *canvas = createView(); - - QmlListModel model; - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - - canvas->setSource(testFileUrl("headerfooter.qml")); - canvas->rootObject()->setProperty("horizontal", true); - qApp->processEvents(); - - QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject()); - QTRY_VERIFY(gridview != 0); - - QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - - QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->x(), -header->width()); + QFETCH(QQuickGridView::Flow, flow); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); + QFETCH(QPointF, headerPos); + QFETCH(QPointF, footerPos); + QFETCH(QPointF, minPos); + QFETCH(QPointF, maxPos); - QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->x(), 0.); + QQuickView *canvas = getView(); - QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), header->width()); - QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), header->width()); + QmlListModel model; + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + canvas->setSource(testFileUrl("headerfooter.qml")); + canvas->show(); + qApp->processEvents(); - delete canvas; - } - { - // Horizontal RTL - QQuickView *canvas = createView(); + QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject()); + QTRY_VERIFY(gridview != 0); + gridview->setFlow(flow); + gridview->setLayoutDirection(layoutDirection); + gridview->setVerticalLayoutDirection(verticalLayoutDirection); + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); - QmlListModel model; - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); + QQuickItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); - canvas->setSource(testFileUrl("headerfooter.qml")); - canvas->rootObject()->setProperty("horizontal", true); - canvas->rootObject()->setProperty("rtl", true); - qApp->processEvents(); + QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->pos(), headerPos); - QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject()); - QTRY_VERIFY(gridview != 0); + QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->pos(), footerPos); - QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), minPos.x()); + QCOMPARE(static_cast<GVAccessor*>(gridview)->minY(), minPos.y()); + QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), maxPos.x()); + QCOMPARE(static_cast<GVAccessor*>(gridview)->maxY(), maxPos.y()); - QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->x(), 0.); + releaseView(canvas); +} - QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->x(), -footer->width()); +void tst_QQuickGridView::headerFooter_data() +{ + QTest::addColumn<QQuickGridView::Flow>("flow"); + QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); + QTest::addColumn<QPointF>("headerPos"); + QTest::addColumn<QPointF>("footerPos"); + QTest::addColumn<QPointF>("minPos"); + QTest::addColumn<QPointF>("maxPos"); + + // header is 240x20 (or 20x320 in TopToBottom) + // footer is 240x30 (or 30x320 in TopToBottom) + + QTest::newRow("LeftToRight, LtR, TtB") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom + << QPointF(0, -20) << QPointF(0, 0) + << QPointF(0, 20) << QPointF(240, 20); + + QTest::newRow("LeftToRight, RtL, TtB") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom + << QPointF(0, -20) << QPointF(0, 0) + << QPointF(0, 20) << QPointF(240, 20); + + QTest::newRow("LeftToRight, LtR, BtT") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, 0) << QPointF(0, -30) + << QPointF(0, 320 - 20) << QPointF(240, 320 - 20); // content flow is reversed + + QTest::newRow("LeftToRight, RtL, BtT") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop + << QPointF(0, 0) << QPointF(0, -30) + << QPointF(0, 320 - 20) << QPointF(240, 320 - 20); // content flow is reversed + + + QTest::newRow("TopToBottom, LtR, TtB") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom + << QPointF(-20, 0) << QPointF(0, 0) + << QPointF(20, 0) << QPointF(20, 320); + + QTest::newRow("TopToBottom, RtL, TtB") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom + << QPointF(0, 0) << QPointF(-30, 0) + << QPointF(240 - 20, 0) << QPointF(240 - 20, 320); // content flow is reversed + + QTest::newRow("TopToBottom, LtR, BtT") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(-20, -320) << QPointF(0, -320) + << QPointF(20, 0) << QPointF(20, 320); + + QTest::newRow("TopToBottom, RtL, BtT") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop + << QPointF(0, -320) << QPointF(-30, -320) + << QPointF(240 - 20, 0) << QPointF(240 - 20, 320); // content flow is reversed +} - QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), 240. - header->width()); - QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), 240. - header->width()); +void tst_QQuickGridView::resetModel_headerFooter() +{ + // Resetting a model shouldn't crash in views with header/footer - delete canvas; - } - { - // Reset model - QQuickView *canvas = createView(); + QQuickView *canvas = createView(); - QaimModel model; - for (int i = 0; i < 6; i++) - model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); + QaimModel model; + for (int i = 0; i < 6; i++) + model.addItem("Item" + QString::number(i), ""); + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); - canvas->setSource(testFileUrl("headerfooter.qml")); - qApp->processEvents(); + canvas->setSource(testFileUrl("headerfooter.qml")); + qApp->processEvents(); - QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject()); - QTRY_VERIFY(gridview != 0); + QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject()); + QTRY_VERIFY(gridview != 0); - QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QQuickItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); - QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->y(), -header->height()); + QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->y(), -header->height()); - QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->y(), 80.*2); + QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->y(), 80.*2); - model.reset(); + model.reset(); - header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->y(), -header->height()); + header = findItem<QQuickItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->y(), -header->height()); - footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->y(), 80.*2); + footer = findItem<QQuickItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->y(), 80.*2); - delete canvas; - } + delete canvas; } void tst_QQuickGridView::resizeViewAndRepaint() @@ -3370,6 +3697,147 @@ void tst_QQuickGridView::resizeViewAndRepaint() delete canvas; } +void tst_QQuickGridView::resizeGrid() +{ + QFETCH(QQuickGridView::Flow, flow); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); + QFETCH(QPointF, initialContentPos); + QFETCH(QPointF, firstItemPos); + + QaimModel model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QQuickView *canvas = getView(); + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testTopToBottom", flow == QQuickGridView::FlowTopToBottom); + ctxt->setContextProperty("testRightToLeft", layoutDirection == Qt::RightToLeft); + ctxt->setContextProperty("testBottomToTop", verticalLayoutDirection == QQuickGridView::BottomToTop); + canvas->setSource(testFileUrl("resizegrid.qml")); + canvas->show(); + qApp->processEvents(); + + QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + QQuickItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + // set the width to slightly larger than 3 items across, to test + // items are aligned correctly in right-to-left + canvas->rootObject()->setWidth(260); + canvas->rootObject()->setHeight(320); + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + + QCOMPARE(gridview->contentX(), initialContentPos.x()); + QCOMPARE(gridview->contentY(), initialContentPos.y()); + + QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0); + QVERIFY(item0); + QCOMPARE(item0->pos(), firstItemPos); + + // Confirm items positioned correctly and indexes correct + QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); + QVERIFY(items.count() >= 18 && items.count() <= 21); + for (int i = 0; i < model.count() && i < items.count(); ++i) { + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); + QCOMPARE(item->pos(), expectedItemPos(gridview, i, 0)); + QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(i)); + } + + // change from 3x5 grid to 4x7 + canvas->rootObject()->setWidth(canvas->rootObject()->width() + 80); + canvas->rootObject()->setHeight(canvas->rootObject()->height() + 60*2); + QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + + // other than in LeftToRight+RightToLeft layout, the first item should not move + // if view is resized + QCOMPARE(findItem<QQuickItem>(contentItem, "wrapper", 0), item0); + if (flow == QQuickGridView::FlowLeftToRight && layoutDirection == Qt::RightToLeft) + firstItemPos.rx() += 80; + QCOMPARE(item0->pos(), firstItemPos); + + QPointF newContentPos = initialContentPos; + if (flow == QQuickGridView::FlowTopToBottom && layoutDirection == Qt::RightToLeft) + newContentPos.rx() -= 80.0; + if (verticalLayoutDirection == QQuickItemView::BottomToTop) + newContentPos.ry() -= 60.0 * 2; + QCOMPARE(gridview->contentX(), newContentPos.x()); + QCOMPARE(gridview->contentY(), newContentPos.y()); + + // Confirm items positioned correctly and indexes correct + items = findItems<QQuickItem>(contentItem, "wrapper"); + QVERIFY(items.count() >= 28); + for (int i = 0; i < model.count() && i < items.count(); ++i) { + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); + QCOMPARE(item->pos(), expectedItemPos(gridview, i, 0)); + QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(i)); + } + + releaseView(canvas); +} + +void tst_QQuickGridView::resizeGrid_data() +{ + QTest::addColumn<QQuickGridView::Flow>("flow"); + QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); + QTest::addColumn<QPointF>("initialContentPos"); + QTest::addColumn<QPointF>("firstItemPos"); + + // Initial view width is 260, so in LeftToRight + right-to-left mode the + // content x should be -20 + + QTest::newRow("LeftToRight, LtR, TtB") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom + << QPointF(0, 0) + << QPointF(0, 0); + + QTest::newRow("LeftToRight, RtL, TtB") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom + << QPointF(-20.0, 0) + << QPointF(80.0 * 2, 0); + + QTest::newRow("LeftToRight, LtR, BtT") + << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, -320) + << QPointF(0, -60.0); + + QTest::newRow("LeftToRight, RtL, BtT") + << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop + << QPointF(-20.0, -320) + << QPointF(80.0 * 2, -60.0); + + + QTest::newRow("TopToBottom, LtR, TtB") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom + << QPointF(0, 0) + << QPointF(0, 0); + + QTest::newRow("TopToBottom, RtL, TtB") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom + << QPointF(-260, 0) + << QPointF(-80.0, 0); + + QTest::newRow("TopToBottom, LtR, BtT") + << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, -320) + << QPointF(0, -60.0); + + QTest::newRow("TopToBottom, RtL, BtT") + << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop + << QPointF(-260, -320) + << QPointF(-80.0, -60.0); +} + + void tst_QQuickGridView::changeColumnCount() { QmlListModel model; @@ -3458,11 +3926,7 @@ void tst_QQuickGridView::indexAt_itemAt() model.addItem("Ben", "04321"); model.addItem("Jim", "0780"); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); qApp->processEvents(); @@ -3776,22 +4240,22 @@ void tst_QQuickGridView::snapToRow_data() QTest::addColumn<qreal>("endExtent"); QTest::addColumn<qreal>("startExtent"); - QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + QTest::newRow("vertical, left to right") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 800.0 << 0.0; - QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + QTest::newRow("horizontal, left to right") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 800.0 << 0.0; - QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) + QTest::newRow("horizontal, right to left") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 << -240.0; - QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 940.0 << -20.0; - QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 940.0 << -20.0; - QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 - 140.0 << -220.0; } @@ -3826,7 +4290,7 @@ void tst_QQuickGridView::snapToRow() // confirm that a flick hits an item boundary flick(canvas, flickStart, flickEnd, 180); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment); else QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment); @@ -3835,11 +4299,11 @@ void tst_QQuickGridView::snapToRow() do { flick(canvas, flickStart, flickEnd, 180); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops - } while (flow == QQuickGridView::LeftToRight + } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYEnd() : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning()); - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentY(), endExtent); else QCOMPARE(gridview->contentX(), endExtent); @@ -3848,11 +4312,11 @@ void tst_QQuickGridView::snapToRow() do { flick(canvas, flickEnd, flickStart, 180); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops - } while (flow == QQuickGridView::LeftToRight + } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYBeginning() : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd()); - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentY(), startExtent); else QCOMPARE(gridview->contentX(), startExtent); @@ -3871,22 +4335,22 @@ void tst_QQuickGridView::snapOneRow_data() QTest::addColumn<qreal>("endExtent"); QTest::addColumn<qreal>("startExtent"); - QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + QTest::newRow("vertical, left to right") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 240.0 << 0.0; - QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + QTest::newRow("horizontal, left to right") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 240.0 << 0.0; - QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) + QTest::newRow("horizontal, right to left") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -240.0 - 240.0 << -240.0; - QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 340.0 << -20.0; - QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 340.0 << -20.0; - QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -240.0 - 240.0 - 100.0 << -220.0; } @@ -3923,7 +4387,7 @@ void tst_QQuickGridView::snapOneRow() // confirm that a flick hits next row boundary flick(canvas, flickStart, flickEnd, 180); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentY(), snapAlignment); else QCOMPARE(gridview->contentX(), snapAlignment); @@ -3937,7 +4401,7 @@ void tst_QQuickGridView::snapOneRow() do { flick(canvas, flickStart, flickEnd, 180); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops - } while (flow == QQuickGridView::LeftToRight + } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYEnd() : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning()); @@ -3946,7 +4410,7 @@ void tst_QQuickGridView::snapOneRow() QCOMPARE(currentIndexSpy.count(), 3); } - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentY(), endExtent); else QCOMPARE(gridview->contentX(), endExtent); @@ -3955,11 +4419,11 @@ void tst_QQuickGridView::snapOneRow() do { flick(canvas, flickEnd, flickStart, 180); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops - } while (flow == QQuickGridView::LeftToRight + } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYBeginning() : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd()); - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentY(), startExtent); else QCOMPARE(gridview->contentX(), startExtent); @@ -4171,7 +4635,7 @@ void tst_QQuickGridView::addTransitions() { QFETCH(int, initialItemCount); QFETCH(bool, shouldAnimateTargets); - QFETCH(qreal, contentY); + QFETCH(qreal, contentYRowOffset); QFETCH(int, insertionIndex); QFETCH(int, insertionCount); QFETCH(ListRange, expectedDisplacedIndexes); @@ -4204,8 +4668,8 @@ void tst_QQuickGridView::addTransitions() QVERIFY(contentItem != 0); QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); - if (contentY != 0) { - gridview->setContentY(contentY); + if (contentYRowOffset != 0) { + gridview->setContentY(contentYRowOffset * 60.0); QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); } @@ -4220,7 +4684,7 @@ void tst_QQuickGridView::addTransitions() newData << qMakePair(QString("New item %1").arg(i), QString("")); // last visible item is the first item of the row beneath the view - if (i >= (contentY / 60)*3 && i < qCeil((contentY + gridview->height()) / 60.0)*3) { + if (i >= (gridview->contentY() / 60)*3 && i < qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) { expectedTargetData << newData.last(); targetIndexes << i; } @@ -4264,7 +4728,7 @@ void tst_QQuickGridView::addTransitions() QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); int firstVisibleIndex = -1; for (int i=0; i<items.count(); i++) { - if (items[i]->y() >= contentY) { + if (items[i]->y() >= gridview->contentY()) { QQmlExpression e(qmlContext(items[i]), items[i], "index"); firstVisibleIndex = e.evaluate().toInt(); break; @@ -4273,8 +4737,7 @@ void tst_QQuickGridView::addTransitions() QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); // verify all items moved to the correct final positions - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); - for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QCOMPARE(item->x(), (i%3)*80.0); @@ -4290,7 +4753,7 @@ void tst_QQuickGridView::addTransitions() void tst_QQuickGridView::addTransitions_data() { QTest::addColumn<int>("initialItemCount"); - QTest::addColumn<qreal>("contentY"); + QTest::addColumn<qreal>("contentYRowOffset"); QTest::addColumn<bool>("shouldAnimateTargets"); QTest::addColumn<int>("insertionIndex"); QTest::addColumn<int>("insertionCount"); @@ -4298,19 +4761,19 @@ void tst_QQuickGridView::addTransitions_data() // if inserting a full row before visible index, items don't appear or animate in, even if there are > 1 new items QTest::newRow("insert 1, just before start") - << 30 << 20.0 << false + << 30 << 1.0 << false << 0 << 1 << ListRange(); QTest::newRow("insert 1, way before start") - << 30 << 20.0 << false + << 30 << 1.0 << false << 0 << 1 << ListRange(); QTest::newRow("insert multiple, just before start") - << 30 << 100.0 << false + << 30 << 1.0 << false << 0 << 3 << ListRange(); QTest::newRow("insert multiple (< 1 row), just before start") - << 30 << 100.0 << false + << 30 << 1.0 << false << 0 << 2 << ListRange(); QTest::newRow("insert multiple, way before start") - << 30 << 100.0 << false + << 30 << 3.0 << false << 0 << 3 << ListRange(); QTest::newRow("insert 1 at start") @@ -4323,13 +4786,13 @@ void tst_QQuickGridView::addTransitions_data() << 30 << 0.0 << true << 0 << 5 << ListRange(0, 17); QTest::newRow("insert 1 at start, content y not 0") - << 30 << 60.0 << true // first visible is index 3 + << 30 << 1.0 << true // first visible is index 3 << 3 << 1 << ListRange(0 + 3, 17 + 3); QTest::newRow("insert multiple at start, content y not 0") - << 30 << 60.0 << true // first visible is index 3 + << 30 << 1.0 << true // first visible is index 3 << 3 << 3 << ListRange(0 + 3, 17 + 3); QTest::newRow("insert multiple (> 1 row) at start, content y not 0") - << 30 << 60.0 << true // first visible is index 3 + << 30 << 1.0 << true // first visible is index 3 << 3 << 5 << ListRange(0 + 3, 17 + 3); QTest::newRow("insert 1 at start, to empty grid") @@ -4356,10 +4819,10 @@ void tst_QQuickGridView::addTransitions_data() << 30 << 0.0 << true << 17 << 3 << ListRange(17, 17); QTest::newRow("insert 1 at bottom, content y not 0") - << 30 << 20.0 * 3 << true + << 30 << 1.0 << true << 17 + 3 << 1 << ListRange(17 + 3, 17 + 3); QTest::newRow("insert multiple at bottom, content y not 0") - << 30 << 20.0 * 3 << true + << 30 << 1.0 << true << 17 + 3 << 3 << ListRange(17 + 3, 17 + 3); @@ -4376,8 +4839,8 @@ void tst_QQuickGridView::addTransitions_data() void tst_QQuickGridView::moveTransitions() { QFETCH(int, initialItemCount); - QFETCH(qreal, contentY); - QFETCH(qreal, itemsOffsetAfterMove); + QFETCH(qreal, contentYRowOffset); + QFETCH(qreal, rowOffsetAfterMove); QFETCH(int, moveFrom); QFETCH(int, moveTo); QFETCH(int, moveCount); @@ -4409,8 +4872,8 @@ void tst_QQuickGridView::moveTransitions() QVERIFY(contentItem != 0); QQuickText *name; - if (contentY != 0) { - gridview->setContentY(contentY); + if (contentYRowOffset != 0) { + gridview->setContentY(contentYRowOffset * 60.0); QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); } @@ -4422,8 +4885,8 @@ void tst_QQuickGridView::moveTransitions() QList<int> targetIndexes; for (int i=moveFrom; i<moveFrom+moveCount; i++) { int toIndex = moveTo + (i - moveFrom); - int firstVisibleIndex = (contentY / 60) * 3; - int lastVisibleIndex = (qCeil((contentY + gridview->height()) / 60.0)*3) - 1; + int firstVisibleIndex = (gridview->contentY() / 60) * 3; + int lastVisibleIndex = (qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) - 1; if ((i >= firstVisibleIndex && i <= lastVisibleIndex) || (toIndex >= firstVisibleIndex && toIndex <= lastVisibleIndex)) { expectedTargetData << qMakePair(model.name(i), model.number(i)); @@ -4461,7 +4924,7 @@ void tst_QQuickGridView::moveTransitions() QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); int firstVisibleIndex = -1; for (int i=0; i<items.count(); i++) { - if (items[i]->y() >= contentY) { + if (items[i]->y() >= gridview->contentY()) { QQmlExpression e(qmlContext(items[i]), items[i], "index"); firstVisibleIndex = e.evaluate().toInt(); break; @@ -4470,12 +4933,12 @@ void tst_QQuickGridView::moveTransitions() QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); // verify all items moved to the correct final positions - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); - for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + qreal pixelOffset = 60 * rowOffsetAfterMove; + for (int i=firstVisibleIndex; i < model.count() && i < items.count(); ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QCOMPARE(item->x(), (i%3)*80.0); - QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove); + QCOMPARE(item->y(), (i/3)*60.0 + pixelOffset); name = findItem<QQuickText>(contentItem, "textName", i); QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); @@ -4487,94 +4950,132 @@ void tst_QQuickGridView::moveTransitions() void tst_QQuickGridView::moveTransitions_data() { QTest::addColumn<int>("initialItemCount"); - QTest::addColumn<qreal>("contentY"); - QTest::addColumn<qreal>("itemsOffsetAfterMove"); + QTest::addColumn<qreal>("contentYRowOffset"); + QTest::addColumn<qreal>("rowOffsetAfterMove"); QTest::addColumn<int>("moveFrom"); QTest::addColumn<int>("moveTo"); QTest::addColumn<int>("moveCount"); QTest::addColumn<ListRange>("expectedDisplacedIndexes"); - QTest::newRow("move from above view, outside visible items, move 1") << 30 << 120.0 << 0.0 + QTest::newRow("move from above view, outside visible items, move 1") + << 30 << 2.0 << 0.0 << 1 << 10 << 1 << ListRange(6, 10); - QTest::newRow("move from above view, outside visible items, move 1 (first item)") << 30 << 120.0 << 0.0 + QTest::newRow("move from above view, outside visible items, move 1 (first item)") + << 30 << 2.0 << 0.0 << 0 << 10 << 1 << ListRange(6, 10); - QTest::newRow("move from above view, outside visible items, move multiple") << 30 << 120.0 << 60.0 + QTest::newRow("move from above view, outside visible items, move multiple") + << 30 << 2.0 << 1.0 << 1 << 10 << 3 << ListRange(13, 23); - QTest::newRow("move from above view, mix of visible/non-visible") << 30 << 120.0 << 60.0 + QTest::newRow("move from above view, mix of visible/non-visible") + << 30 << 2.0 << 1.0 << 1 << 10 << 6 << (ListRange(7, 15) + ListRange(16, 23)); - QTest::newRow("move from above view, mix of visible/non-visible (move first)") << 30 << 120.0 << 120.0 + QTest::newRow("move from above view, mix of visible/non-visible (move first)") + << 30 << 2.0 << 2.0 << 0 << 10 << 6 << ListRange(16, 23); - QTest::newRow("move within view, move 1 down") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move 1 down") + << 30 << 0.0 << 0.0 << 1 << 10 << 1 << ListRange(2, 10); - QTest::newRow("move within view, move 1 down, move first item") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move 1 down, move first item") + << 30 << 0.0 << 0.0 << 0 << 10 << 1 << ListRange(1, 10); - QTest::newRow("move within view, move 1 down, move first item, contentY not 0") << 30 << 120.0 << 0.0 + QTest::newRow("move within view, move 1 down, move first item, contentY not 0") + << 30 << 2.0 << 0.0 << 0+6 << 10+6 << 1 << ListRange(1+6, 10+6); - QTest::newRow("move within view, move 1 down, to last item") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move 1 down, to last item") + << 30 << 0.0 << 0.0 << 10 << 17 << 1 << ListRange(11, 17); - QTest::newRow("move within view, move first->last") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move first->last") + << 30 << 0.0 << 0.0 << 0 << 17 << 1 << ListRange(1, 17); - QTest::newRow("move within view, move multiple down") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple down") + << 30 << 0.0 << 0.0 << 1 << 10 << 3 << ListRange(4, 12); - QTest::newRow("move within view, move multiple down, move first item") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple down, move first item") + << 30 << 0.0 << 0.0 << 0 << 10 << 3 << ListRange(3, 12); - QTest::newRow("move within view, move multiple down, move first item, contentY not 0") << 30 << 60.0 << 0.0 + QTest::newRow("move within view, move multiple down, move first item, contentY not 0") + << 30 << 1.0 << 0.0 << 0+3 << 10+3 << 3 << ListRange(3+3, 12+3); - QTest::newRow("move within view, move multiple down, displace last item") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple down, displace last item") + << 30 << 0.0 << 0.0 << 5 << 15 << 3 << ListRange(8, 17); - QTest::newRow("move within view, move multiple down, move first->last") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple down, move first->last") + << 30 << 0.0 << 0.0 << 0 << 15 << 3 << ListRange(3, 17); - QTest::newRow("move within view, move 1 up") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move 1 up") + << 30 << 0.0 << 0.0 << 10 << 1 << 1 << ListRange(1, 9); - QTest::newRow("move within view, move 1 up, move to first index") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move 1 up, move to first index") + << 30 << 0.0 << 0.0 << 10 << 0 << 1 << ListRange(0, 9); - QTest::newRow("move within view, move 1 up, move to first index, contentY not 0") << 30 << 120.0 << 0.0 + QTest::newRow("move within view, move 1 up, move to first index, contentY not 0") + << 30 << 2.0 << 0.0 << 10+6 << 0+6 << 1 << ListRange(0+6, 9+6); - QTest::newRow("move within view, move 1 up, move to first index, contentY not on item border") << 30 << 80.0 << 0.0 + QTest::newRow("move within view, move 1 up, move to first index, contentY not on item border") + << 30 << 1.5 << 0.0 << 10+3 << 0+3 << 1 << ListRange(0+3, 9+3); - QTest::newRow("move within view, move 1 up, move last item") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move 1 up, move last item") + << 30 << 0.0 << 0.0 << 17 << 10 << 1 << ListRange(10, 16); - QTest::newRow("move within view, move 1 up, move last->first") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move 1 up, move last->first") + << 30 << 0.0 << 0.0 << 17 << 0 << 1 << ListRange(0, 16); - QTest::newRow("move within view, move multiple up") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple up") + << 30 << 0.0 << 0.0 << 10 << 1 << 3 << ListRange(1, 9); - QTest::newRow("move within view, move multiple (> 1 row) up") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple (> 1 row) up") + << 30 << 0.0 << 0.0 << 10 << 1 << 5 << ListRange(1, 9); - QTest::newRow("move within view, move multiple up, move to first index") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple up, move to first index") + << 30 << 0.0 << 0.0 << 10 << 0 << 3 << ListRange(0, 9); - QTest::newRow("move within view, move multiple up, move to first index, contentY not 0") << 30 << 60.0 << 0.0 + QTest::newRow("move within view, move multiple up, move to first index, contentY not 0") + << 30 << 1.0 << 0.0 << 10+3 << 0+3 << 3 << ListRange(0+3, 9+3); - QTest::newRow("move within view, move multiple up (> 1 row), move to first index, contentY not on border") << 30 << 80.0 << 0.0 + QTest::newRow("move within view, move multiple up (> 1 row), move to first index, contentY not on border") + << 30 << 1.5 << 0.0 << 10+3 << 0+3 << 5 << ListRange(0+3, 9+3); - QTest::newRow("move within view, move multiple up, move last item") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple up, move last item") + << 30 << 0.0 << 0.0 << 15 << 5 << 3 << ListRange(5, 14); - QTest::newRow("move within view, move multiple up, move last->first") << 30 << 0.0 << 0.0 + QTest::newRow("move within view, move multiple up, move last->first") + << 30 << 0.0 << 0.0 << 15 << 0 << 3 << ListRange(0, 14); - QTest::newRow("move from below view, move 1 up") << 30 << 0.0 << 0.0 + QTest::newRow("move from below view, move 1 up") + << 30 << 0.0 << 0.0 << 20 << 5 << 1 << ListRange(5, 17); - QTest::newRow("move from below view, move 1 up, move to top") << 30 << 0.0 << 0.0 + QTest::newRow("move from below view, move 1 up, move to top") + << 30 << 0.0 << 0.0 << 20 << 0 << 1 << ListRange(0, 17); - QTest::newRow("move from below view, move 1 up, move to top, contentY not 0") << 30 << 60.0 << 0.0 + QTest::newRow("move from below view, move 1 up, move to top, contentY not 0") + << 30 << 1.0 << 0.0 << 25 << 3 << 1 << ListRange(0+3, 17+3); - QTest::newRow("move from below view, move multiple (> 1 row) up") << 30 << 0.0 << 0.0 + QTest::newRow("move from below view, move multiple (> 1 row) up") + << 30 << 0.0 << 0.0 << 20 << 5 << 5 << ListRange(5, 17); - QTest::newRow("move from below view, move multiple up, move to top") << 30 << 0.0 << 0.0 + QTest::newRow("move from below view, move multiple up, move to top") + << 30 << 0.0 << 0.0 << 20 << 0 << 3 << ListRange(0, 17); - QTest::newRow("move from below view, move multiple up, move to top, contentY not 0") << 30 << 60.0 << 0.0 + QTest::newRow("move from below view, move multiple up, move to top, contentY not 0") + << 30 << 1.0 << 0.0 << 25 << 3 << 3 << ListRange(0+3, 17+3); - QTest::newRow("move from below view, move 1 up, move to bottom") << 30 << 0.0 << 0.0 + QTest::newRow("move from below view, move 1 up, move to bottom") + << 30 << 0.0 << 0.0 << 20 << 17 << 1 << ListRange(17, 17); - QTest::newRow("move from below view, move 1 up, move to bottom, contentY not 0") << 30 << 60.0 << 0.0 + QTest::newRow("move from below view, move 1 up, move to bottom, contentY not 0") + << 30 << 1.0 << 0.0 << 25 << 17+3 << 1 << ListRange(17+3, 17+3); - QTest::newRow("move from below view, move multiple up, move to to bottom") << 30 << 0.0 << 0.0 + QTest::newRow("move from below view, move multiple up, move to to bottom") + << 30 << 0.0 << 0.0 << 20 << 17 << 3 << ListRange(17, 17); - QTest::newRow("move from below view, move multiple up, move to bottom, contentY not 0") << 30 << 60.0 << 0.0 + QTest::newRow("move from below view, move multiple up, move to bottom, contentY not 0") + << 30 << 1.0 << 0.0 << 25 << 17+3 << 3 << ListRange(17+3, 17+3); } @@ -4582,7 +5083,7 @@ void tst_QQuickGridView::removeTransitions() { QFETCH(int, initialItemCount); QFETCH(bool, shouldAnimateTargets); - QFETCH(qreal, contentY); + QFETCH(qreal, contentYRowOffset); QFETCH(int, removalIndex); QFETCH(int, removalCount); QFETCH(ListRange, expectedDisplacedIndexes); @@ -4615,8 +5116,8 @@ void tst_QQuickGridView::removeTransitions() QVERIFY(contentItem != 0); QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); - if (contentY != 0) { - gridview->setContentY(contentY); + if (contentYRowOffset != 0) { + gridview->setContentY(contentYRowOffset * 60.0); QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); } @@ -4627,8 +5128,8 @@ void tst_QQuickGridView::removeTransitions() QList<int> targetIndexes; if (shouldAnimateTargets) { for (int i=removalIndex; i<removalIndex+removalCount; i++) { - int firstVisibleIndex = (contentY / 60.0)*3; - int lastVisibleIndex = (qCeil((contentY + gridview->height()) / 60.0)*3) - 1; + int firstVisibleIndex = (gridview->contentY() / 60.0)*3; + int lastVisibleIndex = (qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) - 1; if (i >= firstVisibleIndex && i <= lastVisibleIndex) { expectedTargetData << qMakePair(model.name(i), model.number(i)); targetIndexes << i; @@ -4678,7 +5179,7 @@ void tst_QQuickGridView::removeTransitions() for (int i=0; i<items.count(); i++) { QQmlExpression e(qmlContext(items[i]), items[i], "index"); int index = e.evaluate().toInt(); - if (firstVisibleIndex < 0 && items[i]->y() >= contentY) + if (firstVisibleIndex < 0 && items[i]->y() >= gridview->contentY()) firstVisibleIndex = index; else if (index < 0) itemCount--; // exclude deleted items @@ -4690,7 +5191,7 @@ void tst_QQuickGridView::removeTransitions() QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QCOMPARE(item->x(), (i%3)*80.0); - QCOMPARE(item->y(), contentY + ((i-firstVisibleIndex)/3) * 60.0); + QCOMPARE(item->y(), gridview->contentY() + ((i-firstVisibleIndex)/3) * 60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); @@ -4702,7 +5203,7 @@ void tst_QQuickGridView::removeTransitions() void tst_QQuickGridView::removeTransitions_data() { QTest::addColumn<int>("initialItemCount"); - QTest::addColumn<qreal>("contentY"); + QTest::addColumn<qreal>("contentYRowOffset"); QTest::addColumn<bool>("shouldAnimateTargets"); QTest::addColumn<int>("removalIndex"); QTest::addColumn<int>("removalCount"); @@ -4714,19 +5215,19 @@ void tst_QQuickGridView::removeTransitions_data() // For a GridView, removing any number of items other than a full row before the start // should displace all items in the view QTest::newRow("remove 1 before start") - << 30 << 120.0 << false + << 30 << 2.0 << false << 2 << 1 << ListRange(6, 24); // 6-24 are displaced QTest::newRow("remove 1 row, before start") - << 30 << 120.0 << false + << 30 << 2.0 << false << 3 << 3 << ListRange(); QTest::newRow("remove between 1-2 rows, before start") - << 30 << 120.0 << false + << 30 << 2.0 << false << 0 << 5 << ListRange(6, 25); QTest::newRow("remove 2 rows, before start") - << 30 << 120.0 << false + << 30 << 2.0 << false << 0 << 6 << ListRange(); QTest::newRow("remove mix of before and after start") - << 30 << 60.0 << true + << 30 << 1.0 << true << 2 << 3 << ListRange(5, 23); // 5-23 are displaced into view @@ -4737,10 +5238,10 @@ void tst_QQuickGridView::removeTransitions_data() << 30 << 0.0 << true << 0 << 3 << ListRange(3, 20); // 3-18 are displaced into view QTest::newRow("remove 1 from start, content y not 0") - << 30 << 60.0 << true + << 30 << 1.0 << true << 3 << 1 << ListRange(1 + 3, 18 + 3); QTest::newRow("remove multiple from start, content y not 0") - << 30 << 60.0 << true + << 30 << 1.0 << true << 3 << 3 << ListRange(3 + 3, 20 + 3); @@ -4762,10 +5263,10 @@ void tst_QQuickGridView::removeTransitions_data() << 30 << 0.0 << true << 15 << 5 << ListRange(20, 22); QTest::newRow("remove 1 from bottom, content y not 0") - << 30 << 60.0 << true + << 30 << 1.0 << true << 17 + 3 << 1 << ListRange(18 + 3, 18 + 3); QTest::newRow("remove multiple (1 row) from bottom, content y not 0") - << 30 << 60.0 << true + << 30 << 1.0 << true << 15 + 3 << 3 << ListRange(18 + 3, 20 + 3); @@ -5246,11 +5747,7 @@ void tst_QQuickGridView::cacheBuffer() for (int i = 0; i < 90; i++) model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("testRightToLeft", QVariant(false)); - ctxt->setContextProperty("testTopToBottom", QVariant(false)); - + canvas->rootContext()->setContextProperty("testModel", &model); canvas->setSource(testFileUrl("gridview1.qml")); canvas->show(); qApp->processEvents(); @@ -5554,6 +6051,220 @@ void tst_QQuickGridView::unrequestedVisibility() delete canvas; } + +void tst_QQuickGridView::inserted_leftToRight_RtL_TtB() +{ + inserted_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft); +} + +void tst_QQuickGridView::inserted_leftToRight_RtL_TtB_data() +{ + inserted_defaultLayout_data(); +} + +void tst_QQuickGridView::inserted_topToBottom_LtR_TtB() +{ + inserted_defaultLayout(QQuickGridView::FlowTopToBottom); +} + +void tst_QQuickGridView::inserted_topToBottom_LtR_TtB_data() +{ + inserted_defaultLayout_data(); +} + +void tst_QQuickGridView::inserted_topToBottom_RtL_TtB() +{ + inserted_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft); +} + +void tst_QQuickGridView::inserted_topToBottom_RtL_TtB_data() +{ + inserted_defaultLayout_data(); +} + +void tst_QQuickGridView::inserted_leftToRight_LtR_BtT() +{ + inserted_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::LeftToRight, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::inserted_leftToRight_LtR_BtT_data() +{ + inserted_defaultLayout_data(); +} + +void tst_QQuickGridView::inserted_leftToRight_RtL_BtT() +{ + inserted_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::inserted_leftToRight_RtL_BtT_data() +{ + inserted_defaultLayout_data(); +} + +void tst_QQuickGridView::inserted_topToBottom_LtR_BtT() +{ + inserted_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::LeftToRight, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::inserted_topToBottom_LtR_BtT_data() +{ + inserted_defaultLayout_data(); +} + +void tst_QQuickGridView::inserted_topToBottom_RtL_BtT() +{ + inserted_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::inserted_topToBottom_RtL_BtT_data() +{ + inserted_defaultLayout_data(); +} + + +void tst_QQuickGridView::removed_leftToRight_RtL_TtB() +{ + removed_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft); +} + +void tst_QQuickGridView::removed_leftToRight_RtL_TtB_data() +{ + removed_defaultLayout_data(); +} + +void tst_QQuickGridView::removed_topToBottom_LtR_TtB() +{ + removed_defaultLayout(QQuickGridView::FlowTopToBottom); +} + +void tst_QQuickGridView::removed_topToBottom_LtR_TtB_data() +{ + removed_defaultLayout_data(); +} + +void tst_QQuickGridView::removed_topToBottom_RtL_TtB() +{ + removed_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft); +} + +void tst_QQuickGridView::removed_topToBottom_RtL_TtB_data() +{ + removed_defaultLayout_data(); +} + +void tst_QQuickGridView::removed_leftToRight_LtR_BtT() +{ + removed_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::LeftToRight, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::removed_leftToRight_LtR_BtT_data() +{ + removed_defaultLayout_data(); +} + +void tst_QQuickGridView::removed_leftToRight_RtL_BtT() +{ + removed_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::removed_leftToRight_RtL_BtT_data() +{ + removed_defaultLayout_data(); +} + +void tst_QQuickGridView::removed_topToBottom_LtR_BtT() +{ + removed_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::LeftToRight, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::removed_topToBottom_LtR_BtT_data() +{ + removed_defaultLayout_data(); +} + +void tst_QQuickGridView::removed_topToBottom_RtL_BtT() +{ + removed_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::removed_topToBottom_RtL_BtT_data() +{ + removed_defaultLayout_data(); +} + + +void tst_QQuickGridView::moved_leftToRight_RtL_TtB() +{ + moved_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft); +} + +void tst_QQuickGridView::moved_leftToRight_RtL_TtB_data() +{ + moved_defaultLayout_data(); +} + +void tst_QQuickGridView::moved_topToBottom_LtR_TtB() +{ + moved_defaultLayout(QQuickGridView::FlowTopToBottom); +} + +void tst_QQuickGridView::moved_topToBottom_LtR_TtB_data() +{ + moved_defaultLayout_data(); +} + +void tst_QQuickGridView::moved_topToBottom_RtL_TtB() +{ + moved_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft); +} + +void tst_QQuickGridView::moved_topToBottom_RtL_TtB_data() +{ + moved_defaultLayout_data(); +} + +void tst_QQuickGridView::moved_leftToRight_LtR_BtT() +{ + moved_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::LeftToRight, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::moved_leftToRight_LtR_BtT_data() +{ + moved_defaultLayout_data(); +} + +void tst_QQuickGridView::moved_leftToRight_RtL_BtT() +{ + moved_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::moved_leftToRight_RtL_BtT_data() +{ + moved_defaultLayout_data(); +} + +void tst_QQuickGridView::moved_topToBottom_LtR_BtT() +{ + moved_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::LeftToRight, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::moved_topToBottom_LtR_BtT_data() +{ + moved_defaultLayout_data(); +} + +void tst_QQuickGridView::moved_topToBottom_RtL_BtT() +{ + moved_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft, QQuickItemView::BottomToTop); +} + +void tst_QQuickGridView::moved_topToBottom_RtL_BtT_data() +{ + moved_defaultLayout_data(); +} + + QList<int> tst_QQuickGridView::toIntList(const QVariantList &list) { QList<int> ret; diff --git a/tests/auto/quick/qquicklistview/data/header.qml b/tests/auto/quick/qquicklistview/data/header.qml index bf70310630..1cc4ae09ee 100644 --- a/tests/auto/quick/qquicklistview/data/header.qml +++ b/tests/auto/quick/qquicklistview/data/header.qml @@ -15,7 +15,7 @@ Rectangle { height: 30 width: 240 Text { - text: index + " " + x + "," + y + text: index + " " + parent.x + "," + parent.y } color: ListView.isCurrentItem ? "lightsteelblue" : "white" } diff --git a/tests/auto/quick/qquicklistview/data/headerfooter.qml b/tests/auto/quick/qquicklistview/data/headerfooter.qml index 4c3eeca328..07a331a4b7 100644 --- a/tests/auto/quick/qquicklistview/data/headerfooter.qml +++ b/tests/auto/quick/qquicklistview/data/headerfooter.qml @@ -2,27 +2,24 @@ import QtQuick 2.0 ListView { id: view - property bool horizontal: false - property bool rtl: false + width: 240 height: 320 model: testModel - - orientation: horizontal ? ListView.Horizontal : ListView.Vertical + header: Rectangle { objectName: "header" - width: horizontal ? 20 : view.width - height: horizontal ? view.height : 20 + width: orientation == ListView.Horizontal ? 20 : view.width + height: orientation == ListView.Horizontal ? view.height : 20 color: "red" } footer: Rectangle { objectName: "footer" - width: horizontal ? 30 : view.width - height: horizontal ? view.height : 30 + width: orientation == ListView.Horizontal ? 30 : view.width + height: orientation == ListView.Horizontal ? view.height : 30 color: "blue" } delegate: Text { width: 30; height: 30; text: index + "(" + x + ")" } - layoutDirection: rtl ? Qt.RightToLeft : Qt.LeftToRight } diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 1ef895d111..3369cf7933 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -58,7 +58,9 @@ #include <math.h> Q_DECLARE_METATYPE(Qt::LayoutDirection) +Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection) Q_DECLARE_METATYPE(QQuickListView::Orientation) +Q_DECLARE_METATYPE(Qt::Key) using namespace QQuickViewTestUtil; using namespace QQuickVisualTestUtil; @@ -89,6 +91,8 @@ private slots: void qAbstractItemModel_inserted(); void qAbstractItemModel_inserted_more(); void qAbstractItemModel_inserted_more_data(); + void qAbstractItemModel_inserted_more_bottomToTop(); + void qAbstractItemModel_inserted_more_bottomToTop_data(); void qListModelInterface_removed(); void qListModelInterface_removed_more(); @@ -97,6 +101,8 @@ private slots: void qAbstractItemModel_removed(); void qAbstractItemModel_removed_more(); void qAbstractItemModel_removed_more_data(); + void qAbstractItemModel_removed_more_bottomToTop(); + void qAbstractItemModel_removed_more_bottomToTop_data(); void qListModelInterface_moved(); void qListModelInterface_moved_data(); @@ -104,13 +110,18 @@ private slots: void qListModelInterface_package_moved_data(); void qAbstractItemModel_moved(); void qAbstractItemModel_moved_data(); + void qAbstractItemModel_moved_bottomToTop(); + void qAbstractItemModel_moved_bottomToTop_data(); - void multipleChanges(); - void multipleChanges_data(); + void multipleChanges_condensed() { multipleChanges(true); } + void multipleChanges_condensed_data() { multipleChanges_data(); } + void multipleChanges_uncondensed() { multipleChanges(false); } + void multipleChanges_uncondensed_data() { multipleChanges_data(); } void qListModelInterface_clear(); void qListModelInterface_package_clear(); void qAbstractItemModel_clear(); + void qAbstractItemModel_clear_bottomToTop(); void insertBeforeVisible(); void insertBeforeVisible_data(); @@ -120,6 +131,8 @@ private slots: void currentIndex_delayedItemCreation_data(); void currentIndex(); void noCurrentIndex(); + void keyNavigation(); + void keyNavigation_data(); void enforceRange(); void enforceRange_withoutHighlight(); void spacing(); @@ -142,6 +155,8 @@ private slots: void footer(); void footer_data(); void headerFooter(); + void headerFooter_data(); + void resetModel_headerFooter(); void resizeView(); void resizeViewAndRepaint(); void sizeLessThan1(); @@ -195,13 +210,16 @@ private: template <class T> void items(const QUrl &source, bool forceLayout); template <class T> void changed(const QUrl &source, bool forceLayout); template <class T> void inserted(const QUrl &source); - template <class T> void inserted_more(); + template <class T> void inserted_more(QQuickItemView::VerticalLayoutDirection verticalLayoutDirection = QQuickItemView::TopToBottom); template <class T> void removed(const QUrl &source, bool animated); - template <class T> void removed_more(const QUrl &source); - template <class T> void moved(const QUrl &source); - template <class T> void clear(const QUrl &source); + template <class T> void removed_more(const QUrl &source, QQuickItemView::VerticalLayoutDirection verticalLayoutDirection = QQuickItemView::TopToBottom); + template <class T> void moved(const QUrl &source, QQuickItemView::VerticalLayoutDirection verticalLayoutDirection = QQuickItemView::TopToBottom); + template <class T> void clear(const QUrl &source, QQuickItemView::VerticalLayoutDirection verticalLayoutDirection = QQuickItemView::TopToBottom); template <class T> void sections(const QUrl &source); + void multipleChanges(bool condensed); + void multipleChanges_data(); + QList<int> toIntList(const QVariantList &list); void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes); void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes); @@ -522,7 +540,7 @@ void tst_QQuickListView::inserted(const QUrl &source) } template <class T> -void tst_QQuickListView::inserted_more() +void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection verticalLayoutDirection) { QFETCH(qreal, contentY); QFETCH(int, insertIndex); @@ -550,8 +568,15 @@ void tst_QQuickListView::inserted_more() QQuickItem *contentItem = listview->contentItem(); QTRY_VERIFY(contentItem != 0); + bool waitForPolish = (contentY != 0); + if (verticalLayoutDirection == QQuickItemView::BottomToTop) { + listview->setVerticalLayoutDirection(verticalLayoutDirection); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + contentY = -listview->height() - contentY; + } listview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + if (waitForPolish) + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); QList<QPair<QString, QString> > newData; for (int i=0; i<insertCount; i++) @@ -562,27 +587,32 @@ void tst_QQuickListView::inserted_more() // check visibleItems.first() is in correct position QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0); QVERIFY(item0); - QCOMPARE(item0->y(), itemsOffsetAfterMove); + if (verticalLayoutDirection == QQuickItemView::BottomToTop) + QCOMPARE(item0->y(), -item0->height() - itemsOffsetAfterMove); + else + QCOMPARE(item0->y(), itemsOffsetAfterMove); QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); int firstVisibleIndex = -1; for (int i=0; i<items.count(); i++) { - if (items[i]->y() >= contentY) { - QQmlExpression e(qmlContext(items[i]), items[i], "index"); - firstVisibleIndex = e.evaluate().toInt(); + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + if (item && item->isVisible()) { + firstVisibleIndex = i; break; } } QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); // Confirm items positioned correctly and indexes correct - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); QQuickText *name; QQuickText *number; - for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); - QTRY_COMPARE(item->y(), i*20.0 + itemsOffsetAfterMove); + qreal pos = i*20.0 + itemsOffsetAfterMove; + if (verticalLayoutDirection == QQuickItemView::BottomToTop) + pos = -item0->height() - pos; + QTRY_COMPARE(item->y(), pos); name = findItem<QQuickText>(contentItem, "textName", i); QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); @@ -952,15 +982,13 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */) } template <class T> -void tst_QQuickListView::removed_more(const QUrl &source) +void tst_QQuickListView::removed_more(const QUrl &source, QQuickItemView::VerticalLayoutDirection verticalLayoutDirection) { QFETCH(qreal, contentY); QFETCH(int, removeIndex); QFETCH(int, removeCount); QFETCH(qreal, itemsOffsetAfterMove); - QQuickText *name; - QQuickText *number; QQuickView *canvas = getView(); T model; @@ -983,13 +1011,15 @@ void tst_QQuickListView::removed_more(const QUrl &source) QQuickItem *contentItem = listview->contentItem(); QTRY_VERIFY(contentItem != 0); + bool waitForPolish = (contentY != 0); + if (verticalLayoutDirection == QQuickItemView::BottomToTop) { + listview->setVerticalLayoutDirection(verticalLayoutDirection); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + contentY = -listview->height() - contentY; + } listview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); - - // wait for refill (after refill, items above the firstVisibleIndex-1 should not be rendered) - int firstVisibleIndex = contentY / 20; - if (firstVisibleIndex - 2 >= 0) - QTRY_VERIFY(!findItem<QQuickText>(contentItem, "textName", firstVisibleIndex - 2)); + if (waitForPolish) + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); model.removeItems(removeIndex, removeCount); QTRY_COMPARE(listview->property("count").toInt(), model.count()); @@ -997,24 +1027,33 @@ void tst_QQuickListView::removed_more(const QUrl &source) // check visibleItems.first() is in correct position QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0); QVERIFY(item0); - QCOMPARE(item0->y(), itemsOffsetAfterMove); + QVERIFY(item0); + if (verticalLayoutDirection == QQuickItemView::BottomToTop) + QCOMPARE(item0->y(), -item0->height() - itemsOffsetAfterMove); + else + QCOMPARE(item0->y(), itemsOffsetAfterMove); QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); + int firstVisibleIndex = -1; for (int i=0; i<items.count(); i++) { - if (items[i]->y() >= contentY) { - QQmlExpression e(qmlContext(items[i]), items[i], "index"); - firstVisibleIndex = e.evaluate().toInt(); + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + if (item && item->isVisible()) { + firstVisibleIndex = i; break; } } QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); // Confirm items positioned correctly and indexes correct - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); - for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + QQuickText *name; + QQuickText *number; + for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); - QTRY_COMPARE(item->y(), i*20.0 + itemsOffsetAfterMove); + qreal pos = i*20.0 + itemsOffsetAfterMove; + if (verticalLayoutDirection == QQuickItemView::BottomToTop) + pos = -item0->height() - pos; + QTRY_COMPARE(item->y(), pos); name = findItem<QQuickText>(contentItem, "textName", i); QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); @@ -1131,7 +1170,7 @@ void tst_QQuickListView::removed_more_data() } template <class T> -void tst_QQuickListView::clear(const QUrl &source) +void tst_QQuickListView::clear(const QUrl &source, QQuickItemView::VerticalLayoutDirection verticalLayoutDirection) { QQuickView *canvas = createView(); @@ -1153,13 +1192,19 @@ void tst_QQuickListView::clear(const QUrl &source) QTRY_VERIFY(listview != 0); QQuickItem *contentItem = listview->contentItem(); QTRY_VERIFY(contentItem != 0); + + listview->setVerticalLayoutDirection(verticalLayoutDirection); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); model.clear(); + QTRY_COMPARE(findItems<QQuickListView>(contentItem, "wrapper").count(), 0); QTRY_VERIFY(listview->count() == 0); QTRY_VERIFY(listview->currentItem() == 0); - QTRY_VERIFY(listview->contentY() == 0); + if (verticalLayoutDirection == QQuickItemView::TopToBottom) + QTRY_COMPARE(listview->contentY(), 0.0); + else + QTRY_COMPARE(listview->contentY(), -listview->height()); QVERIFY(listview->currentIndex() == -1); // confirm sanity when adding an item to cleared list @@ -1173,7 +1218,7 @@ void tst_QQuickListView::clear(const QUrl &source) } template <class T> -void tst_QQuickListView::moved(const QUrl &source) +void tst_QQuickListView::moved(const QUrl &source, QQuickItemView::VerticalLayoutDirection verticalLayoutDirection) { QFETCH(qreal, contentY); QFETCH(int, from); @@ -1204,15 +1249,19 @@ void tst_QQuickListView::moved(const QUrl &source) QTRY_VERIFY(listview != 0); QQuickItem *contentItem = listview->contentItem(); QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); - QQuickItem *currentItem = listview->currentItem(); - QTRY_VERIFY(currentItem != 0); + // always need to wait for view to be painted before the first move() + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); - if (contentY != 0) { - listview->setContentY(contentY); + bool waitForPolish = (contentY != 0); + if (verticalLayoutDirection == QQuickItemView::BottomToTop) { + listview->setVerticalLayoutDirection(verticalLayoutDirection); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + contentY = -listview->height() - contentY; } + listview->setContentY(contentY); + if (waitForPolish) + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); model.moveItems(from, to, count); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); @@ -1220,22 +1269,22 @@ void tst_QQuickListView::moved(const QUrl &source) QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); int firstVisibleIndex = -1; for (int i=0; i<items.count(); i++) { - if (items[i]->y() >= contentY) { - QQmlExpression e(qmlContext(items[i]), items[i], "index"); - firstVisibleIndex = e.evaluate().toInt(); + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + if (item && item->isVisible()) { + firstVisibleIndex = i; break; } } QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); // Confirm items positioned correctly and indexes correct - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); - for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { - if (i >= firstVisibleIndex + 16) // index has moved out of view - continue; + for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); - QTRY_COMPARE(item->y(), i*20.0 + itemsOffsetAfterMove); + qreal pos = i*20.0 + itemsOffsetAfterMove; + if (verticalLayoutDirection == QQuickItemView::BottomToTop) + pos = -item->height() - pos; + QTRY_COMPARE(item->y(), pos); name = findItem<QQuickText>(contentItem, "textName", i); QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); @@ -1244,7 +1293,7 @@ void tst_QQuickListView::moved(const QUrl &source) QTRY_COMPARE(number->text(), model.number(i)); // current index should have been updated - if (item == currentItem) + if (item == listview->currentItem()) QTRY_COMPARE(listview->currentIndex(), i); } @@ -1403,7 +1452,7 @@ void tst_QQuickListView::moved_data() << -20.0 * 3; // to minimize movement, 16,17,18 move to above item 0, and other items do not move } -void tst_QQuickListView::multipleChanges() +void tst_QQuickListView::multipleChanges(bool condensed) { QFETCH(int, startCount); QFETCH(QList<ListChange>, changes); @@ -1439,31 +1488,32 @@ void tst_QQuickListView::multipleChanges() for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j) items << qMakePair(QString("new item %1").arg(j), QString::number(j)); model.insertItems(changes[i].index, items); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); break; } case ListChange::Removed: model.removeItems(changes[i].index, changes[i].count); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); break; case ListChange::Moved: model.moveItems(changes[i].index, changes[i].to, changes[i].count); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); break; case ListChange::SetCurrent: listview->setCurrentIndex(changes[i].index); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); break; case ListChange::SetContentY: listview->setContentY(changes[i].pos); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); break; + default: + continue; + } + if (!condensed) { + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); } } + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); - QTRY_COMPARE(listview->count(), newCount); + QCOMPARE(listview->count(), newCount); QCOMPARE(listview->count(), model.count()); - QTRY_COMPARE(listview->currentIndex(), newCurrentIndex); + QCOMPARE(listview->currentIndex(), newCurrentIndex); QQuickText *name; QQuickText *number; @@ -1626,13 +1676,34 @@ void tst_QQuickListView::multipleChanges_data() << ListChange::insert(3, 5) ) << 15 << 8; - QTest::newRow("clear current") << 0 << (QList<ListChange>() << ListChange::insert(0, 5) << ListChange::setCurrent(-1) << ListChange::remove(0, 5) << ListChange::insert(0, 5) ) << 5 << -1; + + QTest::newRow("remove, scroll") << 30 << (QList<ListChange>() + << ListChange::remove(20, 5) + << ListChange::setContentY(20) + ) << 25 << 0; + + QTest::newRow("insert, scroll") << 10 << (QList<ListChange>() + << ListChange::insert(9, 5) + << ListChange::setContentY(20) + ) << 15 << 0; + + QTest::newRow("move, scroll") << 20 << (QList<ListChange>() + << ListChange::move(15, 8, 3) + << ListChange::setContentY(0) + ) << 20 << 0; + + QTest::newRow("clear, insert, scroll") << 30 << (QList<ListChange>() + << ListChange::setContentY(20) + << ListChange::remove(0, 30) + << ListChange::insert(0, 2) + << ListChange::setContentY(0) + ) << 2 << 0; } void tst_QQuickListView::swapWithFirstItem() @@ -2313,35 +2384,11 @@ void tst_QQuickListView::currentIndex() QCOMPARE(listview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 20)); QCOMPARE(listview->highlightItem()->y(), listview->currentItem()->y()); - // no wrap listview->setCurrentIndex(0); QCOMPARE(listview->currentIndex(), 0); // confirm that the velocity is updated QTRY_VERIFY(listview->verticalVelocity() != 0.0); - listview->incrementCurrentIndex(); - QCOMPARE(listview->currentIndex(), 1); - listview->decrementCurrentIndex(); - QCOMPARE(listview->currentIndex(), 0); - - listview->decrementCurrentIndex(); - QCOMPARE(listview->currentIndex(), 0); - - // with wrap - ctxt->setContextProperty("testWrap", QVariant(true)); - QVERIFY(listview->isWrapEnabled()); - - listview->decrementCurrentIndex(); - QCOMPARE(listview->currentIndex(), model.count()-1); - - QTRY_COMPARE(listview->contentY(), 280.0); - - listview->incrementCurrentIndex(); - QCOMPARE(listview->currentIndex(), 0); - - QTRY_COMPARE(listview->contentY(), 0.0); - - // footer should become visible if it is out of view, and then current index is set to count-1 canvas->rootObject()->setProperty("showFooter", true); QTRY_VERIFY(listview->footerItem()); @@ -2360,40 +2407,6 @@ void tst_QQuickListView::currentIndex() QTRY_COMPARE(listview->contentY(), -listview->headerItem()->height()); canvas->rootObject()->setProperty("showHeader", false); - - // Test keys - canvas->show(); - canvas->requestActivateWindow(); - QTest::qWaitForWindowShown(canvas); - QTRY_VERIFY(qGuiApp->focusWindow() == canvas); - - listview->setCurrentIndex(0); - - QTest::keyClick(canvas, Qt::Key_Down); - QCOMPARE(listview->currentIndex(), 1); - - QTest::keyClick(canvas, Qt::Key_Up); - QCOMPARE(listview->currentIndex(), 0); - - // hold down Key_Down - for (int i=0; i<model.count()-1; i++) { - QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true); - QTRY_COMPARE(listview->currentIndex(), i+1); - } - QTest::keyRelease(canvas, Qt::Key_Down); - QTRY_COMPARE(listview->currentIndex(), model.count()-1); - QTRY_COMPARE(listview->contentY(), 280.0); - - // hold down Key_Up - for (int i=model.count()-1; i > 0; i--) { - QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true); - QTRY_COMPARE(listview->currentIndex(), i-1); - } - QTest::keyRelease(canvas, Qt::Key_Up); - QTRY_COMPARE(listview->currentIndex(), 0); - QTRY_COMPARE(listview->contentY(), 0.0); - - // turn off auto highlight listview->setHighlightFollowsCurrentItem(false); QVERIFY(listview->highlightFollowsCurrentItem() == false); @@ -2416,6 +2429,7 @@ void tst_QQuickListView::currentIndex() QVERIFY(!listview->highlightItem()); QVERIFY(!listview->currentItem()); + // moving currentItem out of view should make it invisible listview->setCurrentIndex(0); QTRY_VERIFY(listview->currentItem()->isVisible()); listview->setContentY(200); @@ -2462,6 +2476,129 @@ void tst_QQuickListView::noCurrentIndex() delete canvas; } +void tst_QQuickListView::keyNavigation() +{ + QFETCH(QQuickListView::Orientation, orientation); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); + QFETCH(Qt::Key, forwardsKey); + QFETCH(Qt::Key, backwardsKey); + QFETCH(QPointF, contentPosAtFirstItem); + QFETCH(QPointF, contentPosAtLastItem); + + QmlListModel model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QQuickView *canvas = getView(); + TestObject *testObject = new TestObject; + canvas->rootContext()->setContextProperty("testModel", &model); + canvas->rootContext()->setContextProperty("testObject", testObject); + canvas->setSource(testFileUrl("listviewtest.qml")); + canvas->show(); + qApp->processEvents(); + + QQuickListView *listview = findItem<QQuickListView>(canvas->rootObject(), "list"); + QTRY_VERIFY(listview != 0); + + listview->setOrientation(orientation); + listview->setLayoutDirection(layoutDirection); + listview->setVerticalLayoutDirection(verticalLayoutDirection); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + + canvas->requestActivateWindow(); + QTRY_VERIFY(qGuiApp->focusWindow() == canvas); + QCOMPARE(listview->currentIndex(), 0); + + QTest::keyClick(canvas, forwardsKey); + QCOMPARE(listview->currentIndex(), 1); + + QTest::keyClick(canvas, backwardsKey); + QCOMPARE(listview->currentIndex(), 0); + + // hold down a key to go forwards + for (int i=0; i<model.count()-1; i++) { + QTest::simulateEvent(canvas, true, forwardsKey, Qt::NoModifier, "", true); + QTRY_COMPARE(listview->currentIndex(), i+1); + } + QTest::keyRelease(canvas, forwardsKey); + QTRY_COMPARE(listview->currentIndex(), model.count()-1); + QTRY_COMPARE(listview->contentX(), contentPosAtLastItem.x()); + QTRY_COMPARE(listview->contentY(), contentPosAtLastItem.y()); + + // hold down a key to go backwards + for (int i=model.count()-1; i > 0; i--) { + QTest::simulateEvent(canvas, true, backwardsKey, Qt::NoModifier, "", true); + QTRY_COMPARE(listview->currentIndex(), i-1); + } + QTest::keyRelease(canvas, backwardsKey); + QTRY_COMPARE(listview->currentIndex(), 0); + QTRY_COMPARE(listview->contentX(), contentPosAtFirstItem.x()); + QTRY_COMPARE(listview->contentY(), contentPosAtFirstItem.y()); + + // no wrap + QVERIFY(!listview->isWrapEnabled()); + listview->incrementCurrentIndex(); + QCOMPARE(listview->currentIndex(), 1); + listview->decrementCurrentIndex(); + QCOMPARE(listview->currentIndex(), 0); + + listview->decrementCurrentIndex(); + QCOMPARE(listview->currentIndex(), 0); + + // with wrap + listview->setWrapEnabled(true); + QVERIFY(listview->isWrapEnabled()); + + listview->decrementCurrentIndex(); + QCOMPARE(listview->currentIndex(), model.count()-1); + QTRY_COMPARE(listview->contentX(), contentPosAtLastItem.x()); + QTRY_COMPARE(listview->contentY(), contentPosAtLastItem.y()); + + listview->incrementCurrentIndex(); + QCOMPARE(listview->currentIndex(), 0); + QTRY_COMPARE(listview->contentX(), contentPosAtFirstItem.x()); + QTRY_COMPARE(listview->contentY(), contentPosAtFirstItem.y()); + + releaseView(canvas); + delete testObject; +} + +void tst_QQuickListView::keyNavigation_data() +{ + QTest::addColumn<QQuickListView::Orientation>("orientation"); + QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); + QTest::addColumn<Qt::Key>("forwardsKey"); + QTest::addColumn<Qt::Key>("backwardsKey"); + QTest::addColumn<QPointF>("contentPosAtFirstItem"); + QTest::addColumn<QPointF>("contentPosAtLastItem"); + + QTest::newRow("Vertical, TopToBottom") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom + << Qt::Key_Down << Qt::Key_Up + << QPointF(0, 0) + << QPointF(0, 30*20 - 320); + + QTest::newRow("Vertical, BottomToTop") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop + << Qt::Key_Up << Qt::Key_Down + << QPointF(0, -320) + << QPointF(0, -(30 * 20)); + + QTest::newRow("Horizontal, LeftToRight") + << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom + << Qt::Key_Right << Qt::Key_Left + << QPointF(0, 0) + << QPointF(30*240 - 240, 0); + + QTest::newRow("Horizontal, RightToLeft") + << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom + << Qt::Key_Left << Qt::Key_Right + << QPointF(-240, 0) + << QPointF(-(30 * 240), 0); +} + void tst_QQuickListView::itemList() { QQuickView *canvas = createView(); @@ -3083,11 +3220,12 @@ void tst_QQuickListView::header() { QFETCH(QQuickListView::Orientation, orientation); QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); QFETCH(QPointF, initialHeaderPos); - QFETCH(QPointF, firstDelegatePos); - QFETCH(QPointF, initialContentPos); QFETCH(QPointF, changedHeaderPos); + QFETCH(QPointF, initialContentPos); QFETCH(QPointF, changedContentPos); + QFETCH(QPointF, firstDelegatePos); QFETCH(QPointF, resizeContentPos); QmlListModel model; @@ -3106,6 +3244,8 @@ void tst_QQuickListView::header() QTRY_VERIFY(listview != 0); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); + listview->setVerticalLayoutDirection(verticalLayoutDirection); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); QQuickItem *contentItem = listview->contentItem(); QTRY_VERIFY(contentItem != 0); @@ -3156,6 +3296,11 @@ void tst_QQuickListView::header() QVERIFY(item); QCOMPARE(item->pos(), firstDelegatePos); + listview->positionViewAtBeginning(); + header->setHeight(10); + header->setWidth(40); + QTRY_COMPARE(QPointF(listview->contentX(), listview->contentY()), resizeContentPos); + releaseView(canvas); @@ -3173,6 +3318,7 @@ void tst_QQuickListView::header() QTRY_VERIFY(listview != 0); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); + listview->setVerticalLayoutDirection(verticalLayoutDirection); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); listview->setWidth(240); @@ -3187,6 +3333,7 @@ void tst_QQuickListView::header_data() { QTest::addColumn<QQuickListView::Orientation>("orientation"); QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); QTest::addColumn<QPointF>("initialHeaderPos"); QTest::addColumn<QPointF>("changedHeaderPos"); QTest::addColumn<QPointF>("initialContentPos"); @@ -3196,11 +3343,11 @@ void tst_QQuickListView::header_data() // header1 = 100 x 30 // header2 = 50 x 20 - // delegates = 240 x 20 + // delegates = 240 x 30 // view width = 240 // header above items, top left - QTest::newRow("vertical, left to right") << QQuickListView::Vertical << Qt::LeftToRight + QTest::newRow("vertical, left to right") << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << QPointF(0, -30) << QPointF(0, -20) << QPointF(0, -30) @@ -3209,7 +3356,7 @@ void tst_QQuickListView::header_data() << QPointF(0, -10); // header above items, top right - QTest::newRow("vertical, layout right to left") << QQuickListView::Vertical << Qt::RightToLeft + QTest::newRow("vertical, layout right to left") << QQuickListView::Vertical << Qt::RightToLeft << QQuickItemView::TopToBottom << QPointF(0, -30) << QPointF(0, -20) << QPointF(0, -30) @@ -3218,7 +3365,7 @@ void tst_QQuickListView::header_data() << QPointF(0, -10); // header to left of items - QTest::newRow("horizontal, layout left to right") << QQuickListView::Horizontal << Qt::LeftToRight + QTest::newRow("horizontal, layout left to right") << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom << QPointF(-100, 0) << QPointF(-50, 0) << QPointF(-100, 0) @@ -3227,13 +3374,22 @@ void tst_QQuickListView::header_data() << QPointF(-40, 0); // header to right of items - QTest::newRow("horizontal, layout right to left") << QQuickListView::Horizontal << Qt::RightToLeft + QTest::newRow("horizontal, layout right to left") << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom << QPointF(0, 0) << QPointF(0, 0) << QPointF(-240 + 100, 0) << QPointF(-240 + 50, 0) << QPointF(-240, 0) << QPointF(-240 + 40, 0); + + // header below items + QTest::newRow("vertical, bottom to top") << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, 0) + << QPointF(0, 0) + << QPointF(0, -320 + 30) + << QPointF(0, -320 + 20) + << QPointF(0, -30) + << QPointF(0, -320 + 10); } void tst_QQuickListView::header_delayItemCreation() @@ -3268,6 +3424,7 @@ void tst_QQuickListView::footer() { QFETCH(QQuickListView::Orientation, orientation); QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); QFETCH(QPointF, initialFooterPos); QFETCH(QPointF, firstDelegatePos); QFETCH(QPointF, initialContentPos); @@ -3292,6 +3449,7 @@ void tst_QQuickListView::footer() QTRY_VERIFY(listview != 0); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); + listview->setVerticalLayoutDirection(verticalLayoutDirection); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); QQuickItem *contentItem = listview->contentItem(); @@ -3320,7 +3478,8 @@ void tst_QQuickListView::footer() model.removeItem(1); if (orientation == QQuickListView::Vertical) { - QTRY_COMPARE(footer->y(), initialFooterPos.y() - 20); // delegate height = 20 + QTRY_COMPARE(footer->y(), verticalLayoutDirection == QQuickItemView::TopToBottom ? + initialFooterPos.y() - 20 : initialFooterPos.y() + 20); // delegate width = 40 } else { QTRY_COMPARE(footer->x(), layoutDirection == Qt::LeftToRight ? initialFooterPos.x() - 40 : initialFooterPos.x() + 40); // delegate width = 40 @@ -3332,6 +3491,8 @@ void tst_QQuickListView::footer() QPointF posWhenNoItems(0, 0); if (orientation == QQuickListView::Horizontal && layoutDirection == Qt::RightToLeft) posWhenNoItems.setX(-100); + else if (orientation == QQuickListView::Vertical && verticalLayoutDirection == QQuickItemView::BottomToTop) + posWhenNoItems.setY(-30); QTRY_COMPARE(footer->pos(), posWhenNoItems); // if header is present, it's at a negative pos, so the footer should not move @@ -3376,6 +3537,7 @@ void tst_QQuickListView::footer_data() { QTest::addColumn<QQuickListView::Orientation>("orientation"); QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); QTest::addColumn<QPointF>("initialFooterPos"); QTest::addColumn<QPointF>("changedFooterPos"); QTest::addColumn<QPointF>("initialContentPos"); @@ -3390,7 +3552,7 @@ void tst_QQuickListView::footer_data() // view height = 320 // footer below items, bottom left - QTest::newRow("vertical, layout left to right") << QQuickListView::Vertical << Qt::LeftToRight + QTest::newRow("vertical, layout left to right") << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << QPointF(0, 3 * 20) << QPointF(0, 30 * 20) // added 30 items << QPointF(0, 0) @@ -3399,7 +3561,7 @@ void tst_QQuickListView::footer_data() << QPointF(0, 30 * 20 - 320 + 10); // footer below items, bottom right - QTest::newRow("vertical, layout right to left") << QQuickListView::Vertical << Qt::RightToLeft + QTest::newRow("vertical, layout right to left") << QQuickListView::Vertical << Qt::RightToLeft << QQuickItemView::TopToBottom << QPointF(0, 3 * 20) << QPointF(0, 30 * 20) << QPointF(0, 0) @@ -3408,7 +3570,7 @@ void tst_QQuickListView::footer_data() << QPointF(0, 30 * 20 - 320 + 10); // footer to right of items - QTest::newRow("horizontal, layout left to right") << QQuickListView::Horizontal << Qt::LeftToRight + QTest::newRow("horizontal, layout left to right") << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom << QPointF(40 * 3, 0) << QPointF(40 * 30, 0) << QPointF(0, 0) @@ -3417,13 +3579,22 @@ void tst_QQuickListView::footer_data() << QPointF(40 * 30 - 240 + 40, 0); // footer to left of items - QTest::newRow("horizontal, layout right to left") << QQuickListView::Horizontal << Qt::RightToLeft + QTest::newRow("horizontal, layout right to left") << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom << QPointF(-(40 * 3) - 100, 0) << QPointF(-(40 * 30) - 50, 0) // 50 = new footer width << QPointF(-240, 0) << QPointF(-240, 0) << QPointF(-40, 0) << QPointF(-(40 * 30) - 40, 0); + + // footer above items + QTest::newRow("vertical, layout left to right") << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, -(3 * 20) - 30) + << QPointF(0, -(30 * 20) - 20) + << QPointF(0, -320) + << QPointF(0, -320) + << QPointF(0, -20) + << QPointF(0, -(30 * 20) - 10); } class LVAccessor : public QQuickListView @@ -3435,140 +3606,127 @@ public: qreal maxX() const { return maxXExtent(); } }; + void tst_QQuickListView::headerFooter() { - { - // Vertical - QQuickView *canvas = createView(); - - QmlListModel model; - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - - canvas->setSource(testFileUrl("headerfooter.qml")); - qApp->processEvents(); - - QQuickListView *listview = qobject_cast<QQuickListView*>(canvas->rootObject()); - QTRY_VERIFY(listview != 0); - - QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - - QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->y(), -header->height()); - - QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->y(), 0.); - - QCOMPARE(static_cast<LVAccessor*>(listview)->minY(), header->height()); - QCOMPARE(static_cast<LVAccessor*>(listview)->maxY(), header->height()); - - delete canvas; - } - { - // Horizontal - QQuickView *canvas = createView(); - - QmlListModel model; - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); - - canvas->setSource(testFileUrl("headerfooter.qml")); - canvas->rootObject()->setProperty("horizontal", true); - qApp->processEvents(); - - QQuickListView *listview = qobject_cast<QQuickListView*>(canvas->rootObject()); - QTRY_VERIFY(listview != 0); - - QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - - QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->x(), -header->width()); + QFETCH(QQuickListView::Orientation, orientation); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); + QFETCH(QPointF, headerPos); + QFETCH(QPointF, footerPos); + QFETCH(QPointF, minPos); + QFETCH(QPointF, maxPos); - QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->x(), 0.); + QQuickView *canvas = getView(); - QCOMPARE(static_cast<LVAccessor*>(listview)->minX(), header->width()); - QCOMPARE(static_cast<LVAccessor*>(listview)->maxX(), header->width()); + QmlListModel model; + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + canvas->setSource(testFileUrl("headerfooter.qml")); + canvas->show(); + qApp->processEvents(); - delete canvas; - } - { - // Horizontal RTL - QQuickView *canvas = createView(); + QQuickListView *listview = qobject_cast<QQuickListView*>(canvas->rootObject()); + QTRY_VERIFY(listview != 0); + listview->setOrientation(orientation); + listview->setLayoutDirection(layoutDirection); + listview->setVerticalLayoutDirection(verticalLayoutDirection); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); - QmlListModel model; - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); + QQuickItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); - canvas->setSource(testFileUrl("headerfooter.qml")); - canvas->rootObject()->setProperty("horizontal", true); - canvas->rootObject()->setProperty("rtl", true); - qApp->processEvents(); + QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->pos(), headerPos); - QQuickListView *listview = qobject_cast<QQuickListView*>(canvas->rootObject()); - QTRY_VERIFY(listview != 0); + QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->pos(), footerPos); - QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QCOMPARE(static_cast<LVAccessor*>(listview)->minX(), minPos.x()); + QCOMPARE(static_cast<LVAccessor*>(listview)->minY(), minPos.y()); + QCOMPARE(static_cast<LVAccessor*>(listview)->maxX(), maxPos.x()); + QCOMPARE(static_cast<LVAccessor*>(listview)->maxY(), maxPos.y()); - QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->x(), 0.); + releaseView(canvas); +} - QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->x(), -footer->width()); +void tst_QQuickListView::headerFooter_data() +{ + QTest::addColumn<QQuickListView::Orientation>("orientation"); + QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); + QTest::addColumn<QPointF>("headerPos"); + QTest::addColumn<QPointF>("footerPos"); + QTest::addColumn<QPointF>("minPos"); + QTest::addColumn<QPointF>("maxPos"); + + // header is 240x20 (or 20x320 in Horizontal orientation) + // footer is 240x30 (or 30x320 in Horizontal orientation) + + QTest::newRow("Vertical, TopToBottom") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom + << QPointF(0, -20) << QPointF(0, 0) + << QPointF(0, 20) << QPointF(240, 20); + + QTest::newRow("Vertical, BottomToTop") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, 0) << QPointF(0, -30) + << QPointF(0, 320 - 20) << QPointF(240, 320 - 20); // content flow is reversed + + + QTest::newRow("Horizontal, LeftToRight") + << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom + << QPointF(-20, 0) << QPointF(0, 0) + << QPointF(20, 0) << QPointF(20, 320); + + QTest::newRow("Horizontal, RightToLeft") + << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom + << QPointF(0, 0) << QPointF(-30, 0) + << QPointF(240 - 20, 0) << QPointF(240 - 20, 320); // content flow is reversed +} - QCOMPARE(static_cast<LVAccessor*>(listview)->minX(), 240. - header->width()); - QCOMPARE(static_cast<LVAccessor*>(listview)->maxX(), 240. - header->width()); +void tst_QQuickListView::resetModel_headerFooter() +{ + // Resetting a model shouldn't crash in views with header/footer - delete canvas; - } - { - // Reset model - QQuickView *canvas = createView(); + QQuickView *canvas = createView(); - QaimModel model; - for (int i = 0; i < 4; i++) - model.addItem("Item" + QString::number(i), ""); - QQmlContext *ctxt = canvas->rootContext(); - ctxt->setContextProperty("testModel", &model); + QaimModel model; + for (int i = 0; i < 4; i++) + model.addItem("Item" + QString::number(i), ""); + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); - canvas->setSource(testFileUrl("headerfooter.qml")); - qApp->processEvents(); + canvas->setSource(testFileUrl("headerfooter.qml")); + qApp->processEvents(); - QQuickListView *listview = qobject_cast<QQuickListView*>(canvas->rootObject()); - QTRY_VERIFY(listview != 0); + QQuickListView *listview = qobject_cast<QQuickListView*>(canvas->rootObject()); + QTRY_VERIFY(listview != 0); - QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QQuickItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); - QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->y(), -header->height()); + QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->y(), -header->height()); - QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->y(), 30.*4); + QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->y(), 30.*4); - model.reset(); + model.reset(); - header = findItem<QQuickItem>(contentItem, "header"); - QVERIFY(header); - QCOMPARE(header->y(), -header->height()); + header = findItem<QQuickItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->y(), -header->height()); - footer = findItem<QQuickItem>(contentItem, "footer"); - QVERIFY(footer); - QCOMPARE(footer->y(), 30.*4); + footer = findItem<QQuickItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->y(), 30.*4); - delete canvas; - } + delete canvas; } void tst_QQuickListView::resizeView() @@ -4288,13 +4446,14 @@ void tst_QQuickListView::marginsResize() { QFETCH(QQuickListView::Orientation, orientation); QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); QFETCH(qreal, start); QFETCH(qreal, end); QPoint flickStart(20, 20); QPoint flickEnd(20, 20); if (orientation == QQuickListView::Vertical) - flickStart.ry() += 180; + flickStart.ry() += (verticalLayoutDirection == QQuickItemView::TopToBottom) ? 180 : -180; else flickStart.rx() += (layoutDirection == Qt::LeftToRight) ? 180 : -180; @@ -4309,6 +4468,7 @@ void tst_QQuickListView::marginsResize() listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); + listview->setVerticalLayoutDirection(verticalLayoutDirection); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); // view is resized after componentCompleted - top margin should still be visible @@ -4354,20 +4514,34 @@ void tst_QQuickListView::marginsResize_data() { QTest::addColumn<QQuickListView::Orientation>("orientation"); QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickListView::VerticalLayoutDirection>("verticalLayoutDirection"); QTest::addColumn<qreal>("start"); QTest::addColumn<qreal>("end"); // in Right to Left mode, leftMargin still means leftMargin - it doesn't reverse to mean rightMargin - QTest::newRow("vertical") << QQuickListView::Vertical << Qt::LeftToRight << -40.0 << 1020.0; - QTest::newRow("horizontal") << QQuickListView::Horizontal << Qt::LeftToRight << -40.0 << 1020.0; - QTest::newRow("horizontal, rtl") << QQuickListView::Horizontal << Qt::RightToLeft << -180.0 << -1240.0; + QTest::newRow("vertical") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom + << -40.0 << 1020.0; + + QTest::newRow("vertical, BottomToTop") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop + << -180.0 << -1240.0; + + QTest::newRow("horizontal") + << QQuickListView::Horizontal<< Qt::LeftToRight << QQuickItemView::TopToBottom + << -40.0 << 1020.0; + + QTest::newRow("horizontal, rtl") + << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom + << -180.0 << -1240.0; } void tst_QQuickListView::snapToItem_data() { QTest::addColumn<QQuickListView::Orientation>("orientation"); QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); QTest::addColumn<int>("highlightRangeMode"); QTest::addColumn<QPoint>("flickStart"); QTest::addColumn<QPoint>("flickEnd"); @@ -4375,22 +4549,36 @@ void tst_QQuickListView::snapToItem_data() QTest::addColumn<qreal>("endExtent"); QTest::addColumn<qreal>("startExtent"); - QTest::newRow("vertical, left to right") << QQuickListView::Vertical << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + QTest::newRow("vertical, top to bottom") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 560.0 << 0.0; - QTest::newRow("horizontal, left to right") << QQuickListView::Horizontal << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + QTest::newRow("vertical, bottom to top") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop << int(QQuickItemView::NoHighlightRange) + << QPoint(20, 20) << QPoint(20, 200) << -60.0 << -560.0 - 240.0 << -240.0; + + QTest::newRow("horizontal, left to right") + << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 560.0 << 0.0; - QTest::newRow("horizontal, right to left") << QQuickListView::Horizontal << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) + QTest::newRow("horizontal, right to left") + << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -560.0 - 240.0 << -240.0; - QTest::newRow("vertical, left to right, enforce range") << QQuickListView::Vertical << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("vertical, top to bottom, enforce range") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 700.0 << -20.0; - QTest::newRow("horizontal, left to right, enforce range") << QQuickListView::Horizontal << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("vertical, bottom to top, enforce range") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop << int(QQuickItemView::StrictlyEnforceRange) + << QPoint(20, 20) << QPoint(20, 200) << -60.0 << -560.0 - 240.0 - 140.0 << -220.0; + + QTest::newRow("horizontal, left to right, enforce range") + << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 700.0 << -20.0; - QTest::newRow("horizontal, right to left, enforce range") << QQuickListView::Horizontal << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("horizontal, right to left, enforce range") + << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -560.0 - 240.0 - 140.0 << -220.0; } @@ -4398,6 +4586,7 @@ void tst_QQuickListView::snapToItem() { QFETCH(QQuickListView::Orientation, orientation); QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); QFETCH(int, highlightRangeMode); QFETCH(QPoint, flickStart); QFETCH(QPoint, flickEnd); @@ -4416,6 +4605,7 @@ void tst_QQuickListView::snapToItem() listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); + listview->setVerticalLayoutDirection(verticalLayoutDirection); listview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode)); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); @@ -4435,7 +4625,7 @@ void tst_QQuickListView::snapToItem() flick(canvas, flickStart, flickEnd, 180); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical - ? !listview->isAtYEnd() + ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYEnd() : !listview->isAtYBeginning() : layoutDirection == Qt::LeftToRight ? !listview->isAtXEnd() : !listview->isAtXBeginning()); if (orientation == QQuickListView::Vertical) @@ -4448,7 +4638,7 @@ void tst_QQuickListView::snapToItem() flick(canvas, flickEnd, flickStart, 180); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical - ? !listview->isAtYBeginning() + ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYBeginning() : !listview->isAtYEnd() : layoutDirection == Qt::LeftToRight ? !listview->isAtXBeginning() : !listview->isAtXEnd()); if (orientation == QQuickListView::Vertical) @@ -4524,6 +4714,16 @@ void tst_QQuickListView::qAbstractItemModel_inserted_more_data() inserted_more_data(); } +void tst_QQuickListView::qAbstractItemModel_inserted_more_bottomToTop() +{ + inserted_more<QaimModel>(QQuickItemView::BottomToTop); +} + +void tst_QQuickListView::qAbstractItemModel_inserted_more_bottomToTop_data() +{ + inserted_more_data(); +} + void tst_QQuickListView::qListModelInterface_removed() { removed<QmlListModel>(testFileUrl("listviewtest.qml"), false); @@ -4562,6 +4762,16 @@ void tst_QQuickListView::qAbstractItemModel_removed_more_data() removed_more_data(); } +void tst_QQuickListView::qAbstractItemModel_removed_more_bottomToTop() +{ + removed_more<QaimModel>(testFileUrl("listviewtest.qml"), QQuickItemView::BottomToTop); +} + +void tst_QQuickListView::qAbstractItemModel_removed_more_bottomToTop_data() +{ + removed_more_data(); +} + void tst_QQuickListView::qListModelInterface_moved() { moved<QmlListModel>(testFileUrl("listviewtest.qml")); @@ -4592,6 +4802,16 @@ void tst_QQuickListView::qAbstractItemModel_moved_data() moved_data(); } +void tst_QQuickListView::qAbstractItemModel_moved_bottomToTop() +{ + moved<QaimModel>(testFileUrl("listviewtest-package.qml"), QQuickItemView::BottomToTop); +} + +void tst_QQuickListView::qAbstractItemModel_moved_bottomToTop_data() +{ + moved_data(); +} + void tst_QQuickListView::qListModelInterface_clear() { clear<QmlListModel>(testFileUrl("listviewtest.qml")); @@ -4607,6 +4827,11 @@ void tst_QQuickListView::qAbstractItemModel_clear() clear<QaimModel>(testFileUrl("listviewtest.qml")); } +void tst_QQuickListView::qAbstractItemModel_clear_bottomToTop() +{ + clear<QaimModel>(testFileUrl("listviewtest.qml"), QQuickItemView::BottomToTop); +} + void tst_QQuickListView::qListModelInterface_sections() { sections<QmlListModel>(testFileUrl("listview-sections.qml")); @@ -4705,6 +4930,7 @@ void tst_QQuickListView::snapOneItem_data() { QTest::addColumn<QQuickListView::Orientation>("orientation"); QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); QTest::addColumn<int>("highlightRangeMode"); QTest::addColumn<QPoint>("flickStart"); QTest::addColumn<QPoint>("flickEnd"); @@ -4712,22 +4938,36 @@ void tst_QQuickListView::snapOneItem_data() QTest::addColumn<qreal>("endExtent"); QTest::addColumn<qreal>("startExtent"); - QTest::newRow("vertical, left to right") << QQuickListView::Vertical << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + QTest::newRow("vertical, top to bottom") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) << QPoint(20, 200) << QPoint(20, 20) << 180.0 << 560.0 << 0.0; - QTest::newRow("horizontal, left to right") << QQuickListView::Horizontal << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + QTest::newRow("vertical, bottom to top") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop << int(QQuickItemView::NoHighlightRange) + << QPoint(20, 20) << QPoint(20, 200) << -420.0 << -560.0 - 240.0 << -240.0; + + QTest::newRow("horizontal, left to right") + << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) << QPoint(200, 20) << QPoint(20, 20) << 180.0 << 560.0 << 0.0; - QTest::newRow("horizontal, right to left") << QQuickListView::Horizontal << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) + QTest::newRow("horizontal, right to left") + << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) << QPoint(20, 20) << QPoint(200, 20) << -420.0 << -560.0 - 240.0 << -240.0; - QTest::newRow("vertical, left to right, enforce range") << QQuickListView::Vertical << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("vertical, top to bottom, enforce range") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) << QPoint(20, 200) << QPoint(20, 20) << 180.0 << 580.0 << -20.0; - QTest::newRow("horizontal, left to right, enforce range") << QQuickListView::Horizontal << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("vertical, bottom to top, enforce range") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop << int(QQuickItemView::StrictlyEnforceRange) + << QPoint(20, 20) << QPoint(20, 200) << -420.0 << -580.0 - 240.0 << -220.0; + + QTest::newRow("horizontal, left to right, enforce range") + << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) << QPoint(200, 20) << QPoint(20, 20) << 180.0 << 580.0 << -20.0; - QTest::newRow("horizontal, right to left, enforce range") << QQuickListView::Horizontal << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) + QTest::newRow("horizontal, right to left, enforce range") + << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) << QPoint(20, 20) << QPoint(200, 20) << -420.0 << -580.0 - 240.0 << -220.0; } @@ -4735,6 +4975,7 @@ void tst_QQuickListView::snapOneItem() { QFETCH(QQuickListView::Orientation, orientation); QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); QFETCH(int, highlightRangeMode); QFETCH(QPoint, flickStart); QFETCH(QPoint, flickEnd); @@ -4758,6 +4999,7 @@ void tst_QQuickListView::snapOneItem() listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); + listview->setVerticalLayoutDirection(verticalLayoutDirection); listview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode)); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); @@ -4784,7 +5026,7 @@ void tst_QQuickListView::snapOneItem() flick(canvas, flickStart, flickEnd, 180); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical - ? !listview->isAtYEnd() + ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYEnd() : !listview->isAtYBeginning() : layoutDirection == Qt::LeftToRight ? !listview->isAtXEnd() : !listview->isAtXBeginning()); if (orientation == QQuickListView::Vertical) @@ -4802,7 +5044,7 @@ void tst_QQuickListView::snapOneItem() flick(canvas, flickEnd, flickStart, 180); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical - ? !listview->isAtYBeginning() + ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYBeginning() : !listview->isAtYEnd() : layoutDirection == Qt::LeftToRight ? !listview->isAtXBeginning() : !listview->isAtXEnd()); if (orientation == QQuickListView::Vertical) @@ -6277,3 +6519,4 @@ QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" + diff --git a/tests/auto/quick/qquickpixmapcache/qquickpixmapcache.pro b/tests/auto/quick/qquickpixmapcache/qquickpixmapcache.pro index a24ea52e11..831ffd3c35 100644 --- a/tests/auto/quick/qquickpixmapcache/qquickpixmapcache.pro +++ b/tests/auto/quick/qquickpixmapcache/qquickpixmapcache.pro @@ -15,6 +15,6 @@ TESTDATA = data/* # LIBS += -lgcov CONFIG += parallel_test -CONFIG += insignificant_test +CONFIG += insignificant_test # QTBUG-25307 QT += core-private gui-private qml-private quick-private network testlib concurrent diff --git a/tests/auto/quick/qquickpositioners/qquickpositioners.pro b/tests/auto/quick/qquickpositioners/qquickpositioners.pro index dbbfae0ebf..e4fce55548 100644 --- a/tests/auto/quick/qquickpositioners/qquickpositioners.pro +++ b/tests/auto/quick/qquickpositioners/qquickpositioners.pro @@ -1,4 +1,5 @@ CONFIG += testcase +CONFIG += insignificant_test TARGET = tst_qquickpositioners SOURCES += tst_qquickpositioners.cpp diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp index ae2bdc7fae..6ceacdfaf0 100644 --- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp @@ -1875,11 +1875,15 @@ void tst_qquickpositioners::test_attachedproperties_dynamic() QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait) { QQuickView *canvas = new QQuickView(0); + qDebug() << "1"; canvas->setSource(QUrl::fromLocalFile(filename)); + qDebug() << "2"; canvas->show(); + qDebug() << "3"; if (wait) QTest::qWaitForWindowShown(canvas); //It may not relayout until the next frame, so it needs to be drawn + qDebug() << "4"; return canvas; } diff --git a/tests/auto/quick/qquickshadereffect/data/deleteShaderEffectSource.qml b/tests/auto/quick/qquickshadereffect/data/deleteShaderEffectSource.qml new file mode 100644 index 0000000000..4e0eb4eb17 --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/deleteShaderEffectSource.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + color: "black" + width: 320 + height: 320 + + ShaderEffect { + id: sei + property variant source + } + + ShaderEffectSource { + id: doomed + hideSource: true + sourceItem: Image { + source: "star.png" + } + } + + function setDeletedShaderEffectSource() { + sei.source = doomed; + doomed.destroy(); + // now set a fragment shader to trigger source texture detection. + sei.fragmentShader = "varying highp vec2 qt_TexCoord0;\ + uniform sampler2D source;\ + uniform lowp float qt_Opacity;\ + void main() {\ + gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity;\ + }"; + } +} diff --git a/tests/auto/quick/qquickshadereffect/data/deleteSourceItem.qml b/tests/auto/quick/qquickshadereffect/data/deleteSourceItem.qml new file mode 100644 index 0000000000..ecf4cbd4bb --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/deleteSourceItem.qml @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + color: "black" + width: 320 + height: 320 + + ShaderEffect { + id: sei + property variant source + } + + ShaderEffectSource { + id: doomedses + hideSource: true + sourceItem: Image { + id: doomed + source: "star.png" + } + } + + function setDeletedSourceItem() { + doomed.destroy(); + sei.source = doomedses; + // now set a fragment shader to trigger source texture detection. + sei.fragmentShader = "varying highp vec2 qt_TexCoord0;\ + uniform sampler2D source;\ + uniform lowp float qt_Opacity;\ + void main() {\ + gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity;\ + }"; + } +} diff --git a/tests/auto/quick/qquickshadereffect/data/star.png b/tests/auto/quick/qquickshadereffect/data/star.png Binary files differnew file mode 100644 index 0000000000..0d592cfa87 --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/star.png diff --git a/tests/auto/quick/qquickshadereffect/qquickshadereffect.pro b/tests/auto/quick/qquickshadereffect/qquickshadereffect.pro index 142d368aed..10aa3daecb 100644 --- a/tests/auto/quick/qquickshadereffect/qquickshadereffect.pro +++ b/tests/auto/quick/qquickshadereffect/qquickshadereffect.pro @@ -2,6 +2,7 @@ CONFIG += testcase TARGET = tst_qquickshadereffect SOURCES += tst_qquickshadereffect.cpp +include (../../shared/util.pri) macx:CONFIG -= app_bundle CONFIG += parallel_test diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp index 1edf511ebf..2816fe62ea 100644 --- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp +++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp @@ -45,6 +45,10 @@ #include <QByteArray> #include <private/qquickshadereffect_p.h> +#include <QtQuick/QQuickView> +#include "../../shared/util.h" + + class TestShaderEffect : public QQuickShaderEffect { Q_OBJECT @@ -68,7 +72,7 @@ private: QList<QByteArray> m_signals; }; -class tst_qquickshadereffect : public QObject +class tst_qquickshadereffect : public QQmlDataTest { Q_OBJECT public: @@ -81,6 +85,9 @@ private slots: void lookThroughShaderCode_data(); void lookThroughShaderCode(); + void deleteSourceItem(); + void deleteShaderEffectSource(); + private: enum PresenceFlags { VertexPresent = 0x01, @@ -97,6 +104,7 @@ tst_qquickshadereffect::tst_qquickshadereffect() void tst_qquickshadereffect::initTestCase() { + QQmlDataTest::initTestCase(); } void tst_qquickshadereffect::cleanupTestCase() @@ -269,6 +277,36 @@ void tst_qquickshadereffect::lookThroughShaderCode() QCOMPARE(item.isConnected(SIGNAL(dummyChanged())), (presenceFlags & PropertyPresent) != 0); } +void tst_qquickshadereffect::deleteSourceItem() +{ + // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash + QQuickView *view = new QQuickView(0); + view->setSource(QUrl::fromLocalFile(testFile("deleteSourceItem.qml"))); + view->show(); + QTest::qWaitForWindowShown(view); + QVERIFY(view); + QObject *obj = view->rootObject(); + QVERIFY(obj); + QMetaObject::invokeMethod(obj, "setDeletedSourceItem"); + QTest::qWait(50); + delete view; +} + +void tst_qquickshadereffect::deleteShaderEffectSource() +{ + // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash + QQuickView *view = new QQuickView(0); + view->setSource(QUrl::fromLocalFile(testFile("deleteShaderEffectSource.qml"))); + view->show(); + QTest::qWaitForWindowShown(view); + QVERIFY(view); + QObject *obj = view->rootObject(); + QVERIFY(obj); + QMetaObject::invokeMethod(obj, "setDeletedShaderEffectSource"); + QTest::qWait(50); + delete view; +} + QTEST_MAIN(tst_qquickshadereffect) #include "tst_qquickshadereffect.moc" diff --git a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp index 35ce724a64..d6e5370711 100644 --- a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp +++ b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp @@ -56,7 +56,8 @@ public: enum Type { Bold = 0x01, Underline = 0x02, - Italic = 0x04 + Italic = 0x04, + Anchor = 0x08 }; Format(int t, int s, int l) : type(t), start(s), length(l) {} @@ -73,6 +74,9 @@ public: private slots: void textOutput(); void textOutput_data(); + void anchors(); + void anchors_data(); + void longString(); }; Q_DECLARE_METATYPE(tst_qquickstyledtext::FormatList); @@ -90,7 +94,13 @@ void tst_qquickstyledtext::textOutput_data() QTest::addColumn<FormatList>("formats"); QTest::addColumn<bool>("modifiesFontSize"); + QTest::newRow("empty") << "" << "" << FormatList() << false; + QTest::newRow("empty tag") << "<>test</>" << "test" << FormatList() << false; + QTest::newRow("nest opening") << "<b<b>>test</b>" << ">test" << FormatList() << false; + QTest::newRow("nest closing") << "<b>test<</b>/b>" << "test/b>" << (FormatList() << Format(Format::Bold, 0, 7)) << false; QTest::newRow("bold") << "<b>bold</b>" << "bold" << (FormatList() << Format(Format::Bold, 0, 4)) << false; + QTest::newRow("bold 2") << "<b>>>>>bold</b>" << ">>>>bold" << (FormatList() << Format(Format::Bold, 0, 8)) << false; + QTest::newRow("bold 3") << "<b>bold<>/b>" << "bold/b>" << (FormatList() << Format(Format::Bold, 0, 7)) << false; QTest::newRow("italic") << "<i>italic</i>" << "italic" << (FormatList() << Format(Format::Italic, 0, 6)) << false; QTest::newRow("underline") << "<u>underline</u>" << "underline" << (FormatList() << Format(Format::Underline, 0, 9)) << false; QTest::newRow("strong") << "<strong>strong</strong>" << "strong" << (FormatList() << Format(Format::Bold, 0, 6)) << false; @@ -111,11 +121,10 @@ void tst_qquickstyledtext::textOutput_data() QTest::newRow("extra space") << "<b >text</b>" << "text" << (FormatList() << Format(Format::Bold, 0, 4)) << false; QTest::newRow("entities") << "<b>this & that</b>" << "<b>this & that</b>" << FormatList() << false; QTest::newRow("newline") << "text<br>more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; + QTest::newRow("self-closing newline") << "text<br/>more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("paragraph") << "text<p>more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("paragraph closed") << "text<p>more text</p>more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("paragraph closed bold") << "<b>text<p>more text</p>more text</b>" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << (FormatList() << Format(Format::Bold, 0, 24)) << false; - QTest::newRow("self-closing newline") << "text<br/>more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; - QTest::newRow("empty") << "" << "" << FormatList() << false; QTest::newRow("unknown tag") << "<a href='#'><foo>underline</foo></a> not" << "underline not" << (FormatList() << Format(Format::Underline, 0, 9)) << false; QTest::newRow("ordered list") << "<ol><li>one<li>two" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false; QTest::newRow("ordered list closed") << "<ol><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; @@ -151,6 +160,7 @@ void tst_qquickstyledtext::textOutput_data() QTest::newRow("space leading bold") << "this is<b> bold</b>" << "this is bold" << (FormatList() << Format(Format::Bold, 7, 5)) << false; QTest::newRow("space trailing bold") << "this is <b>bold </b>" << "this is bold " << (FormatList() << Format(Format::Bold, 8, 5)) << false; QTest::newRow("img") << "a<img src=\"blah.png\"/>b" << "a b" << FormatList() << false; + QTest::newRow("tag mix") << "<f6>ds<b></img><pro>gfh</b><w><w>ghj</stron><ql><sl><pl>dfg</j6><img><bol><r><prp>dfg<bkj></b><up><string>ewrq</al><bl>jklhj<zl>" << "dsgfhghjdfgdfgewrqjklhj" << (FormatList() << Format(Format::Bold, 2, 3)) << false; } void tst_qquickstyledtext::textOutput() @@ -183,6 +193,60 @@ void tst_qquickstyledtext::textOutput() QCOMPARE(fontSizeModified, modifiesFontSize); } +void tst_qquickstyledtext::anchors() +{ + QFETCH(QString, input); + QFETCH(QString, output); + QFETCH(FormatList, formats); + + QTextLayout layout; + QList<QQuickStyledTextImgTag*> imgTags; + bool fontSizeModified = false; + QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); + + QCOMPARE(layout.text(), output); + + QList<QTextLayout::FormatRange> layoutFormats = layout.additionalFormats(); + + QCOMPARE(layoutFormats.count(), formats.count()); + for (int i = 0; i < formats.count(); ++i) { + QCOMPARE(layoutFormats.at(i).start, formats.at(i).start); + QCOMPARE(layoutFormats.at(i).length, formats.at(i).length); + QVERIFY(layoutFormats.at(i).format.isAnchor() == bool(formats.at(i).type & Format::Anchor)); + } +} + +void tst_qquickstyledtext::anchors_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("output"); + QTest::addColumn<FormatList>("formats"); + + QTest::newRow("empty 1") << "Test string with <a href=>url</a>." << "Test string with url." << FormatList(); + QTest::newRow("empty 2") << "Test string with <a href="">url</a>." << "Test string with url." << FormatList(); + QTest::newRow("unknown attr") << "Test string with <a hfre=\"http://strange<username>@ok-hostname\">url</a>." << "Test string with url." << FormatList(); + QTest::newRow("close") << "Test string with <a href=\"http://strange<username>@ok-hostname\"/>url." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 4)); + QTest::newRow("username") << "Test string with <a href=\"http://strange<username>@ok-hostname\">url</a>." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); + QTest::newRow("query") << "Test string with <a href=\"http://www.foo.bar?hello=world\">url</a>." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); + QTest::newRow("ipv6") << "Test string with <a href=\"//user:pass@[56::56:56:56:127.0.0.1]:99\">url</a>." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); + QTest::newRow("uni") << "Test string with <a href=\"data:text/javascript,d5%20%3D%20'five\\u0027s'%3B\">url</a>." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); + QTest::newRow("utf8") << "Test string with <a href=\"http://www.räksmörgås.se/pub?a=b&a=dø&a=f#vræl\">url</a>." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); +} + +void tst_qquickstyledtext::longString() +{ + QTextLayout layout; + QList<QQuickStyledTextImgTag*> imgTags; + bool fontSizeModified = false; + + QString input(9999999, QChar('.')); + QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); + QCOMPARE(layout.text(), input); + + input = QString(9999999, QChar('\t')); // whitespace + QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); + QCOMPARE(layout.text(), QString("")); +} QTEST_MAIN(tst_qquickstyledtext) diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 724b24280a..a31b30dc60 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -131,6 +131,9 @@ private slots: void fontFormatSizes_data(); void fontFormatSizes(); + void baselineOffset_data(); + void baselineOffset(); + private: QStringList standard; QStringList richText; @@ -1579,18 +1582,20 @@ void tst_qquicktext::implicitSize() QFETCH(QString, wrap); QFETCH(QString, elide); QString componentStr = "import QtQuick 2.0\nText { " + "property real iWidth: implicitWidth; " "text: \"" + text + "\"; " "width: " + width + "; " "textFormat: " + format + "; " "wrapMode: " + wrap + "; " "elide: " + elide + "; " - "maximumLineCount: 1 }"; + "maximumLineCount: 2 }"; QQmlComponent textComponent(&engine); textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); QVERIFY(textObject->width() < textObject->implicitWidth()); QVERIFY(textObject->height() == textObject->implicitHeight()); + QCOMPARE(textObject->property("iWidth").toReal(), textObject->implicitWidth()); textObject->resetWidth(); QVERIFY(textObject->width() == textObject->implicitWidth()); @@ -1692,7 +1697,7 @@ void tst_qquicktext::boundingRect() QCOMPARE(text->boundingRect().x(), qreal(0)); QCOMPARE(text->boundingRect().y(), qreal(0)); QCOMPARE(text->boundingRect().width(), qreal(0)); - QCOMPARE(text->boundingRect().height(), QFontMetricsF(text->font()).height()); + QCOMPARE(text->boundingRect().height(), qreal(qCeil(QFontMetricsF(text->font()).height()))); text->setText("Hello World"); @@ -2592,6 +2597,251 @@ void tst_qquicktext::fontFormatSizes() delete view; } +typedef qreal (*ExpectedBaseline)(QQuickText *item); +Q_DECLARE_METATYPE(ExpectedBaseline) + +static qreal expectedBaselineTop(QQuickText *item) +{ + QFontMetricsF fm(item->font()); + return fm.ascent(); +} + +static qreal expectedBaselineBottom(QQuickText *item) +{ + QFontMetricsF fm(item->font()); + return item->height() - item->contentHeight() + fm.ascent(); +} + +static qreal expectedBaselineCenter(QQuickText *item) +{ + QFontMetricsF fm(item->font()); + return ((item->height() - item->contentHeight()) / 2) + fm.ascent(); +} + +static qreal expectedBaselineBold(QQuickText *item) +{ + QFont font = item->font(); + font.setBold(true); + QFontMetricsF fm(font); + return fm.ascent(); +} + +static qreal expectedBaselineImage(QQuickText *item) +{ + QFontMetricsF fm(item->font()); + // The line is positioned so the bottom of the line is aligned with the bottom of the image, + // or image height - line height and the baseline is line position + ascent. Because + // QTextLine's height is rounded up this can give slightly different results to image height + // - descent. + return 181 - qCeil(fm.height()) + fm.ascent(); +} + +static qreal expectedBaselineCustom(QQuickText *item) +{ + QFontMetricsF fm(item->font()); + return 16 + fm.ascent(); +} + +static qreal expectedBaselineScaled(QQuickText *item) +{ + QFont font = item->font(); + QTextLayout layout(item->text().replace(QLatin1Char('\n'), QChar::LineSeparator)); + do { + layout.setFont(font); + qreal width = 0; + layout.beginLayout(); + for (QTextLine line = layout.createLine(); line.isValid(); line = layout.createLine()) { + line.setLineWidth(FLT_MAX); + width = qMax(line.naturalTextWidth(), width); + } + layout.endLayout(); + + if (width < item->width()) { + QFontMetricsF fm(layout.font()); + return fm.ascent(); + } + font.setPointSize(font.pointSize() - 1); + } while (font.pointSize() > 0); + return 0; +} + +static qreal expectedBaselineFixedBottom(QQuickText *item) +{ + QFontMetricsF fm(item->font()); + qreal dy = item->text().contains(QLatin1Char('\n')) + ? 160 + : 180; + return dy + fm.ascent(); +} + +static qreal expectedBaselineProportionalBottom(QQuickText *item) +{ + QFontMetricsF fm(item->font()); + qreal dy = item->text().contains(QLatin1Char('\n')) + ? 200 - (qCeil(fm.height()) * 3) + : 200 - (qCeil(fm.height()) * 1.5); + return dy + fm.ascent(); +} + +void tst_qquicktext::baselineOffset_data() +{ + qRegisterMetaType<ExpectedBaseline>(); + QTest::addColumn<QString>("text"); + QTest::addColumn<QString>("wrappedText"); + QTest::addColumn<QByteArray>("bindings"); + QTest::addColumn<ExpectedBaseline>("expectedBaseline"); + QTest::addColumn<ExpectedBaseline>("expectedBaselineEmpty"); + + QTest::newRow("top align") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; verticalAlignment: Text.AlignTop") + << &expectedBaselineTop + << &expectedBaselineTop; + QTest::newRow("bottom align") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; verticalAlignment: Text.AlignBottom") + << &expectedBaselineBottom + << &expectedBaselineBottom; + QTest::newRow("center align") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter") + << &expectedBaselineCenter + << &expectedBaselineCenter; + + QTest::newRow("bold") + << "<b>hello world</b>" + << "<b>hello<br/>world</b>" + << QByteArray("height: 200") + << &expectedBaselineTop + << &expectedBaselineBold; + + QTest::newRow("richText") + << "<b>hello world</b>" + << "<b>hello<br/>world</b>" + << QByteArray("height: 200; textFormat: Text.RichText") + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("elided") + << "hello world" + << "hello\nworld" + << QByteArray("width: 20; height: 8; elide: Text.ElideRight") + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("elided bottom align") + << "hello world" + << "hello\nworld!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + << QByteArray("width: 200; height: 200; elide: Text.ElideRight; verticalAlignment: Text.AlignBottom") + << &expectedBaselineBottom + << &expectedBaselineBottom; + + QTest::newRow("image") + << "hello <img src=\"images/heart200.png\" /> world" + << "hello <img src=\"images/heart200.png\" /><br/>world" + << QByteArray("height: 200\n; baseUrl: \"") + testFileUrl("reference").toEncoded() + QByteArray("\"") + << &expectedBaselineImage + << &expectedBaselineTop; + + QTest::newRow("customLine") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; onLineLaidOut: line.y += 16") + << &expectedBaselineCustom + << &expectedBaselineCustom; + + QTest::newRow("scaled font") + << "hello world" + << "hello\nworld" + << QByteArray("width: 200; minimumPointSize: 1; font.pointSize: 64; fontSizeMode: Text.HorizontalFit") + << &expectedBaselineScaled + << &expectedBaselineTop; + + QTest::newRow("fixed line height top align") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignTop") + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("fixed line height bottom align") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignBottom") + << &expectedBaselineFixedBottom + << &expectedBaselineFixedBottom; + + QTest::newRow("proportional line height top align") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignTop") + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("proportional line height bottom align") + << "hello world" + << "hello\nworld" + << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignBottom") + << &expectedBaselineProportionalBottom + << &expectedBaselineProportionalBottom; +} + +void tst_qquicktext::baselineOffset() +{ + QFETCH(QString, text); + QFETCH(QString, wrappedText); + QFETCH(QByteArray, bindings); + QFETCH(ExpectedBaseline, expectedBaseline); + QFETCH(ExpectedBaseline, expectedBaselineEmpty); + + QQmlComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Text {\n" + + bindings + "\n" + "}", QUrl()); + + QScopedPointer<QObject> object(component.create()); + + QQuickText *item = qobject_cast<QQuickText *>(object.data()); + QVERIFY(item); + + { + qreal baseline = expectedBaselineEmpty(item); + + QCOMPARE(item->baselineOffset(), baseline); + + item->setText(text); + if (expectedBaseline != expectedBaselineEmpty) + baseline = expectedBaseline(item); + + QCOMPARE(item->baselineOffset(), baseline); + + item->setText(wrappedText); + QCOMPARE(item->baselineOffset(), expectedBaseline(item)); + } + + QFont font = item->font(); + font.setPointSize(font.pointSize() + 8); + + { + QCOMPARE(item->baselineOffset(), expectedBaseline(item)); + + item->setText(text); + qreal baseline = expectedBaseline(item); + QCOMPARE(item->baselineOffset(), baseline); + + item->setText(QString()); + if (expectedBaselineEmpty != expectedBaseline) + baseline = expectedBaselineEmpty(item); + + QCOMPARE(item->baselineOffset(), baseline); + } +} + QTEST_MAIN(tst_qquicktext) #include "tst_qquicktext.moc" diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index dd9aa0acad..7113141800 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -2379,6 +2379,11 @@ void tst_qquicktextedit::inputMethodUpdate() QVERIFY(edit->selectionStart() != edit->selectionEnd()); QVERIFY(platformInputContext.m_updateCallCount > 0); + // programmatical selections trigger update + platformInputContext.clear(); + edit->selectAll(); + QCOMPARE(platformInputContext.m_updateCallCount, 1); + // font changes platformInputContext.clear(); QFont font = edit->font(); diff --git a/tools/easingcurveeditor/mainwindow.cpp b/tools/easingcurveeditor/mainwindow.cpp index 569b74ae29..3bd5b3e88f 100644 --- a/tools/easingcurveeditor/mainwindow.cpp +++ b/tools/easingcurveeditor/mainwindow.cpp @@ -104,7 +104,7 @@ MainWindow::MainWindow(QWidget *parent) : void MainWindow::showQuickView() { const int margin = 16; - quickView.move(pos() + QPoint(0, frameGeometry().height() + margin)); + quickView.setPos(pos() + QPoint(0, frameGeometry().height() + margin)); quickView.raise(); quickView.show(); |