Merge branch 'buildsystem'
authorOswald Buddenhagen <oswald.buddenhagen@nokia.com>
Tue, 26 Jun 2012 15:59:46 +0000 (17:59 +0200)
committerOswald Buddenhagen <oswald.buddenhagen@nokia.com>
Tue, 26 Jun 2012 15:59:46 +0000 (17:59 +0200)
Change-Id: I230e776290761be7c811c3aec4d915367012fc99

68 files changed:
doc/config/qtdeclarative_doc.pri
examples/demos/rssnews/rssnews.qml
examples/particles/emitters/customemitter.qml
src/particles/qquickparticleemitter.cpp
src/particles/qquicktrailemitter.cpp
src/qml/doc/qtqml.qdocconf
src/qml/doc/src/cppintegration/registercpptypes.qdoc
src/qml/doc/src/typesystem/basictypes.qdoc
src/qml/qml.pro
src/qml/qml/ftw/qpodvector_p.h
src/qml/qml/qqml.h
src/qml/qml/qqmlcompiler.cpp
src/qml/qml/qqmlfile.cpp
src/qml/qml/qqmlproperty.cpp
src/qml/qml/qqmlpropertycache.cpp
src/qml/qml/qquicklistmodel.cpp
src/qml/qml/v4/qv4bindings.cpp
src/quick/doc/qtquick.qdocconf
src/quick/doc/src/concepts/effects-particles.qdoc
src/quick/items/qquickborderimage.cpp
src/quick/items/qquickcanvas.cpp
src/quick/items/qquickcanvas_p.h
src/quick/items/qquickdrag.cpp
src/quick/items/qquickdrag_p.h
src/quick/items/qquickdroparea.cpp
src/quick/items/qquickdroparea_p.h
src/quick/items/qquickimagebase.cpp
src/quick/items/qquickitem.cpp
src/quick/items/qquickitem.h
src/quick/items/qquickitem_p.h
src/quick/items/qquickitemsmodule.cpp
src/quick/items/qquicklistview.cpp
src/quick/items/qquicklistview_p.h
src/quick/items/qquickmousearea.cpp
src/quick/items/qquickmousearea_p.h
src/quick/items/qquickmousearea_p_p.h
src/quick/items/qquicktext.cpp
src/quick/items/qquicktext_p_p.h
src/quick/items/qquicktextinput.cpp
src/quick/items/qquicktextutil.cpp
src/quick/items/qquicktextutil_p.h
src/quick/quick.pro
tests/auto/qml/qml.pro
tests/auto/qml/qqmllanguage/testtypes.cpp
tests/auto/qml/qqmllanguage/testtypes.h
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
tests/auto/qml/qquicklistmodel/tst_qquicklistmodel.cpp
tests/auto/qml/qrcqml/tst_qrcqml.cpp
tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
tests/auto/quick/qquicklistview/data/displaylist.qml
tests/auto/quick/qquicklistview/data/flickBeyondBoundsBug.qml
tests/auto/quick/qquicklistview/data/listview-initCurrent.qml
tests/auto/quick/qquicklistview/data/listview-noCurrent.qml
tests/auto/quick/qquicklistview/data/listviewtest-package.qml
tests/auto/quick/qquicklistview/data/listviewtest.qml
tests/auto/quick/qquicklistview/data/sectiondelegatechange.qml [new file with mode: 0644]
tests/auto/quick/qquicklistview/data/sectionpropertychange.qml
tests/auto/quick/qquicklistview/qquicklistview.pro
tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
tests/auto/quick/qquickloader/data/subdir/Test.qml [new file with mode: 0644]
tests/auto/quick/qquickloader/tst_qquickloader.cpp
tests/auto/quick/qquicktext/tst_qquicktext.cpp
tests/auto/quick/qquicktextinput/data/horizontalAlignment_RightToLeft.qml
tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
tools/qmlscene/main.cpp

index c2cf908..411e50c 100644 (file)
@@ -15,11 +15,11 @@ $$unixstyle {
     DITA_DOCS = $$replace(ONLINE_CONF, "/", "\\")
 }
 
-online_docs.commands = $$QDOC $$ONLINE_CONF
-dita_docs.commands = $$QDOC $$DITA_CONF
+qtquick_online_docs.commands = $$QDOC $$ONLINE_CONF
+qtquick_dita_docs.commands = $$QDOC $$DITA_CONF
 
-docs.depends = dita_docs online_docs
-QMAKE_EXTRA_TARGETS = docs dita_docs online_docs
+qtquick_docs.depends = qtquick_dita_docs qtquick_online_docs
+QMAKE_EXTRA_TARGETS = qtquick_docs qtquick_dita_docs qtquick_online_docs
 QMAKE_CLEAN += \
                "-r $$PWD/html" \
                "-r $$PWD/ditaxml"
index 706eac2..56960a5 100644 (file)
@@ -75,7 +75,7 @@ Rectangle {
                 footer: quitButtonDelegate
                 delegate: CategoryDelegate {}
                 highlight: Rectangle { color: "steelblue" }
-                highlightMoveDuration: 50
+                highlightMoveVelocity: 9999999
             }
             ScrollBar {
                 scrollArea: categories; height: categories.height; width: 8
index 757c836..135b3d7 100644 (file)
@@ -72,7 +72,11 @@ ParticleSystem {
             for (var i=0; i<particles.length; i++) {
                 var particle = particles[i];
                 particle.startSize = Math.max(02,Math.min(492,Math.tan(particle.t/2)*24));
-                var theta = Math.floor(Math.random() * 6.0) / 6.0;
+                var theta = Math.floor(Math.random() * 6.0);
+                particle.red = theta == 0 || theta == 1 || theta == 2 ? 0.2 : 1;
+                particle.green = theta == 2 || theta == 3 || theta == 4 ? 0.2 : 1;
+                particle.blue = theta == 4 || theta == 5 || theta == 0 ? 0.2 : 1;
+                theta /= 6.0;
                 theta *= 2.0*Math.PI;
                 theta += sys.convert(sys.petalRotation);
                 particle.initialVX = petalLength * Math.cos(theta);
@@ -86,7 +90,5 @@ ParticleSystem {
     ImageParticle {
         source: "../images/particle4.png"
         alpha: 0.0
-        redVariation: 0.6
-        color: "white"
     }
 }
index 6e53b09..7db1707 100644 (file)
@@ -472,7 +472,12 @@ void QQuickParticleEmitter::emitWindow(int timeStamp)
         }
     }
 
+    foreach (QQuickParticleData* d, toEmit)
+            m_system->emitParticle(d);
+
     if (isEmitConnected()) {
+        //Done after emitParticle so that the Painter::load is done first, this allows you to customize its static variables
+        //We then don't need to request another reload, because the first reload isn't scheduled until we get back to the render thread
         v8::HandleScope handle_scope;
         v8::Context::Scope scope(QQmlEnginePrivate::getV8Engine(qmlEngine(this))->context());
         v8::Handle<v8::Array> array = v8::Array::New(toEmit.size());
@@ -481,8 +486,6 @@ void QQuickParticleEmitter::emitWindow(int timeStamp)
 
         emitParticles(QQmlV8Handle::fromHandle(array));//A chance for arbitrary JS changes
     }
-    foreach (QQuickParticleData* d, toEmit)
-            m_system->emitParticle(d);
 
     m_last_emission = pt;
 
index 68b43a0..5f09410 100644 (file)
@@ -118,7 +118,7 @@ QQuickTrailEmitter::QQuickTrailEmitter(QQuickItem *parent) :
     \qmlproperty real QtQuick.Particles2::TrailEmitter::emitRatePerParticle
 */
 /*!
-    \qmlsignal QtQuick.Particles2::TrailEmitter::emitFollowParticles(Array particles, real followed)
+    \qmlsignal QtQuick.Particles2::TrailEmitter::emitFollowParticles(Array particles, QtQuick.Particles2::Particle followed)
 
     This handler is called when particles are emitted from the \a followed particle. \a particles contains an array of particle objects which can be directly manipulated.
 
@@ -264,6 +264,9 @@ void QQuickTrailEmitter::emitWindow(int timeStamp)
             }
         }
 
+        foreach (QQuickParticleData* d, toEmit)
+            m_system->emitParticle(d);
+
         if (isEmitConnected() || isEmitFollowConnected()) {
             v8::HandleScope handle_scope;
             v8::Context::Scope scope(QQmlEnginePrivate::getV8Engine(qmlEngine(this))->context());
@@ -276,8 +279,6 @@ void QQuickTrailEmitter::emitWindow(int timeStamp)
             else if (isEmitConnected())
                 emitParticles(QQmlV8Handle::fromHandle(array));//A chance for arbitrary JS changes
         }
-        foreach (QQuickParticleData* d, toEmit)
-            m_system->emitParticle(d);
         m_lastEmission[d->index] = pt;
     }
 
index 80f7cef..7cc65b7 100644 (file)
@@ -1,3 +1,6 @@
+include(global/qt-html-templates-offline.qdocconf)
+include(global/qt-cpp-ignore.qdocconf)
+
 project                 = QtQml
 description             = Qt QML Reference Documentation
 url                     = http://qt-project.org/doc/qt-5.0/qtqml
@@ -8,7 +11,7 @@ outputencoding          = UTF-8
 naturallanguage         = en_US
 qhp.projects            = QtCore
 
-depends += qtcore qtjsbackend qtxmlpatterns qtquick
+depends += qtcore qtxmlpatterns
 
 qhp.QtQml.file                = qtqml.qhp
 qhp.QtQml.namespace           = org.qt-project.qtqml.500
@@ -52,7 +55,7 @@ HTML.nobreadcrumbs      = "true"
 
 HTML.templatedir = .
 
-HTML.stylesheets = ../../../doc/global/style/offline.css
+HTML.stylesheets = global/style/offline.css
 
 HTML.headerstyles = \
     "  <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n"
index 9ccf428..0e11883 100644 (file)
@@ -265,6 +265,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
     \code
     template<typename T, int metaObjectRevision>
     int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
+
+    template<typename T, int metaObjectRevision>
+    int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
     \endcode
 
     For example, if \c BaseObject is changed and now has a revision 1, you can specify that
index 3c1b849..c24787b 100644 (file)
@@ -167,6 +167,21 @@ See \l {QML Basic Types} for the list of basic types that are supported by the Q
     Usually you will only have to do this once, because relative URLs resolved from
     that file will use the same protocol.
 
+    URLs may contain encoded characters using the 'percent-encoding' scheme
+    specified by \l {http://tools.ietf.org/html/rfc3986}{RFC 3986}.  These characters
+    will be preserved within properties of type \c url, to allow QML code to
+    construct precise URL values. An exception to this rule is the preemptive
+    decoding of directory-separator characters (\c '/') - these characters are decoded
+    to allow the URL to be correctly classified.
+
+    For example, a local file containing a '#' character, which would normally be
+    interpreted as the beginning of the URL 'fragment' element, can be accessed by
+    encoding the characters of the file name:
+
+    \qml
+    Image { source: encodeURIComponent("/tmp/test#1.png") }
+    \endqml
+
     \sa {QML Basic Types}
 */
 
index 311ee3c..5c16502 100644 (file)
@@ -17,6 +17,8 @@ exists("qqml_enable_gcov") {
 MODULE_DEFINES = QQmlImageProvider=QQuickImageProvider
 load(qt_module_config)
 
+QMAKE_DOCS = $$PWD/doc/qtqml.qdocconf
+
 # private dependencies
 QT += v8-private
 
index c966926..d7f51b4 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
-template<class T, int Increment=1024>
-class QPODVector 
+template<class T, int Increment>
+class QPODVector
 {
 public:
     QPODVector()
     : m_count(0), m_capacity(0), m_data(0) {}
-    ~QPODVector() { if (m_data) ::free(m_data); } 
+    ~QPODVector() { if (m_data) ::free(m_data); }
 
     const T &at(int idx) const {
         return m_data[idx];
@@ -109,8 +109,8 @@ public:
         int newSize = m_count + count;
         reserve(newSize);
         int moveCount = m_count - idx;
-        if (moveCount) 
-            ::memmove(m_data + idx + count,  m_data + idx, 
+        if (moveCount)
+            ::memmove(m_data + idx + count,  m_data + idx,
                       moveCount * sizeof(T));
         m_count = newSize;
     }
@@ -118,7 +118,7 @@ public:
     void remove(int idx, int count = 1) {
         int moveCount = m_count - (idx + count);
         if (moveCount)
-            ::memmove(m_data + idx, m_data + idx + count, 
+            ::memmove(m_data + idx, m_data + idx + count,
                       moveCount * sizeof(T));
         m_count -= count;
     }
index c7092a6..528f8e6 100644 (file)
@@ -167,6 +167,37 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
     return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
 }
 
+template<typename T, int metaObjectRevision>
+int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+{
+    QML_GETTYPENAMES
+
+    QQmlPrivate::RegisterType type = {
+        1,
+
+        qRegisterNormalizedMetaType<T *>(pointerName.constData()),
+        qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+        0, 0,
+        reason,
+
+        uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+        QQmlPrivate::attachedPropertiesFunc<T>(),
+        QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+        QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+        QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+        QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+        0, 0,
+
+        0,
+        metaObjectRevision
+    };
+
+    return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
 template<typename T>
 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
 {
index 2bb99dd..13ff9e8 100644 (file)
@@ -515,6 +515,8 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
             {
             Instruction::StoreUrl instr;
             QString string = v->value.asString();
+            // Encoded dir-separators defeat QUrl processing - decode them first
+            string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
             QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
             instr.propertyIndex = prop->index;
             instr.value = output->indexForUrl(u);
index b0da80f..df876b6 100644 (file)
@@ -51,7 +51,7 @@
 \class QQmlFile
 \brief The QQmlFile class gives access to local and remote files.
 
-Supports file://, qrc://, bundle:// uris and whatever QNetworkAccessManager supports.
+Supports file://, qrc:/, bundle:// uris and whatever QNetworkAccessManager supports.
 */
 
 #define QQMLFILE_MAX_REDIRECT_RECURSION 16
@@ -481,7 +481,7 @@ bool QQmlFile::connectDownloadProgress(QObject *object, int method)
 /*!
 Returns true if QQmlFile will open \a url synchronously.
 
-Synchronous urls have a qrc://, file://, or bundle:// scheme.
+Synchronous urls have a qrc:/, file://, or bundle:// scheme.
 */
 bool QQmlFile::isSynchronous(const QUrl &url)
 {
@@ -498,11 +498,11 @@ bool QQmlFile::isSynchronous(const QUrl &url)
 /*!
 Returns true if QQmlFile will open \a url synchronously.
 
-Synchronous urls have a qrc://, file://, or bundle:// scheme.
+Synchronous urls have a qrc:/, file://, or bundle:// scheme.
 */
 bool QQmlFile::isSynchronous(const QString &url)
 {
-    if (url.length() < 6 /* qrc:// */)
+    if (url.length() < 5 /* qrc:/ */)
         return false;
 
     QChar f = url[0];
@@ -521,9 +521,9 @@ bool QQmlFile::isSynchronous(const QString &url)
 
     } else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
 
-        return url.length() >= 6 /* bundle:// */ &&
+        return url.length() >= 5 /* qrc:/ */ &&
                url.startsWith(qrc_string, Qt::CaseInsensitive) &&
-               url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/') && url[5] == QLatin1Char('/');
+               url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
 
     }
 
@@ -556,7 +556,7 @@ bool QQmlFile::isBundle(const QUrl &url)
 /*!
 Returns true if \a url is a local file that can be opened with QFile.
 
-Local file urls have either a qrc:// or file:// scheme.
+Local file urls have either a qrc:/ or file:// scheme.
 */
 bool QQmlFile::isLocalFile(const QUrl &url)
 {
@@ -572,11 +572,11 @@ bool QQmlFile::isLocalFile(const QUrl &url)
 /*!
 Returns true if \a url is a local file that can be opened with QFile.
 
-Local file urls have either a qrc:// or file:// scheme.
+Local file urls have either a qrc:/ or file:// scheme.
 */
 bool QQmlFile::isLocalFile(const QString &url)
 {
-    if (url.length() < 6 /* qrc:// */)
+    if (url.length() < 5 /* qrc:/ */)
         return false;
 
     QChar f = url[0];
@@ -589,9 +589,9 @@ bool QQmlFile::isLocalFile(const QString &url)
 
     } else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
 
-        return url.length() >= 6 /* bundle:// */ &&
+        return url.length() >= 5 /* qrc:/ */ &&
                url.startsWith(qrc_string, Qt::CaseInsensitive) &&
-               url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/') && url[5] == QLatin1Char('/');
+               url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
 
     }
 
index 33f860f..d0c2761 100644 (file)
@@ -1319,10 +1319,16 @@ bool QQmlPropertyPrivate::write(QObject *object,
             u = value.toUrl();
             found = true;
         } else if (variantType == QVariant::ByteArray) {
-            u = QUrl(QString::fromUtf8(value.toByteArray()));
+            QString input(QString::fromUtf8(value.toByteArray()));
+            // Encoded dir-separators defeat QUrl processing - decode them first
+            input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+            u = QUrl(input);
             found = true;
         } else if (variantType == QVariant::String) {
-            u = QUrl(value.toString());
+            QString input(value.toString());
+            // Encoded dir-separators defeat QUrl processing - decode them first
+            input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+            u = QUrl(input);
             found = true;
         }
 
index 87e707d..d922b99 100644 (file)
@@ -210,7 +210,8 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
     propType = QMetaType::Void;
 
     const char *returnType = m.typeName();
-    Q_ASSERT(returnType != 0);
+    if (!returnType)
+        returnType = "\0";
     if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
         propTypeName = returnType;
         flags |= NotFullyResolved;
index 52ef2ab..03f9e3a 100644 (file)
@@ -2327,6 +2327,8 @@ void QQuickListModelParser::setCustomData(QObject *obj, const QByteArray &d)
     const ListModelData *lmd = (const ListModelData *)d.constData();
     const char *data = ((const char *)lmd) + lmd->dataOffset;
 
+    bool setRoles = false;
+
     QStack<DataStackElement> stack;
 
     for (int ii = 0; ii < lmd->instrCount; ++ii) {
@@ -2398,6 +2400,7 @@ void QQuickListModelParser::setCustomData(QObject *obj, const QByteArray &d)
                 }
 
                 e1.model->setOrCreateProperty(e1.elementIndex, name, value);
+                setRoles = true;
             }
             break;
 
@@ -2410,6 +2413,9 @@ void QQuickListModelParser::setCustomData(QObject *obj, const QByteArray &d)
             break;
         }
     }
+
+    if (setRoles == false)
+        qmlInfo(obj) << "All ListElement declarations are empty, no roles can be created unless dynamicRoles is set.";
 }
 
 bool QQuickListModelParser::definesEmptyList(const QString &s)
index ff16f3b..7d42b47 100644 (file)
@@ -1296,7 +1296,9 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
         if (src.isUndefined()) {
             output.setUndefined();
         } else {
-            const QString tmp(*src.getstringptr());
+            QString tmp(*src.getstringptr());
+            // Encoded dir-separators defeat QUrl processing - decode them first
+            tmp.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
             if (instr->unaryop.src == instr->unaryop.output) {
                 output.cleanupString();
                 MARK_CLEAN_REGISTER(instr->unaryop.output);
@@ -1326,7 +1328,7 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
             COLOR_REGISTER(instr->unaryop.output);
         }
     }
-    QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
+    QML_V4_END_INSTR(ConvertStringToColor, unaryop)
 
     QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop)
     {
index 4236278..9aa056e 100644 (file)
@@ -1,9 +1,12 @@
+include(global/qt-html-templates-offline.qdocconf)
+include(global/qt-cpp-ignore.qdocconf)
+
 project                 = QtQuick
 description             = Qt Quick Reference Documentation
 url                     = http://qt-project.org/doc/qt-5.0/qtquick
 version                 = 5.0.0
 
-depends += qtqcore qtxmlpatterns qtjsbackend qtqml
+depends += qtqcore qtxmlpatterns qtqml
 
 sourceencoding          = UTF-8
 outputencoding          = UTF-8
@@ -52,7 +55,7 @@ HTML.nobreadcrumbs      = "true"
 
 HTML.templatedir = .
 
-HTML.stylesheets = ../../../doc/global/style/offline.css
+HTML.stylesheets = global/style/offline.css
 
 HTML.headerstyles = \
     "  <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n"
index 8d77c26..9fbe85c 100644 (file)
@@ -47,6 +47,7 @@
     \inqmlmodule QtQuick.Particles 2.0
     \title Using the Qt Quick Particle System
 
+    Documentation for all Particle System elements can be found on the \l{QML Module QtQuick.Particles 2}{QtQuick.Particles} module page.
 
   Note that to use elements from the particles module, you will need to import the types with the following line:
   \code
index 5d4ce7f..abd20c6 100644 (file)
@@ -274,8 +274,8 @@ QQuickBorderImage::~QQuickBorderImage()
 void QQuickBorderImage::setSource(const QUrl &url)
 {
     Q_D(QQuickBorderImage);
-    //equality is fairly expensive, so we bypass for simple, common case
-    if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
+
+    if (url == d->url)
         return;
 
     if (d->sciReply) {
@@ -305,6 +305,7 @@ void QQuickBorderImage::load()
         setImplicitSize(0, 0);
         emit statusChanged(d->status);
         update();
+        return;
     } else {
         d->status = Loading;
         if (d->url.path().endsWith(QLatin1String("sci"))) {
@@ -347,6 +348,7 @@ void QQuickBorderImage::load()
                 emit statusChanged(d->status);
                 emit progressChanged(d->progress);
                 update();
+                return;
             }
         }
     }
index 82fabd0..7c59a9d 100644 (file)
@@ -1062,12 +1062,14 @@ bool QQuickCanvas::event(QEvent *e)
         d->clearHover();
         d->lastMousePosition = QPoint();
         break;
+#ifndef QT_NO_DRAGANDDROP
     case QEvent::DragEnter:
     case QEvent::DragLeave:
     case QEvent::DragMove:
     case QEvent::Drop:
         d->deliverDragEvent(&d->dragGrabber, e);
         break;
+#endif
     case QEvent::WindowDeactivate:
         rootItem()->windowDeactivateEvent();
         break;
@@ -1578,6 +1580,7 @@ bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
     return false;
 }
 
+#ifndef QT_NO_DRAGANDDROP
 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
 {
     Q_Q(QQuickCanvas);
@@ -1697,6 +1700,7 @@ bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
 
     return accepted;
 }
+#endif // QT_NO_DRAGANDDROP
 
 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
 {
@@ -1792,12 +1796,14 @@ bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
             QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
         }
         break;
+#ifndef QT_NO_DRAGANDDROP
     case QEvent::DragEnter:
     case QEvent::DragMove:
     case QEvent::DragLeave:
     case QEvent::Drop:
         QQuickItemPrivate::get(item)->deliverDragEvent(e);
         break;
+#endif
     default:
         break;
     }
index 29c0d51..e08c342 100644 (file)
@@ -68,7 +68,6 @@
 #include <qopenglcontext.h>
 #include <QtGui/qopenglframebufferobject.h>
 #include <QtGui/qevent.h>
-#include <QtGui/qinputpanel.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -112,7 +111,9 @@ public:
 
     QQuickItem *activeFocusItem;
     QQuickItem *mouseGrabberItem;
+#ifndef QT_NO_DRAGANDDROP
     QQuickDragGrabber dragGrabber;
+#endif
     int touchMouseId;
     ulong touchMousePressTimestamp;
 
@@ -132,8 +133,10 @@ public:
     bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos,
                         Qt::KeyboardModifiers modifiers, bool accepted);
     bool clearHover();
+#ifndef QT_NO_DRAGANDDROP
     void deliverDragEvent(QQuickDragGrabber *, QEvent *);
     bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *);
+#endif
 
     QList<QQuickItem*> hoverItems;
     enum FocusOption {
index 2357e3a..80dbf2b 100644 (file)
@@ -49,6 +49,8 @@
 #include <QtQml/qqmlinfo.h>
 #include <QtGui/qevent.h>
 
+#ifndef QT_NO_DRAGANDDROP
+
 QT_BEGIN_NAMESPACE
 
 class QQuickDragAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
@@ -614,3 +616,5 @@ void QQuickDragAttached::cancel()
 }
 
 QT_END_NAMESPACE
+
+#endif // QT_NO_DRAGANDDROP
index 7209469..4ed98fa 100644 (file)
@@ -49,6 +49,7 @@
 #include <QtCore/qmimedata.h>
 #include <QtCore/qstringlist.h>
 
+#ifndef QT_NO_DRAGANDDROP
 
 QT_BEGIN_HEADER
 
@@ -206,4 +207,6 @@ QT_END_NAMESPACE
 
 QT_END_HEADER
 
+#endif // QT_NO_DRAGANDDROP
+
 #endif
index 6c178c5..1f5d98c 100644 (file)
@@ -46,6 +46,8 @@
 
 #include <private/qqmlengine_p.h>
 
+#ifndef QT_NO_DRAGANDDROP
+
 QT_BEGIN_NAMESPACE
 
 QQuickDropAreaDrag::QQuickDropAreaDrag(QQuickDropAreaPrivate *d, QObject *parent)
@@ -429,3 +431,4 @@ void QQuickDropEvent::accept(QQmlV8Function *args)
 
 QT_END_NAMESPACE
 
+#endif // QT_NO_DRAGANDDROP
index e207787..082c3da 100644 (file)
@@ -49,6 +49,8 @@
 
 #include <QtGui/qevent.h>
 
+#ifndef QT_NO_DRAGANDDROP
+
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
@@ -162,4 +164,6 @@ QML_DECLARE_TYPE(QQuickDropArea)
 
 QT_END_HEADER
 
+#endif // QT_NO_DRAGANDDROP
+
 #endif // QQUICKDROPAREA_P_H
index 0bdfab6..735910e 100644 (file)
@@ -100,8 +100,8 @@ QUrl QQuickImageBase::source() const
 void QQuickImageBase::setSource(const QUrl &url)
 {
     Q_D(QQuickImageBase);
-    //equality is fairly expensive, so we bypass for simple, common case
-    if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
+
+    if (url == d->url)
         return;
 
     d->url = url;
index 00e0182..ab942f6 100644 (file)
@@ -3254,6 +3254,7 @@ void QQuickItem::hoverLeaveEvent(QHoverEvent *event)
     Q_UNUSED(event);
 }
 
+#ifndef QT_NO_DRAGANDDROP
 void QQuickItem::dragEnterEvent(QDragEnterEvent *event)
 {
     Q_UNUSED(event);
@@ -3275,6 +3276,7 @@ void QQuickItem::dropEvent(QDropEvent *event)
 {
     Q_UNUSED(event);
 }
+#endif // QT_NO_DRAGANDDROP
 
 bool QQuickItem::childMouseEventFilter(QQuickItem *, QEvent *)
 {
@@ -3860,6 +3862,7 @@ void QQuickItemPrivate::deliverHoverEvent(QHoverEvent *e)
     }
 }
 
+#ifndef QT_NO_DRAGANDDROP
 void QQuickItemPrivate::deliverDragEvent(QEvent *e)
 {
     Q_Q(QQuickItem);
@@ -3880,6 +3883,7 @@ void QQuickItemPrivate::deliverDragEvent(QEvent *e)
         break;
     }
 }
+#endif // QT_NO_DRAGANDDROP
 
 void QQuickItem::itemChange(ItemChange change, const ItemChangeData &value)
 {
index 69122bd..c0fd01f 100644 (file)
@@ -384,10 +384,12 @@ protected:
     virtual void hoverEnterEvent(QHoverEvent *event);
     virtual void hoverMoveEvent(QHoverEvent *event);
     virtual void hoverLeaveEvent(QHoverEvent *event);
+#ifndef QT_NO_DRAGANDDROP
     virtual void dragEnterEvent(QDragEnterEvent *);
     virtual void dragMoveEvent(QDragMoveEvent *);
     virtual void dragLeaveEvent(QDragLeaveEvent *);
     virtual void dropEvent(QDropEvent *);
+#endif
     virtual bool childMouseEventFilter(QQuickItem *, QEvent *);
     virtual void windowDeactivateEvent();
 
index bbff260..0b4b2bd 100644 (file)
@@ -532,7 +532,9 @@ public:
     void deliverWheelEvent(QWheelEvent *);
     void deliverTouchEvent(QTouchEvent *);
     void deliverHoverEvent(QHoverEvent *);
+#ifndef QT_NO_DRAGANDDROP
     void deliverDragEvent(QEvent *);
+#endif
 
     bool calcEffectiveVisible() const;
     bool setEffectiveVisibleRecur(bool);
index bb13055..380354c 100644 (file)
@@ -214,10 +214,12 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
     qmlRegisterType<QQuickPathAnimation>("QtQuick",2,0,"PathAnimation");
     qmlRegisterType<QQuickPathInterpolator>("QtQuick",2,0,"PathInterpolator");
 
+#ifndef QT_NO_DRAGANDDROP
     qmlRegisterType<QQuickDropArea>("QtQuick", 2, 0, "DropArea");
     qmlRegisterType<QQuickDropEvent>();
     qmlRegisterType<QQuickDropAreaDrag>();
     qmlRegisterUncreatableType<QQuickDrag>("QtQuick", 2, 0, "Drag", QQuickDragAttached::tr("Drag is only available via attached properties"));
+#endif
 
     qmlRegisterType<QQuickMultiPointTouchArea>("QtQuick", 2, 0, "MultiPointTouchArea");
     qmlRegisterType<QQuickTouchPoint>("QtQuick", 2, 0, "TouchPoint");
index d42d1cb..f12da43 100644 (file)
@@ -113,6 +113,7 @@ public:
     virtual void updateSections();
     QQuickItem *getSectionItem(const QString &section);
     void releaseSectionItem(QQuickItem *item);
+    void releaseSectionItems();
     void updateInlineSection(FxListItemSG *);
     void updateCurrentSection();
     void updateStickySections();
@@ -143,6 +144,8 @@ public:
 
     QSmoothedAnimation *highlightPosAnimator;
     QSmoothedAnimation *highlightSizeAnimator;
+    qreal highlightMoveVelocity;
+    qreal highlightResizeVelocity;
     int highlightResizeDuration;
 
     QQuickViewSection *sectionCriteria;
@@ -166,7 +169,7 @@ public:
         , averageSize(100.0), spacing(0.0)
         , snapMode(QQuickListView::NoSnap)
         , highlightPosAnimator(0), highlightSizeAnimator(0)
-        , highlightResizeDuration(250)
+        , highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
         , sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
         , overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
     {}
@@ -207,6 +210,8 @@ void QQuickViewSection::setCriteria(QQuickViewSection::SectionCriteria criteria)
 void QQuickViewSection::setDelegate(QQmlComponent *delegate)
 {
     if (delegate != m_delegate) {
+        if (m_delegate)
+            m_view->releaseSectionItems();
         m_delegate = delegate;
         emit delegateChanged();
         m_view->updateSections();
@@ -873,10 +878,12 @@ void QQuickListViewPrivate::createHighlight()
             const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
             highlightPosAnimator = new QSmoothedAnimation;
             highlightPosAnimator->target = QQmlProperty(item, posProp);
+            highlightPosAnimator->velocity = highlightMoveVelocity;
             highlightPosAnimator->userDuration = highlightMoveDuration;
 
             const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
             highlightSizeAnimator = new QSmoothedAnimation;
+            highlightSizeAnimator->velocity = highlightResizeVelocity;
             highlightSizeAnimator->userDuration = highlightResizeDuration;
             highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
 
@@ -976,6 +983,24 @@ void QQuickListViewPrivate::releaseSectionItem(QQuickItem *item)
     delete item;
 }
 
+
+void QQuickListViewPrivate::releaseSectionItems()
+{
+    for (int i = 0; i < visibleItems.count(); ++i) {
+        FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems.at(i));
+        if (listItem->section()) {
+            qreal pos = listItem->position();
+            releaseSectionItem(listItem->section());
+            listItem->setSection(0);
+            listItem->setPosition(pos);
+        }
+    }
+    for (int i = 0; i < sectionCacheSize; ++i) {
+        delete sectionCache[i];
+        sectionCache[i] = 0;
+    }
+}
+
 void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
 {
     if (!sectionCriteria || !sectionCriteria->delegate())
@@ -1140,6 +1165,8 @@ void QQuickListViewPrivate::updateSections()
     lastVisibleSection = QString();
     updateCurrentSection();
     updateStickySections();
+    forceLayout = true;
+    q->polish();
 }
 
 void QQuickListViewPrivate::updateCurrentSection()
@@ -1901,7 +1928,7 @@ QQuickListView::~QQuickListView()
     is scrolled.  This is because the view moves to maintain the
     highlight within the preferred highlight range (or visible viewport).
 
-    \sa highlight
+    \sa highlight, highlightMoveVelocity
 */
 //###Possibly rename these properties, since they are very useful even without a highlight?
 /*!
@@ -2190,20 +2217,42 @@ QString QQuickListView::currentSection() const
 }
 
 /*!
+    \qmlproperty real QtQuick2::ListView::highlightMoveVelocity
     \qmlproperty int QtQuick2::ListView::highlightMoveDuration
+    \qmlproperty real QtQuick2::ListView::highlightResizeVelocity
     \qmlproperty int QtQuick2::ListView::highlightResizeDuration
 
-    These properties hold the move and resize animation duration of
-    the highlight delegate.
+    These properties control the speed of the move and resize animations for the
+    highlight delegate.
 
     \l highlightFollowsCurrentItem must be true for these properties
     to have effect.
 
-    The default value for highlightMoveDuration is 150ms and the
-    default value for highlightResizeDuration is 250ms.
+    The default value for the velocity properties is 400 pixels/second.
+    The default value for the duration properties is -1, i.e. the
+    highlight will take as much time as necessary to move at the set speed.
+
+    These properties have the same characteristics as a SmoothedAnimation.
 
     \sa highlightFollowsCurrentItem
 */
+qreal QQuickListView::highlightMoveVelocity() const
+{
+    Q_D(const QQuickListView);
+    return d->highlightMoveVelocity;
+}
+
+void QQuickListView::setHighlightMoveVelocity(qreal speed)
+{
+    Q_D(QQuickListView);
+    if (d->highlightMoveVelocity != speed) {
+        d->highlightMoveVelocity = speed;
+        if (d->highlightPosAnimator)
+            d->highlightPosAnimator->velocity = d->highlightMoveVelocity;
+        emit highlightMoveVelocityChanged();
+    }
+}
+
 void QQuickListView::setHighlightMoveDuration(int duration)
 {
     Q_D(QQuickListView);
@@ -2214,6 +2263,23 @@ void QQuickListView::setHighlightMoveDuration(int duration)
     }
 }
 
+qreal QQuickListView::highlightResizeVelocity() const
+{
+    Q_D(const QQuickListView);
+    return d->highlightResizeVelocity;
+}
+
+void QQuickListView::setHighlightResizeVelocity(qreal speed)
+{
+    Q_D(QQuickListView);
+    if (d->highlightResizeVelocity != speed) {
+        d->highlightResizeVelocity = speed;
+        if (d->highlightSizeAnimator)
+            d->highlightSizeAnimator->velocity = d->highlightResizeVelocity;
+        emit highlightResizeVelocityChanged();
+    }
+}
+
 int QQuickListView::highlightResizeDuration() const
 {
     Q_D(const QQuickListView);
index 6bdd4cb..a40a01a 100644 (file)
@@ -102,6 +102,8 @@ class Q_AUTOTEST_EXPORT QQuickListView : public QQuickItemView
     Q_OBJECT
     Q_DECLARE_PRIVATE(QQuickListView)
 
+    Q_PROPERTY(qreal highlightMoveVelocity READ highlightMoveVelocity WRITE setHighlightMoveVelocity NOTIFY highlightMoveVelocityChanged)
+    Q_PROPERTY(qreal highlightResizeVelocity READ highlightResizeVelocity WRITE setHighlightResizeVelocity NOTIFY highlightResizeVelocityChanged)
     Q_PROPERTY(int highlightResizeDuration READ highlightResizeDuration WRITE setHighlightResizeDuration NOTIFY highlightResizeDurationChanged)
 
     Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
@@ -132,6 +134,12 @@ public:
 
     virtual void setHighlightFollowsCurrentItem(bool);
 
+    qreal highlightMoveVelocity() const;
+    void setHighlightMoveVelocity(qreal);
+
+    qreal highlightResizeVelocity() const;
+    void setHighlightResizeVelocity(qreal);
+
     int highlightResizeDuration() const;
     void setHighlightResizeDuration(int);
 
@@ -151,6 +159,8 @@ Q_SIGNALS:
     void spacingChanged();
     void orientationChanged();
     void currentSectionChanged();
+    void highlightMoveVelocityChanged();
+    void highlightResizeVelocityChanged();
     void highlightResizeDurationChanged();
     void snapModeChanged();
 
index f114292..17458ab 100644 (file)
@@ -59,6 +59,8 @@ DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
 
 static const int PressAndHoldDelay = 800;
 
+#ifndef QT_NO_DRAGANDDROP
+
 QQuickDrag::QQuickDrag(QObject *parent)
 : QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX),
 _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false)
@@ -186,16 +188,29 @@ QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
     return new QQuickDragAttached(obj);
 }
 
+#endif // QT_NO_DRAGANDDROP
+
 QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
 : enabled(true), hovered(false), pressed(false), longPress(false),
   moved(false), dragX(true), dragY(true), stealMouse(false), doubleClick(false), preventStealing(false),
-  propagateComposedEvents(false), drag(0)
+  propagateComposedEvents(false)
+#ifndef QT_NO_DRAGANDDROP
+  , drag(0)
+#endif
+#ifndef QT_NO_CURSOR
+  , cursor(0)
+#endif
 {
 }
 
 QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
 {
+#ifndef QT_NO_DRAGANDDROP
     delete drag;
+#endif
+#ifndef QT_NO_CURSOR
+    delete cursor;
+#endif
 }
 
 void QQuickMouseAreaPrivate::init()
@@ -696,18 +711,22 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
     else {
         d->longPress = false;
         d->saveEvent(event);
+#ifndef QT_NO_DRAGANDDROP
         if (d->drag)
             d->drag->setActive(false);
+#endif
         setHovered(true);
         d->startScene = event->windowPos();
         d->pressAndHoldTimer.start(PressAndHoldDelay, this);
         setKeepMouseGrab(d->stealMouse);
         event->setAccepted(setPressed(true));
 
+#ifndef QT_NO_DRAGANDDROP
         if (d->drag) {
             d->dragX = drag()->axis() & QQuickDrag::XAxis;
             d->dragY = drag()->axis() & QQuickDrag::YAxis;
         }
+#endif
     }
 }
 
@@ -729,6 +748,7 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
     else if (!d->hovered && isInside)
         setHovered(true);
 
+#ifndef QT_NO_DRAGANDDROP
     if (d->drag && d->drag->target()) {
         if (!d->moved) {
             d->targetStartPos = d->drag->target()->parentItem()
@@ -789,6 +809,8 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
 
         d->moved = true;
     }
+#endif
+
     QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
     emit mouseXChanged(&me);
     me.setPosition(d->lastPos);
@@ -806,8 +828,10 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
     } else {
         d->saveEvent(event);
         setPressed(false);
+#ifndef QT_NO_DRAGANDDROP
         if (d->drag)
             d->drag->setActive(false);
+#endif
         // If we don't accept hover, we need to reset containsMouse.
         if (!acceptHoverEvents())
             setHovered(false);
@@ -969,7 +993,13 @@ bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
 bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
 {
     Q_D(QQuickMouseArea);
-    if (!d->pressed && (!d->enabled || !isVisible() || !d->drag || !d->drag->filterChildren()))
+    if (!d->pressed &&
+            (!d->enabled || !isVisible()
+#ifndef QT_NO_DRAGANDDROP
+             || !d->drag || !d->drag->filterChildren()
+#endif
+            )
+       )
         return QQuickItem::childMouseEventFilter(i, e);
     switch (e->type()) {
     case QEvent::MouseButtonPress:
@@ -988,7 +1018,11 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event)
     Q_D(QQuickMouseArea);
     if (event->timerId() == d->pressAndHoldTimer.timerId()) {
         d->pressAndHoldTimer.stop();
+#ifndef QT_NO_DRAGANDDROP
         bool dragged = d->drag && d->drag->active();
+#else
+        bool dragged = false;
+#endif
         if (d->pressed && dragged == false && d->hovered == true) {
             d->longPress = true;
             QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
@@ -1091,8 +1125,18 @@ void QQuickMouseArea::setHovered(bool h)
         d->hovered = h;
         emit hoveredChanged();
         d->hovered ? emit entered() : emit exited();
+#ifndef QT_NO_CURSOR
+        if (d->cursor) {
+            if (d->hovered) {
+                canvas()->setCursor(QCursor(*d->cursor));
+            } else {
+                canvas()->unsetCursor();
+            }
+        }
+#endif
     }
 }
+
 /*!
     \qmlproperty QtQuick2::Qt::MouseButtons MouseArea::acceptedButtons
     This property holds the mouse buttons that the mouse area reacts to.
@@ -1129,7 +1173,11 @@ void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
 bool QQuickMouseArea::setPressed(bool p)
 {
     Q_D(QQuickMouseArea);
+#ifndef QT_NO_DRAGANDDROP
     bool dragged = d->drag && d->drag->active();
+#else
+    bool dragged = false;
+#endif
     bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
 
     if (d->pressed != p) {
@@ -1160,6 +1208,68 @@ bool QQuickMouseArea::setPressed(bool p)
     return false;
 }
 
+
+/*!
+    \qmlproperty QtQuick2::Qt::CursorShape MouseArea::cursorShape
+    This property holds the cursor shape for this mouse area.
+    Note that on platforms that do not display a mouse cursor this may have
+    no effect.
+
+    The available cursor shapes are:
+    \list
+    \li Qt.ArrowCursor
+    \li Qt.UpArrowCursor
+    \li Qt.CrossCursor
+    \li Qt.WaitCursor
+    \li Qt.IBeamCursor
+    \li Qt.SizeVerCursor
+    \li Qt.SizeHorCursor
+    \li Qt.SizeBDiagCursor
+    \li Qt.SizeFDiagCursor
+    \li Qt.SizeAllCursor
+    \li Qt.BlankCursor
+    \li Qt.SplitVCursor
+    \li Qt.SplitHCursor
+    \li Qt.PointingHandCursor
+    \li Qt.ForbiddenCursor
+    \li Qt.WhatsThisCursor
+    \li Qt.BusyCursor
+    \li Qt.OpenHandCursor
+    \li Qt.ClosedHandCursor
+    \li Qt.DragCopyCursor
+    \li Qt.DragMoveCursor
+    \li Qt.DragLinkCursor
+    \endlist
+
+    In order to only set a mouse cursor shape for a region without reacting
+    to mouse events set the acceptedButtons to none:
+
+    \code
+    MouseArea { cursorShape: Qt.IBeamCursor; acceptedButtons: Qt.NoButton }
+    \endcode
+
+    The default value is \c Qt.ArrowCursor.
+    \sa Qt::CursorShape
+*/
+
+#ifndef QT_NO_CURSOR
+Qt::CursorShape QQuickMouseArea::cursorShape() const
+{
+    Q_D(const QQuickMouseArea);
+    if (d->cursor)
+        return d->cursor->shape();
+    return Qt::ArrowCursor;
+}
+
+void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
+{
+    Q_D(QQuickMouseArea);
+    setHoverEnabled(true);
+    delete d->cursor;
+    d->cursor = new QCursor(shape);
+}
+#endif
+
 /*!
     \qmlproperty Item QtQuick2::MouseArea::drag.target
     \qmlproperty bool QtQuick2::MouseArea::drag.active
@@ -1197,6 +1307,7 @@ bool QQuickMouseArea::setPressed(bool p)
 
 */
 
+#ifndef QT_NO_DRAGANDDROP
 QQuickDrag *QQuickMouseArea::drag()
 {
     Q_D(QQuickMouseArea);
@@ -1204,6 +1315,7 @@ QQuickDrag *QQuickMouseArea::drag()
         d->drag = new QQuickDrag;
     return d->drag;
 }
+#endif
 
 QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
 {
index 177d283..14b74f4 100644 (file)
@@ -50,8 +50,11 @@ QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
 
-class QQuickDragAttached;
 class QQuickMouseEvent;
+
+#ifndef QT_NO_DRAGANDDROP
+
+class QQuickDragAttached;
 class Q_AUTOTEST_EXPORT QQuickDrag : public QObject
 {
     Q_OBJECT
@@ -118,6 +121,8 @@ private:
     Q_DISABLE_COPY(QQuickDrag)
 };
 
+#endif // QT_NO_DRAGANDDROP
+
 class QQuickMouseAreaPrivate;
 class QQuickWheelEvent;
 // used in QtLocation
@@ -133,9 +138,14 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
     Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedChanged)
     Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
     Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged)
+#ifndef QT_NO_DRAGANDDROP
     Q_PROPERTY(QQuickDrag *drag READ drag CONSTANT) //### add flicking to QQuickDrag or add a QQuickFlick ???
+#endif
     Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged)
     Q_PROPERTY(bool propagateComposedEvents READ propagateComposedEvents WRITE setPropagateComposedEvents NOTIFY propagateComposedEventsChanged)
+#ifndef QT_NO_CURSOR
+    Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY cursorShapeChanged)
+#endif
 
 public:
     QQuickMouseArea(QQuickItem *parent=0);
@@ -158,7 +168,9 @@ public:
     bool hoverEnabled() const;
     void setHoverEnabled(bool h);
 
+#ifndef QT_NO_DRAGANDDROP
     QQuickDrag *drag();
+#endif
 
     bool preventStealing() const;
     void setPreventStealing(bool prevent);
@@ -166,12 +178,20 @@ public:
     bool propagateComposedEvents() const;
     void setPropagateComposedEvents(bool propagate);
 
+#ifndef QT_NO_CURSOR
+    Qt::CursorShape cursorShape() const;
+    void setCursorShape(Qt::CursorShape shape);
+#endif
+
 Q_SIGNALS:
     void hoveredChanged();
     void pressedChanged();
     void enabledChanged();
     void acceptedButtonsChanged();
     void hoverEnabledChanged();
+#ifndef QT_NO_CURSOR
+    void cursorShapeChanged();
+#endif
     void positionChanged(QQuickMouseEvent *mouse);
     void mouseXChanged(QQuickMouseEvent *mouse);
     void mouseYChanged(QQuickMouseEvent *mouse);
@@ -223,8 +243,10 @@ private:
 
 QT_END_NAMESPACE
 
+#ifndef QT_NO_DRAGANDDROP
 QML_DECLARE_TYPE(QQuickDrag)
 QML_DECLARE_TYPEINFO(QQuickDrag, QML_HAS_ATTACHED_PROPERTIES)
+#endif
 QML_DECLARE_TYPE(QQuickMouseArea)
 
 QT_END_HEADER
index d73fb12..39a0616 100644 (file)
@@ -96,7 +96,9 @@ public:
     bool doubleClick : 1;
     bool preventStealing : 1;
     bool propagateComposedEvents : 1;
+#ifndef QT_NO_DRAGANDDROP
     QQuickDrag *drag;
+#endif
     QPointF startScene;
     QPointF targetStartPos;
     QPointF lastPos;
@@ -105,6 +107,9 @@ public:
     Qt::MouseButtons lastButtons;
     Qt::KeyboardModifiers lastModifiers;
     QBasicTimer pressAndHoldTimer;
+#ifndef QT_NO_CURSOR
+    QCursor *cursor;
+#endif
 };
 
 QT_END_NAMESPACE
index f03afd6..b19b13f 100644 (file)
@@ -47,6 +47,8 @@
 #include <private/qsgadaptationlayer_p.h>
 #include "qquicktextnode_p.h"
 #include "qquickimage_p_p.h"
+#include "qquicktextutil_p.h"
+
 #include <QtQuick/private/qsgtexture_p.h>
 
 #include <QtQml/qqmlinfo.h>
@@ -2011,36 +2013,13 @@ QRectF QQuickText::boundingRect() const
     Q_D(const QQuickText);
 
     QRectF rect = d->layedOutTextRect;
+    rect.moveLeft(QQuickTextUtil::alignedX(rect, width(), d->hAlign));
+    rect.moveTop(QQuickTextUtil::alignedY(rect, height(), d->vAlign));
+
     if (d->style != Normal)
         rect.adjust(-1, 0, 1, 2);
-
     // Could include font max left/right bearings to either side of rectangle.
 
-    qreal w = width();
-    switch (d->hAlign) {
-    case AlignLeft:
-    case AlignJustify:
-        break;
-    case AlignRight:
-        rect.moveLeft(w - rect.width());
-        break;
-    case AlignHCenter:
-        rect.moveLeft((w - rect.width()) / 2);
-        break;
-    }
-
-    qreal h = height();
-    switch (d->vAlign) {
-    case AlignTop:
-        break;
-    case AlignBottom:
-        rect.moveTop(h - rect.height());
-        break;
-    case AlignVCenter:
-        rect.moveTop((h - rect.height()) / 2);
-        break;
-    }
-
     return rect;
 }
 
@@ -2131,7 +2110,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
 
     d->updateType = QQuickTextPrivate::UpdateNone;
 
-    QRectF bounds = boundingRect();
+    const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect, height(), d->vAlign);
 
     // We need to make sure the layout is done in the current thread
 #if defined(Q_OS_MAC)
@@ -2156,27 +2135,28 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
 
     if (d->richText) {
         d->ensureDoc();
-        node->addTextDocument(bounds.topLeft(), d->extra->doc, color, d->style, styleColor, linkColor);
-    } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
+        const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect, width(), d->hAlign);
+        node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor);
+    } else if (d->elideMode == QQuickText::ElideNone || d->layedOutTextRect.width() > 0.) {
         int unelidedLineCount = d->lineCount;
         if (d->elideLayout)
             unelidedLineCount -= 1;
         if (unelidedLineCount > 0) {
             node->addTextLayout(
-                        QPoint(0, bounds.y()),
+                        QPoint(0, dy),
                         &d->layout,
                         color, d->style, styleColor, linkColor,
                         QColor(), QColor(), -1, -1,
                         0, unelidedLineCount);
         }
         if (d->elideLayout)
-            node->addTextLayout(QPoint(0, bounds.y()), d->elideLayout, color, d->style, styleColor, linkColor);
+            node->addTextLayout(QPoint(0, dy), d->elideLayout, color, d->style, styleColor, linkColor);
     }
 
     foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
         QQuickPixmap *pix = img->pix;
         if (pix && pix->isReady())
-            node->addImage(QRectF(img->pos.x(), img->pos.y() + bounds.y(), pix->width(), pix->height()), pix->image());
+            node->addImage(QRectF(img->pos.x(), img->pos.y() + dy, pix->width(), pix->height()), pix->image());
     }
     return node;
 }
@@ -2397,28 +2377,42 @@ void QQuickText::componentComplete()
         d->updateLayout();
 }
 
-
-QString QQuickTextPrivate::anchorAt(const QPointF &mousePos)
+QString QQuickTextPrivate::anchorAt(const QTextLayout *layout, const QPointF &mousePos)
 {
-    if (styledText) {
-        for (int i = 0; i < layout.lineCount(); ++i) {
-            QTextLine line = layout.lineAt(i);
-            if (line.naturalTextRect().contains(mousePos)) {
-                int charPos = line.xToCursor(mousePos.x());
-                foreach (const QTextLayout::FormatRange &formatRange, layout.additionalFormats()) {
-                    if (formatRange.format.isAnchor()
-                            && charPos >= formatRange.start
-                            && charPos <= formatRange.start + formatRange.length) {
-                        return formatRange.format.anchorHref();
-                    }
+    for (int i = 0; i < layout->lineCount(); ++i) {
+        QTextLine line = layout->lineAt(i);
+        if (line.naturalTextRect().contains(mousePos)) {
+            int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter);
+            foreach (const QTextLayout::FormatRange &formatRange, layout->additionalFormats()) {
+                if (formatRange.format.isAnchor()
+                        && charPos >= formatRange.start
+                        && charPos < formatRange.start + formatRange.length) {
+                    return formatRange.format.anchorHref();
                 }
-                break;
             }
+            break;
         }
     }
     return QString();
 }
 
+QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const
+{
+    Q_Q(const QQuickText);
+    QPointF translatedMousePos = mousePos;
+    translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect, q->height(), vAlign);
+    if (styledText) {
+        QString link = anchorAt(&layout, translatedMousePos);
+        if (link.isEmpty() && elideLayout)
+            link = anchorAt(elideLayout, translatedMousePos);
+        return link;
+    } else if (richText && extra.isAllocated() && extra->doc) {
+        translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect, q->width(), hAlign);
+        return extra->doc->documentLayout()->anchorAt(translatedMousePos);
+    }
+    return QString();
+}
+
 bool QQuickTextPrivate::isLinkActivatedConnected()
 {
     Q_Q(QQuickText);
@@ -2431,14 +2425,8 @@ void QQuickText::mousePressEvent(QMouseEvent *event)
     Q_D(QQuickText);
 
     QString link;
-    if (d->isLinkActivatedConnected()) {
-        if (d->styledText)
-            link = d->anchorAt(event->localPos());
-        else if (d->richText) {
-            d->ensureDoc();
-            link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
-        }
-    }
+    if (d->isLinkActivatedConnected())
+        link = d->anchorAt(event->localPos());
 
     if (link.isEmpty()) {
         event->setAccepted(false);
@@ -2450,9 +2438,9 @@ void QQuickText::mousePressEvent(QMouseEvent *event)
 
     if (!event->isAccepted())
         QQuickItem::mousePressEvent(event);
-
 }
 
+
 /*! \internal */
 void QQuickText::mouseReleaseEvent(QMouseEvent *event)
 {
@@ -2461,14 +2449,8 @@ void QQuickText::mouseReleaseEvent(QMouseEvent *event)
     // ### confirm the link, and send a signal out
 
     QString link;
-    if (d->isLinkActivatedConnected()) {
-        if (d->styledText)
-            link = d->anchorAt(event->localPos());
-        else if (d->richText) {
-            d->ensureDoc();
-            link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
-        }
-    }
+    if (d->isLinkActivatedConnected())
+        link = d->anchorAt(event->localPos());
 
     if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link)
         emit linkActivated(d->extra->activeLink);
index 2afcd8f..985b1e1 100644 (file)
@@ -166,7 +166,8 @@ public:
     QRectF setupTextLayout(qreal *const naturalWidth,  qreal * const baseline);
     void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0);
     bool isLinkActivatedConnected();
-    QString anchorAt(const QPointF &pos);
+    static QString anchorAt(const QTextLayout *layout, const QPointF &mousePos);
+    QString anchorAt(const QPointF &pos) const;
 
     inline qreal lineHeight() const { return extra.isAllocated() ? extra->lineHeight : 1.0; }
     inline int maximumLineCount() const { return extra.isAllocated() ? extra->maximumLineCount : INT_MAX; }
index 0d05d6f..30512a1 100644 (file)
@@ -1588,7 +1588,7 @@ void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
 {
     Q_D(QQuickTextInput);
     if (!d->inLayout) {
-        if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
+        if (newGeometry.width() != oldGeometry.width())
             d->updateLayout();
         updateCursorRectangle();
     }
index c2c11b3..176301d 100644 (file)
@@ -78,4 +78,37 @@ QQuickItem *QQuickTextUtil::createCursor(
     return item;
 }
 
+qreal QQuickTextUtil::alignedX(const QRectF &rect, qreal width, int alignment)
+{
+    qreal x = 0;
+    switch (alignment) {
+    case Qt::AlignLeft:
+    case Qt::AlignJustify:
+        break;
+    case Qt::AlignRight:
+        x = width - rect.width();
+        break;
+    case Qt::AlignHCenter:
+        x = (width - rect.width()) / 2;
+        break;
+    }
+    return x;
+}
+
+qreal QQuickTextUtil::alignedY(const QRectF &rect, const qreal height, int alignment)
+{
+    qreal y = 0;
+    switch (alignment) {
+    case Qt::AlignTop:
+        break;
+    case Qt::AlignBottom:
+        y = height - rect.height();
+        break;
+    case Qt::AlignVCenter:
+        y = (height - rect.height()) / 2;
+        break;
+    }
+    return y;
+}
+
 QT_END_NAMESPACE
index 91ef40b..d6c05aa 100644 (file)
@@ -66,12 +66,16 @@ public:
     template <typename Private> static void setCursorDelegate(Private *d, QQmlComponent *delegate);
     template <typename Private> static void createCursor(Private *d);
 
+    static qreal alignedX(const QRectF &rect, qreal width, int alignment);
+    static qreal alignedY(const QRectF &rect, qreal height, int alignment);
+
 private:
     static QQuickItem *createCursor(
             QQmlComponent *component,
             QQuickItem *parent,
             const QRectF &cursorRectangle,
             const char *className);
+
 };
 
 template <typename Private>
index 29098e4..7df0491 100644 (file)
@@ -17,6 +17,9 @@ exists("qqml_enable_gcov") {
 
 load(qt_module_config)
 
+QMAKE_DOCS = $$PWD/doc/qtquick.qdocconf
+QMAKE_DOCS_INDEX = ../../doc
+
 # private dependencies
 QT += v8-private network
 
index e41c261..48613a4 100644 (file)
@@ -46,6 +46,7 @@ PRIVATETESTS += \
     qquicklistmodelworkerscript \
     qquickworkerscript \
     qqmlbundle \
+    qrcqml \
     v4
 
 !contains(QT_CONFIG, no-widgets) {
index beb0f59..561300d 100644 (file)
@@ -83,6 +83,12 @@ void registerTypes()
     qmlRegisterType<MyEnumDerivedClass>("Test",1,0,"MyEnumDerivedClass");
 
     qmlRegisterType<MyReceiversTestObject>("Test",1,0,"MyReceiversTestObject");
+
+    qmlRegisterUncreatableType<MyUncreateableBaseClass>("Test", 1, 0, "MyUncreateableBaseClass", "Cannot create MyUncreateableBaseClass");
+    qmlRegisterType<MyCreateableDerivedClass>("Test", 1, 0, "MyCreateableDerivedClass");
+
+    qmlRegisterUncreatableType<MyUncreateableBaseClass,1>("Test", 1, 1, "MyUncreateableBaseClass", "Cannot create MyUncreateableBaseClass");
+    qmlRegisterType<MyCreateableDerivedClass,1>("Test", 1, 1, "MyCreateableDerivedClass");
 }
 
 QVariant myCustomVariantTypeConverter(const QString &data)
index f84e42f..50b6089 100644 (file)
@@ -910,6 +910,41 @@ protected:
     qreal m_p5;
 };
 
+class MyUncreateableBaseClass : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(bool prop1 READ prop1 WRITE setprop1)
+    Q_PROPERTY(bool prop2 READ prop2 WRITE setprop2 REVISION 1)
+    Q_PROPERTY(bool prop3 READ prop3 WRITE setprop3 REVISION 1)
+public:
+    explicit MyUncreateableBaseClass(bool arg, QObject *parent = 0)
+        : QObject(parent), _prop1(false), _prop2(false), _prop3(false)
+    {
+    }
+
+    bool _prop1;
+    bool prop1() const { return _prop1; }
+    void setprop1(bool p) { _prop1 = p; }
+    bool _prop2;
+    bool prop2() const { return _prop2; }
+    void setprop2(bool p) { _prop2 = p; }
+    bool _prop3;
+    bool prop3() const { return _prop3; }
+    void setprop3(bool p) { _prop3 = p; }
+};
+
+class MyCreateableDerivedClass : public MyUncreateableBaseClass
+{
+    Q_OBJECT
+    Q_PROPERTY(bool prop2 READ prop2 WRITE setprop2 REVISION 1)
+
+public:
+    MyCreateableDerivedClass(QObject *parent = 0)
+        : MyUncreateableBaseClass(true, parent)
+    {
+    }
+};
+
 class MyVersion2Class : public QObject
 {
     Q_OBJECT
index 6349cd3..2f2f0a7 100644 (file)
@@ -176,6 +176,9 @@ private slots:
     void revisions();
     void revisionOverloads();
 
+    void subclassedUncreateableRevision_data();
+    void subclassedUncreateableRevision();
+
     void propertyInit();
     void remoteLoadCrash();
     void signalWithDefaultArg();
@@ -2540,6 +2543,59 @@ void tst_qqmllanguage::revisionOverloads()
     }
 }
 
+void tst_qqmllanguage::subclassedUncreateableRevision_data()
+{
+    QTest::addColumn<QString>("version");
+    QTest::addColumn<QString>("prop");
+    QTest::addColumn<bool>("shouldWork");
+
+    QTest::newRow("prop1 exists in 1.0") << "1.0" << "prop1" << true;
+    QTest::newRow("prop2 does not exist in 1.0") << "1.0" << "prop2" << false;
+    QTest::newRow("prop3 does not exist in 1.0") << "1.0" << "prop3" << false;
+
+    QTest::newRow("prop1 exists in 1.1") << "1.1" << "prop1" << true;
+    QTest::newRow("prop2 works because it's re-declared in Derived") << "1.1" << "prop2" << true;
+    QTest::newRow("prop3 only works if the Base REVISION 1 is picked up") << "1.1" << "prop3" << true;
+
+}
+
+void tst_qqmllanguage::subclassedUncreateableRevision()
+{
+    QFETCH(QString, version);
+    QFETCH(QString, prop);
+    QFETCH(bool, shouldWork);
+
+    {
+        QQmlEngine engine;
+        QString qml = QString("import QtQuick 2.0\nimport Test %1\nMyUncreateableBaseClass {}").arg(version);
+        QQmlComponent c(&engine);
+        QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+        c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
+        QObject *obj = c.create();
+        QCOMPARE(obj, static_cast<QObject*>(0));
+        QCOMPARE(c.errors().count(), 1);
+        QCOMPARE(c.errors().first().description(), QString("Cannot create MyUncreateableBaseClass"));
+    }
+
+    QQmlEngine engine;
+    QString qml = QString("import QtQuick 2.0\nimport Test %1\nMyCreateableDerivedClass {\n%3: true\n}").arg(version).arg(prop);
+    QQmlComponent c(&engine);
+    if (!shouldWork)
+        QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+    c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
+    QObject *obj = c.create();
+    if (!shouldWork) {
+        QCOMPARE(obj, static_cast<QObject*>(0));
+        return;
+    }
+
+    QVERIFY(obj);
+    MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj);
+    QVERIFY(base);
+    QCOMPARE(base->property(prop.toLatin1()).toBool(), true);
+    delete obj;
+}
+
 void tst_qqmllanguage::initTestCase()
 {
     QString testdataDir = QFileInfo(QFINDTESTDATA("data")).absolutePath();
index 248cc0d..658874f 100644 (file)
@@ -1557,11 +1557,12 @@ void tst_qqmlproperty::urlHandling_data()
         << QString("/main.qml")
         << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working?");
 
+    // Although 'text%2Fqml' is pre-encoded, it will be decoded to allow correct QUrl classification
     QTest::newRow("preencodedQuery")
         << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now working%3F")
         << QString("http")
         << QString("/main.qml")
-        << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now%20working%3F");
+        << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working%3F");
 
     QTest::newRow("encodableFragment")
         << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000|volume+50%")
index 89e8886..e94fe81 100644 (file)
@@ -123,6 +123,8 @@ private slots:
     void role_mode_data();
     void role_mode();
     void string_to_list_crash();
+    void empty_element_warning();
+    void empty_element_warning_data();
 };
 
 bool tst_qquicklistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -1189,6 +1191,41 @@ void tst_qquicklistmodel::string_to_list_crash()
     e.evaluate();
 }
 
+void tst_qquicklistmodel::empty_element_warning_data()
+{
+    QTest::addColumn<QString>("qml");
+    QTest::addColumn<bool>("warning");
+
+    QTest::newRow("empty") << "import QtQuick 2.0\nListModel {}" << false;
+    QTest::newRow("withid") << "import QtQuick 2.0\nListModel { id: model }" << false;
+    QTest::newRow("emptyElement") << "import QtQuick 2.0\nListModel { ListElement {} }" << true;
+    QTest::newRow("emptyElements") << "import QtQuick 2.0\nListModel { ListElement {} ListElement {} }" << true;
+    QTest::newRow("role1") << "import QtQuick 2.0\nListModel { ListElement {a:1} }" << false;
+    QTest::newRow("role2") << "import QtQuick 2.0\nListModel { ListElement {} ListElement {a:1} ListElement {} }" << false;
+    QTest::newRow("role3") << "import QtQuick 2.0\nListModel { ListElement {} ListElement {a:1} ListElement {b:2} }" << false;
+}
+
+void tst_qquicklistmodel::empty_element_warning()
+{
+    QFETCH(QString, qml);
+    QFETCH(bool, warning);
+
+    if (warning) {
+        QString warningString = QLatin1String("file:dummy.qml:2:1: QML ListModel: All ListElement declarations are empty, no roles can be created unless dynamicRoles is set.");
+        QTest::ignoreMessage(QtWarningMsg, warningString.toLatin1());
+    }
+
+    QQmlEngine engine;
+    QQmlComponent component(&engine);
+    component.setData(qml.toUtf8(), QUrl::fromLocalFile(QString("dummy.qml")));
+    QVERIFY(!component.isError());
+
+    QObject *obj = component.create();
+    QVERIFY(obj != 0);
+
+    delete obj;
+}
+
 QTEST_MAIN(tst_qquicklistmodel)
 
 #include "tst_qquicklistmodel.moc"
index f5d7dd5..b81fff0 100644 (file)
@@ -66,9 +66,6 @@ void tst_qrcqml::basicLoad()
 {
     QQmlEngine e;
     QQmlComponent c(&e, QUrl("qrc:/main.qml"));
-    if (c.isError())
-        qDebug() << "Error: " << c.errors();
-    QEXPECT_FAIL("", "QTBUG-25937", Abort);
     QVERIFY(c.isReady());
     QObject* o = c.create();
     QVERIFY(o);
index 3d02dce..287ccef 100644 (file)
@@ -85,7 +85,7 @@ void tst_qquickapplication::active()
     // not active
     QVERIFY(!item->property("active").toBool());
     QVERIFY(!item->property("active2").toBool());
-    QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0);
+    QCOMPARE(item->property("active").toBool(), QGuiApplication::focusWindow() != 0);
 
     // active
     view.show();
@@ -93,8 +93,8 @@ void tst_qquickapplication::active()
     QTest::qWait(50);
     QEXPECT_FAIL("", "QTBUG-21573", Abort);
     QTRY_COMPARE(view.status(), QQuickView::Ready);
-    QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0);
-    QCOMPARE(item->property("active2").toBool(), QGuiApplication::activeWindow() != 0);
+    QCOMPARE(item->property("active").toBool(), QGuiApplication::focusWindow() != 0);
+    QCOMPARE(item->property("active2").toBool(), QGuiApplication::focusWindow() != 0);
 
 #if 0
     // QGuiApplication has no equivalent of setActiveWindow(0). QTBUG-21573
@@ -107,7 +107,7 @@ void tst_qquickapplication::active()
     // not active again
     QGuiApplication::setActiveWindow(0);
     QVERIFY(!item->property("active").toBool());
-    QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0);
+    QCOMPARE(item->property("active").toBool(), QGuiApplication::focusWindow() != 0);
 #endif
 
 }
index c6c3f6c..9bffdbc 100644 (file)
@@ -44,6 +44,7 @@
 #include <QTcpSocket>
 #include <QDir>
 #include <QPainter>
+#include <QSignalSpy>
 
 #include <QtQml/qqmlengine.h>
 #include <QtQml/qqmlcomponent.h>
@@ -60,6 +61,8 @@
 #define SERVER_PORT 14446
 #define SERVER_ADDR "http://127.0.0.1:14446"
 
+Q_DECLARE_METATYPE(QQuickImageBase::Status)
+
 class tst_qquickborderimage : public QQmlDataTest
 
 {
@@ -84,6 +87,9 @@ private slots:
     void pendingRemoteRequest();
     void pendingRemoteRequest_data();
 
+    void statusChanges();
+    void statusChanges_data();
+
 private:
     QQmlEngine engine;
 };
@@ -396,6 +402,51 @@ void tst_qquickborderimage::pendingRemoteRequest_data()
     QTest::newRow("sci file") << "http://localhost/none.sci";
 }
 
+//QTBUG-26155
+void tst_qquickborderimage::statusChanges_data()
+{
+    QTest::addColumn<QString>("source");
+    QTest::addColumn<int>("emissions");
+    QTest::addColumn<bool>("remote");
+    QTest::addColumn<QQuickImageBase::Status>("finalStatus");
+
+    QTest::newRow("localfile") << testFileUrl("colors.png").toString() << 1 << false << QQuickImageBase::Ready;
+    QTest::newRow("nofile") << "" << 0 << false << QQuickImageBase::Null;
+    QTest::newRow("nonexistent") << testFileUrl("thisfiledoesnotexist.png").toString() << 1 << false << QQuickImageBase::Error;
+    QTest::newRow("noprotocol") << QString("thisfiledoesnotexisteither.png") << 2 << false << QQuickImageBase::Error;
+    QTest::newRow("remote") << "http://localhost:14446/colors.png" << 2 << true << QQuickImageBase::Ready;
+}
+
+void tst_qquickborderimage::statusChanges()
+{
+    QFETCH(QString, source);
+    QFETCH(int, emissions);
+    QFETCH(bool, remote);
+    QFETCH(QQuickImageBase::Status, finalStatus);
+
+    TestHTTPServer *server = 0;
+    if (remote) {
+        server = new TestHTTPServer(SERVER_PORT);
+        QVERIFY(server->isValid());
+        server->serveDirectory(dataDirectory(), TestHTTPServer::Delay);
+    }
+
+    QString componentStr = "import QtQuick 2.0\nBorderImage { width: 300; height: 300 }";
+    QQmlComponent component(&engine);
+    component.setData(componentStr.toLatin1(), QUrl(""));
+
+    QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create());
+    qRegisterMetaType<QQuickImageBase::Status>();
+    QSignalSpy spy(obj, SIGNAL(statusChanged(QQuickImageBase::Status)));
+    QVERIFY(obj != 0);
+    obj->setSource(source);
+    QTRY_VERIFY(obj->status() == finalStatus);
+    QCOMPARE(spy.count(), emissions);
+
+    delete obj;
+    delete server;
+}
+
 QTEST_MAIN(tst_qquickborderimage)
 
 #include "tst_qquickborderimage.moc"
index 001fd0d..83a1154 100644 (file)
@@ -78,6 +78,7 @@ public:
 
 private slots:
     void init();
+    void cleanupTestCase();
     void items();
     void changed();
     void inserted_basic();
@@ -320,6 +321,15 @@ void tst_QQuickGridView::init()
 #endif
 }
 
+void tst_QQuickGridView::cleanupTestCase()
+{
+#ifdef SHARE_VIEWS
+    testForView = QString();
+    delete m_view;
+    m_view = 0;
+#endif
+}
+
 void tst_QQuickGridView::items()
 {
     QQuickView *canvas = createView();
index 6ac56f8..63c332b 100644 (file)
@@ -44,5 +44,7 @@ Rectangle {
         model: testModel
         delegate: myDelegate
         highlight: myHighlight
+        highlightMoveVelocity: 1000
+        highlightResizeVelocity: 1000
     }
 }
index 17f787c..01b9ce3 100644 (file)
@@ -35,6 +35,8 @@ Rectangle {
         height: 320
         model: 2
         delegate: myDelegate
+        highlightMoveVelocity: 1000
+        highlightResizeVelocity: 1000
         cacheBuffer: 400
     }
     Text { anchors.bottom: parent.bottom; text: list.contentY }
index 1f6cccd..a02b66b 100644 (file)
@@ -56,6 +56,7 @@ Rectangle {
         height: 320
         keyNavigationWraps: testWrap
         delegate: myDelegate
+        highlightMoveVelocity: 1000
         model: testModel
         header: root.showHeader ? headerFooter : null
         footer: root.showFooter ? headerFooter : null
index 9aac506..fa7430c 100644 (file)
@@ -45,6 +45,7 @@ Rectangle {
         height: 320
         cacheBuffer: 0
         delegate: myDelegate
+        highlightMoveVelocity: 1000
         model: testModel
     }
 }
index 87179d5..14d2651 100644 (file)
@@ -136,6 +136,8 @@ Rectangle {
         height: 320
         model: visualModel.parts.package
         highlight: testObject.invalidHighlight ? invalidHl : myHighlight
+        highlightMoveVelocity: 1000
+        highlightResizeVelocity: 1000
         cacheBuffer: testObject.cacheBuffer
         header: root.showHeader ? headerFooter : null
         footer: root.showFooter ? headerFooter : null
index 29f9b92..8da859f 100644 (file)
@@ -124,6 +124,8 @@ Rectangle {
         model: testModel
         delegate: testObject.animate ? animatedDelegate : myDelegate
         highlight: testObject.invalidHighlight ? invalidHl : myHighlight
+        highlightMoveVelocity: 1000
+        highlightResizeVelocity: 1000
         cacheBuffer: testObject.cacheBuffer
         header: root.showHeader ? headerFooter : null
         footer: root.showFooter ? headerFooter : null
diff --git a/tests/auto/quick/qquicklistview/data/sectiondelegatechange.qml b/tests/auto/quick/qquicklistview/data/sectiondelegatechange.qml
new file mode 100644 (file)
index 0000000..eee15ed
--- /dev/null
@@ -0,0 +1,61 @@
+import QtQuick 2.0
+
+ListView {
+    width: 240
+    height: 320
+
+    function switchDelegates() {
+        section.delegate = section.delegate === delegate1
+                ? delegate2
+                : delegate1
+    }
+
+    Component {
+        id: delegate1
+
+        Rectangle {
+            objectName: "section1"
+            color: "lightsteelblue"
+            border.width: 1;
+            width: 240
+            height: 25
+
+            Text {
+                anchors.centerIn: parent
+                text: section
+            }
+        }
+    }
+    Component {
+        id: delegate2
+
+        Rectangle {
+            objectName: "section2"
+            color: "yellow"
+            border.width: 1;
+            width: 240
+            height: 50
+
+            Text {
+                anchors.centerIn: parent
+                text: section
+            }
+        }
+    }
+
+    section.property: "modelData"
+    section.delegate: delegate1
+
+    model: 20
+    delegate: Rectangle {
+        objectName: "item"
+        border.width: 1
+        width: 240
+        height: 25
+
+        Text {
+            anchors.centerIn: parent
+            text: modelData
+        }
+    }
+}
index f4679b5..feb2240 100644 (file)
@@ -23,12 +23,20 @@ Rectangle {
     }
 
     function switchGroups() {
+        myListView.model.move(0,1,1)
         if ("title" === myListView.groupBy)
             myListView.groupBy = "genre"
         else
             myListView.groupBy = "title"
     }
 
+    function switchGrouped() {
+        if ("pageCount" === myListView.groupBy)
+            myListView.groupBy = "genre"
+        else
+            myListView.groupBy = "pageCount"
+    }
+
     Component.onCompleted: {
         myListView.model = generateModel(myListView)
     }
@@ -56,11 +64,6 @@ Rectangle {
             Text { text: parent.y; anchors.right: parent.right }
         }
 
-        onGroupByChanged: {
-            model.move(0,1,1)
-            section.property = groupBy
-        }
-
         section {
             criteria: ViewSection.FullString
             delegate: Rectangle { width: 320; height: 25; color: "lightblue"
@@ -68,15 +71,15 @@ Rectangle {
                 Text {text: section }
                 Text { text: parent.y; anchors.right: parent.right }
             }
-            property: "title"
+            property: myListView.groupBy
         }
     }
 
     function generateModel(theParent)
     {
         var books = [
-                    { "author": "Billy Bob", "genre": "Anarchism", "title": "Frogs and Love" },
-                    { "author": "Lefty Smith", "genre": "Horror", "title": "Chainsaws for Noobs" }
+                { "author": "Billy Bob", "genre": "Anarchism", "title": "Frogs and Love", "pageCount": 80 },
+                { "author": "Lefty Smith", "genre": "Horror", "title": "Chainsaws for Noobs", "pageCount": 80 }
                 ];
 
         var model = Qt.createQmlObject("import QtQuick 2.0; ListModel {}", theParent);
index 0b873b6..98ade83 100644 (file)
@@ -13,4 +13,3 @@ include (../shared/util.pri)
 TESTDATA = data/*
 
 QT += core-private gui-private qml-private quick-private v8-private testlib
-mac: CONFIG += insignificant_test # QTBUG-26244 (exit crash)
index 92526a0..7dba3a6 100644 (file)
@@ -74,6 +74,7 @@ public:
 
 private slots:
     void init();
+    void cleanupTestCase();
     // Test both QListModelInterface and QAbstractItemModel model types
     void qListModelInterface_items();
     void qListModelInterface_package_items();
@@ -143,7 +144,9 @@ private slots:
     void sectionsDelegate();
     void sectionsDragOutsideBounds_data();
     void sectionsDragOutsideBounds();
+    void sectionsDelegate_headerVisibility();
     void sectionPropertyChange();
+    void sectionDelegateChange();
     void cacheBuffer();
     void positionViewAtIndex();
     void resetModel();
@@ -331,6 +334,15 @@ void tst_QQuickListView::init()
 #endif
 }
 
+void tst_QQuickListView::cleanupTestCase()
+{
+#ifdef SHARE_VIEWS
+    testForView = QString();
+    delete m_view;
+    m_view = 0;
+#endif
+}
+
 template <class T>
 void tst_QQuickListView::items(const QUrl &source, bool forceLayout)
 {
@@ -407,6 +419,9 @@ void tst_QQuickListView::items(const QUrl &source, bool forceLayout)
     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
     QTRY_VERIFY(itemCount == 0);
 
+    QTRY_COMPARE(listview->highlightResizeVelocity(), 1000.0);
+    QTRY_COMPARE(listview->highlightMoveVelocity(), 1000.0);
+
     delete canvas;
     delete testObject;
 }
@@ -2013,8 +2028,6 @@ void tst_QQuickListView::sections(const QUrl &source)
 
 void tst_QQuickListView::sectionsDelegate()
 {
-    QSKIP("QTBUG-24395");
-
     QQuickView *canvas = createView();
 
     QmlListModel model;
@@ -2052,12 +2065,6 @@ void tst_QQuickListView::sectionsDelegate()
         QTRY_COMPARE(item->y(), qreal(i*20*6));
     }
 
-    // ensure section header is maintained in view
-    listview->setCurrentIndex(20);
-    QTRY_VERIFY(listview->contentY() >= 200.0);
-    listview->setCurrentIndex(0);
-    QTRY_COMPARE(listview->contentY(), 0.0);
-
     // change section
     model.modifyItem(0, "One", "aaa");
     model.modifyItem(1, "Two", "aaa");
@@ -2174,6 +2181,39 @@ void tst_QQuickListView::sectionsDragOutsideBounds()
     releaseView(canvas);
 }
 
+void tst_QQuickListView::sectionsDelegate_headerVisibility()
+{
+    QSKIP("QTBUG-24395");
+
+    QQuickView *canvas = createView();
+
+    QmlListModel model;
+    for (int i = 0; i < 30; i++)
+        model.addItem("Item" + QString::number(i), QString::number(i/5));
+
+    canvas->rootContext()->setContextProperty("testModel", &model);
+    canvas->setSource(testFileUrl("listview-sections_delegate.qml"));
+    canvas->show();
+    qApp->processEvents();
+
+    QQuickListView *listview = findItem<QQuickListView>(canvas->rootObject(), "list");
+    QTRY_VERIFY(listview != 0);
+
+    QQuickItem *contentItem = listview->contentItem();
+    QTRY_VERIFY(contentItem != 0);
+    QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+    // ensure section header is maintained in view
+    listview->setCurrentIndex(20);
+    QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+    QTRY_COMPARE(listview->contentY(), 200.0);
+    QTRY_VERIFY(listview->isMoving() == false);
+    listview->setCurrentIndex(0);
+    QTRY_COMPARE(listview->contentY(), 0.0);
+
+    delete canvas;
+}
+
 void tst_QQuickListView::sectionsPositioning()
 {
     QQuickView *canvas = createView();
@@ -2369,6 +2409,66 @@ void tst_QQuickListView::sectionPropertyChange()
         QTRY_COMPARE(item->y(), qreal(25. + i*75.));
     }
 
+    QMetaObject::invokeMethod(canvas->rootObject(), "switchGrouped");
+    QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+    // Confirm items positioned correctly
+    for (int i = 0; i < 2; ++i) {
+        QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+        QTRY_VERIFY(item);
+        QTRY_COMPARE(item->y(), qreal(25. + i*50.));
+    }
+
+    QMetaObject::invokeMethod(canvas->rootObject(), "switchGrouped");
+    QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+    // Confirm items positioned correctly
+    for (int i = 0; i < 2; ++i) {
+        QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+        QTRY_VERIFY(item);
+        QTRY_COMPARE(item->y(), qreal(25. + i*75.));
+    }
+
+    delete canvas;
+}
+
+void tst_QQuickListView::sectionDelegateChange()
+{
+    QQuickView *canvas = createView();
+
+    canvas->setSource(testFileUrl("sectiondelegatechange.qml"));
+    canvas->show();
+    qApp->processEvents();
+
+    QQuickListView *listview = qobject_cast<QQuickListView *>(canvas->rootObject());
+    QVERIFY(listview != 0);
+
+    QQuickItem *contentItem = listview->contentItem();
+    QVERIFY(contentItem != 0);
+
+    QQUICK_VERIFY_POLISH(listview);
+
+    QVERIFY(findItems<QQuickItem>(contentItem, "section1").count() > 0);
+    QCOMPARE(findItems<QQuickItem>(contentItem, "section2").count(), 0);
+
+    for (int i = 0; i < 3; ++i) {
+        QQuickItem *item = findItem<QQuickItem>(contentItem, "item", i);
+        QTRY_VERIFY(item);
+        QTRY_COMPARE(item->y(), qreal(25. + i*50.));
+    }
+
+    QMetaObject::invokeMethod(canvas->rootObject(), "switchDelegates");
+    QQUICK_VERIFY_POLISH(listview);
+
+    QCOMPARE(findItems<QQuickItem>(contentItem, "section1").count(), 0);
+    QVERIFY(findItems<QQuickItem>(contentItem, "section2").count() > 0);
+
+    for (int i = 0; i < 3; ++i) {
+        QQuickItem *item = findItem<QQuickItem>(contentItem, "item", i);
+        QVERIFY(item);
+        QTRY_COMPARE(item->y(), qreal(50. + i*75.));
+    }
+
     delete canvas;
 }
 
@@ -6787,6 +6887,8 @@ void tst_QQuickListView::parentBinding()
     QVERIFY(!m_errorCount);
 
     qInstallMsgHandler(old);
+
+    delete canvas;
 }
 
 QTEST_MAIN(tst_QQuickListView)
diff --git a/tests/auto/quick/qquickloader/data/subdir/Test.qml b/tests/auto/quick/qquickloader/data/subdir/Test.qml
new file mode 100644 (file)
index 0000000..3abbd89
--- /dev/null
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+    id: test
+}
index dfe02c6..dc21af8 100644 (file)
@@ -201,6 +201,10 @@ void tst_QQuickLoader::sourceOrComponent_data()
     QTest::addColumn<QString>("errorString");
 
     QTest::newRow("source") << "source" << "source: 'Rect120x60.qml'\n" << testFileUrl("Rect120x60.qml") << "";
+    QTest::newRow("source with subdir") << "source" << "source: 'subdir/Test.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+    QTest::newRow("source with encoded subdir literal") << "source" << "source: 'subdir%2fTest.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+    QTest::newRow("source with encoded subdir optimized binding") << "source" << "source: 'subdir' + '%2fTest.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+    QTest::newRow("source with encoded subdir binding") << "source" << "source: encodeURIComponent('subdir/Test.qml')\n" << testFileUrl("subdir/Test.qml") << "";
     QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
     QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml")
             << QString(testFileUrl("IDontExist.qml").toString() + ": File not found");
index 7d24de6..2bdf4a9 100644 (file)
@@ -105,6 +105,7 @@ private slots:
     void letterSpacing();
     void wordSpacing();
 
+    void clickLink_data();
     void clickLink();
 
     void implicitSize_data();
@@ -1438,6 +1439,8 @@ public:
             mousePressEvent(event);
         else if (event->type() == QEvent::MouseButtonRelease)
             mouseReleaseEvent(event);
+        else if (event->type() == QEvent::MouseMove)
+            mouseMoveEvent(event);
         else
             qWarning() << "Trying to send unsupported event type";
     }
@@ -1455,36 +1458,339 @@ public slots:
     void linkClicked(QString l) { link = l; }
 };
 
-void tst_qquicktext::clickLink()
+class TextMetrics
 {
+public:
+    TextMetrics(const QString &text, Qt::TextElideMode elideMode = Qt::ElideNone)
     {
-        QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
-        QQmlComponent textComponent(&engine);
-        textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
-        QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
-
-        QVERIFY(textObject != 0);
+        QString adjustedText = text;
+        adjustedText.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator));
+        if (elideMode == Qt::ElideLeft)
+            adjustedText = QChar(0x2026) + adjustedText;
+        else if (elideMode == Qt::ElideRight)
+            adjustedText = adjustedText + QChar(0x2026);
+
+        layout.setText(adjustedText);
+        QTextOption option;
+        option.setUseDesignMetrics(true);
+        layout.setTextOption(option);
 
-        LinkTest test;
-        QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
+        layout.beginLayout();
+        qreal height = 0;
+        QTextLine line = layout.createLine();
+        while (line.isValid()) {
+            line.setLineWidth(FLT_MAX);
+            line.setPosition(QPointF(0, height));
+            height += line.height();
+            line = layout.createLine();
+        }
+        layout.endLayout();
+    }
 
-        {
-            QMouseEvent me(QEvent::MouseButtonPress,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
-            static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+    qreal width() const { return layout.maximumWidth(); }
 
+    QRectF characterRectangle(
+            int position,
+            int hAlign = Qt::AlignLeft,
+            int vAlign = Qt::AlignTop,
+            const QSizeF &bounds = QSizeF(240, 320)) const
+    {
+        qreal dy = 0;
+        switch (vAlign) {
+        case Qt::AlignBottom:
+            dy = bounds.height() - layout.boundingRect().height();
+            break;
+        case Qt::AlignVCenter:
+            dy = (bounds.height() - layout.boundingRect().height()) / 2;
+            break;
+        default:
+            break;
         }
 
-        {
-            QMouseEvent me(QEvent::MouseButtonRelease,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
-            static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+        for (int i = 0; i < layout.lineCount(); ++i) {
+            QTextLine line = layout.lineAt(i);
+            if (position >= line.textStart() + line.textLength())
+                continue;
+            qreal dx = 0;
+            switch (hAlign) {
+            case Qt::AlignRight:
+                dx = bounds.width() - line.naturalTextWidth();
+                break;
+            case Qt::AlignHCenter:
+                dx = (bounds.width() - line.naturalTextWidth()) / 2;
+                break;
+            default:
+                break;
+            }
 
+            QRectF rect;
+            rect.setLeft(dx + line.cursorToX(position, QTextLine::Leading));
+            rect.setRight(dx + line.cursorToX(position, QTextLine::Trailing));
+            rect.setTop(dy + line.y());
+            rect.setBottom(dy + line.y() + line.height());
+
+            return rect;
         }
+        return QRectF();
+    }
 
+    QTextLayout layout;
+};
 
-        QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
 
-        delete textObject;
+typedef QVector<QPointF> PointVector;
+Q_DECLARE_METATYPE(PointVector);
+
+void tst_qquicktext::clickLink_data()
+{
+    QTest::addColumn<QString>("text");
+    QTest::addColumn<qreal>("width");
+    QTest::addColumn<QString>("bindings");
+    QTest::addColumn<PointVector>("mousePositions");
+    QTest::addColumn<QString>("link");
+
+    const QString singleLineText = "this text has a <a href=\\\"http://qt-project.org/single\\\">link</a> in it";
+    const QString singleLineLink = "http://qt-project.org/single";
+    const QString multipleLineText = "this text<br/>has <a href=\\\"http://qt-project.org/multiple\\\">multiple<br/>lines</a> in it";
+    const QString multipleLineLink = "http://qt-project.org/multiple";
+    const QString nestedText = "this text has a <a href=\\\"http://qt-project.org/outer\\\">nested <a href=\\\"http://qt-project.org/inner\\\">link</a> in it</a>";
+    const QString outerLink = "http://qt-project.org/outer";
+    const QString innerLink = "http://qt-project.org/inner";
+
+    {
+        const TextMetrics metrics("this text has a link in it");
+
+        QTest::newRow("click on link")
+                << singleLineText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(18).center())
+                << singleLineLink;
+        QTest::newRow("click on text")
+                << singleLineText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(13).center())
+                << QString();
+        QTest::newRow("drag within link")
+                << singleLineText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(17).center()
+                    << metrics.characterRectangle(19).center())
+                << singleLineLink;
+        QTest::newRow("drag away from link")
+                << singleLineText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(18).center()
+                    << metrics.characterRectangle(13).center())
+                << QString();
+        QTest::newRow("drag on to link")
+                << singleLineText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(13).center()
+                    << metrics.characterRectangle(18).center())
+                << QString();
+        QTest::newRow("click on bottom right aligned link")
+                << singleLineText << 240.
+                << "horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
+                << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
+                << singleLineLink;
+        QTest::newRow("click on center aligned link")
+                << singleLineText << 240.
+                << "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
+                << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
+                << singleLineLink;
+        QTest::newRow("click on rich text link")
+                << singleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(18).center())
+                << singleLineLink;
+        QTest::newRow("click on rich text")
+                << singleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(13).center())
+                << QString();
+        QTest::newRow("click on bottom right aligned rich text link")
+                << singleLineText << 240.
+                << "textFormat: Text.RichText; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
+                << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
+                << singleLineLink;
+        QTest::newRow("click on center aligned rich text link")
+                << singleLineText << 240.
+                << "textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
+                << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
+                << singleLineLink;
+    } {
+        const TextMetrics metrics("this text has a li", Qt::ElideRight);
+        QTest::newRow("click on right elided link")
+                << singleLineText << metrics.width() +  2
+                << "elide: Text.ElideRight"
+                << (PointVector() << metrics.characterRectangle(17).center())
+                << singleLineLink;
+    } {
+        const TextMetrics metrics("ink in it", Qt::ElideLeft);
+        QTest::newRow("click on left elided link")
+                << singleLineText << metrics.width() +  2
+                << "elide: Text.ElideLeft"
+                << (PointVector() << metrics.characterRectangle(2).center())
+                << singleLineLink;
+    } {
+        const TextMetrics metrics("this text\nhas multiple\nlines in it");
+        QTest::newRow("click on second line")
+                << multipleLineText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(18).center())
+                << multipleLineLink;
+        QTest::newRow("click on third line")
+                << multipleLineText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(25).center())
+                << multipleLineLink;
+        QTest::newRow("drag from second line to third")
+                << multipleLineText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(18).center()
+                    << metrics.characterRectangle(25).center())
+                << multipleLineLink;
+        QTest::newRow("click on rich text second line")
+                << multipleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(18).center())
+                << multipleLineLink;
+        QTest::newRow("click on rich text third line")
+                << multipleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(25).center())
+                << multipleLineLink;
+        QTest::newRow("drag rich text from second line to third")
+                << multipleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector()
+                    << metrics.characterRectangle(18).center()
+                    << metrics.characterRectangle(25).center())
+                << multipleLineLink;
+    } {
+        const TextMetrics metrics("this text has a nested link in it");
+        QTest::newRow("click on left outer link")
+                << nestedText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(22).center())
+                << outerLink;
+        QTest::newRow("click on right outer link")
+                << nestedText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(27).center())
+                << outerLink;
+        QTest::newRow("click on inner link left")
+                << nestedText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(23).center())
+                << innerLink;
+        QTest::newRow("click on inner link right")
+                << nestedText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(26).center())
+                << innerLink;
+        QTest::newRow("drag from inner to outer link")
+                << nestedText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(25).center()
+                    << metrics.characterRectangle(30).center())
+                << QString();
+        QTest::newRow("drag from outer to inner link")
+                << nestedText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(30).center()
+                    << metrics.characterRectangle(25).center())
+                << QString();
+        QTest::newRow("click on left outer rich text link")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(22).center())
+                << outerLink;
+        QTest::newRow("click on right outer rich text link")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(27).center())
+                << outerLink;
+        QTest::newRow("click on inner rich text link left")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(23).center())
+                << innerLink;
+        QTest::newRow("click on inner rich text link right")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(26).center())
+                << innerLink;
+        QTest::newRow("drag from inner to outer rich text link")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector()
+                    << metrics.characterRectangle(25).center()
+                    << metrics.characterRectangle(30).center())
+                << QString();
+        QTest::newRow("drag from outer to inner rich text link")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector()
+                    << metrics.characterRectangle(30).center()
+                    << metrics.characterRectangle(25).center())
+                << QString();
+    }
+}
+
+void tst_qquicktext::clickLink()
+{
+    QFETCH(QString, text);
+    QFETCH(qreal, width);
+    QFETCH(QString, bindings);
+    QFETCH(PointVector, mousePositions);
+    QFETCH(QString, link);
+
+    QString componentStr =
+            "import QtQuick 2.0\nText {\n"
+                "width: " + QString::number(width) + "\n"
+                "height: 320\n"
+                "text: \"" + text + "\"\n"
+                "" + bindings + "\n"
+            "}";
+    QQmlComponent textComponent(&engine);
+    textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+    QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+
+    QVERIFY(textObject != 0);
+
+    LinkTest test;
+    QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
+
+    QVERIFY(mousePositions.count() > 0);
+
+    QPointF mousePosition = mousePositions.first();
+    {
+        QMouseEvent me(QEvent::MouseButtonPress, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+        static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
     }
+
+    for (int i = 1; i < mousePositions.count(); ++i) {
+        mousePosition = mousePositions.at(i);
+
+        QMouseEvent me(QEvent::MouseMove, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+        static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+    }
+
+    {
+        QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+        static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+    }
+
+    QCOMPARE(test.link, link);
+
+    delete textObject;
 }
 
 void tst_qquicktext::baseUrl()
index d14caea..cf09250 100644 (file)
@@ -16,7 +16,9 @@ Rectangle {
         TextInput {
             id: text
             objectName: "text"
-            anchors.fill: parent
+            anchors.left: parent.left
+            anchors.top: parent.top
+            width: 180
             text: top.text
             focus: true
 
index 5044f48..a87cbeb 100644 (file)
@@ -1441,6 +1441,11 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft()
     QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignLeft);
     platformInputContext.setInputDirection(Qt::RightToLeft);
     QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignRight);
+
+    // changing width keeps right aligned cursor on proper position
+    textInput->setText("");
+    textInput->setWidth(500);
+    QVERIFY(textInput->positionToRectangle(0).x() > textInput->width() / 2);
 }
 
 void tst_qquicktextinput::verticalAlignment()
index 54713fc..0aa64ce 100644 (file)
@@ -410,57 +410,54 @@ int main(int argc, char ** argv)
         displayFileDialog(&options);
 #endif
 
-    QWindow *window = 0;
     QQmlEngine *engine = 0;
 
     int exitCode = 0;
 
     if (!options.file.isEmpty()) {
         if (!options.versionDetection || checkVersion(options.file)) {
-            QQuickView *qxView = new QQuickView();
-            engine = qxView->engine();
+            QQuickView qxView;
+            engine = qxView.engine();
             for (int i = 0; i < imports.size(); ++i)
                 engine->addImportPath(imports.at(i));
             for (int i = 0; i < bundles.size(); ++i)
                 engine->addNamedBundle(bundles.at(i).first, bundles.at(i).second);
-            window = qxView;
             if (options.file.isLocalFile()) {
                 QFileInfo fi(options.file.toLocalFile());
                 loadDummyDataFiles(*engine, fi.path());
             }
-            qxView->setSource(options.file);
+            qxView.setSource(options.file);
 
             QObject::connect(engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
 
             if (options.resizeViewToRootItem)
-                qxView->setResizeMode(QQuickView::SizeViewToRootObject);
+                qxView.setResizeMode(QQuickView::SizeViewToRootObject);
             else
-                qxView->setResizeMode(QQuickView::SizeRootObjectToView);
+                qxView.setResizeMode(QQuickView::SizeRootObjectToView);
 
             if (options.transparent) {
                 QSurfaceFormat surfaceFormat;
                 surfaceFormat.setAlphaBufferSize(8);
-                qxView->setFormat(surfaceFormat);
-                qxView->setClearBeforeRendering(true);
-                qxView->setClearColor(QColor(Qt::transparent));
-                qxView->setWindowFlags(Qt::FramelessWindowHint);
+                qxView.setFormat(surfaceFormat);
+                qxView.setClearBeforeRendering(true);
+                qxView.setClearColor(QColor(Qt::transparent));
+                qxView.setWindowFlags(Qt::FramelessWindowHint);
             }
 
-            window->setWindowFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
+            qxView.setWindowFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
+
             if (options.fullscreen)
-                window->showFullScreen();
+                qxView.showFullScreen();
             else if (options.maximized)
-                window->showMaximized();
+                qxView.showMaximized();
             else
-                window->show();
+                qxView.show();
 
             if (options.quitImmediately)
                 QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
 
             exitCode = app.exec();
 
-            delete window;
-
 #ifdef QML_RUNTIME_TESTING
             RenderStatistics::printTotalStats();
 #endif