diff options
77 files changed, 1618 insertions, 306 deletions
diff --git a/doc/src/qml/qtdeclarative.qdoc b/doc/src/qml/qtdeclarative.qdoc index 20d1c40d66..48cc898458 100644 --- a/doc/src/qml/qtdeclarative.qdoc +++ b/doc/src/qml/qtdeclarative.qdoc @@ -27,10 +27,10 @@ /*! \module QtQml - \title Qt Declarative Module + \title Qt Qml Module \ingroup modules - \brief The Qt Declarative module provides a declarative framework + \brief The Qt Qml module provides a declarative framework for building highly dynamic, custom user interfaces. To include the definitions of the module's classes, use the @@ -44,10 +44,11 @@ .pro file: \code - QT += declarative + QT += qml \endcode - For more information on the Qt Declarative module, see the + For more information on the Qt Qml module (including the visual + elements which are implemented on top of the Qt Qml module) see the \l{Qt Quick} documentation. */ @@ -278,7 +279,16 @@ */ /*! + \internal \fn int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, QObject *(*callback)(QQmlEngine *, QJSEngine *)) + \deprecated + + Any uses of a module API in a binding where that module API was registered with this + function instead of the template version will result in suboptimal binding generation. + */ + +/*! + \fn template<typename T> int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, QObject *(*callback)(QQmlEngine *, QJSEngine *)) \relates QQmlEngine This function may be used to register a module API provider \a callback in a particular \a uri @@ -289,13 +299,18 @@ A module API may be either a QObject or a QJSValue. Only one module API provider may be registered into any given namespace (combination of \a uri, \a versionMajor and \a versionMinor). - This function should be used to register a module API provider function which returns a QObject as a module API. + This function should be used to register a module API provider function which returns a QObject + of the given type T as a module API. A QObject module API must be imported with a qualifier, and that qualifier may be used as the target in a \l Connections element or otherwise used as any other element id would. One exception to this is that a QObject module API property may not be aliased (because the module API qualifier does not identify an object within the same component as any other item). + \b{NOTE:} A QObject module API instance returned from a module API provider is owned by the QML + engine. For this reason, the module API provider function should \b{not} be implemented as a + singleton factory. + Usage: \code // first, define your QObject which provides the functionality. diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 0187d06e6a..4f08e71fd0 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -661,7 +661,7 @@ public: void registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == "QtQuick.LocalStorage"); - qmlRegisterModuleApi(uri, 2, 0, module_api_factory); + qmlRegisterModuleApi<QQuickLocalStorage>(uri, 2, 0, module_api_factory); } }; diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.cpp b/src/plugins/accessible/quick/qaccessiblequickitem.cpp index 45db9fa795..d282b04eaf 100644 --- a/src/plugins/accessible/quick/qaccessiblequickitem.cpp +++ b/src/plugins/accessible/quick/qaccessiblequickitem.cpp @@ -135,7 +135,14 @@ QList<QQuickItem *> QAccessibleQuickItem::childItems() const role() == QAccessible::PageTab || role() == QAccessible::ProgressBar) return QList<QQuickItem *>(); - return item()->childItems(); + + QList<QQuickItem *> items; + Q_FOREACH (QQuickItem *child, item()->childItems()) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(child); + if (itemPrivate->isAccessible) + items.append(child); + } + return items; } QAccessible::State QAccessibleQuickItem::state() const diff --git a/src/plugins/accessible/quick/qaccessiblequickview.cpp b/src/plugins/accessible/quick/qaccessiblequickview.cpp index 1823dfea42..2df1f243b8 100644 --- a/src/plugins/accessible/quick/qaccessiblequickview.cpp +++ b/src/plugins/accessible/quick/qaccessiblequickview.cpp @@ -41,6 +41,8 @@ #include "qaccessiblequickview.h" +#include <QtGui/qguiapplication.h> + #include <QtQuick/qquickitem.h> #include <QtQuick/private/qquickitem_p.h> @@ -83,7 +85,12 @@ QAccessible::Role QAccessibleQuickView::role() const QAccessible::State QAccessibleQuickView::state() const { - return QAccessible::State(); // FIXME + QAccessible::State st; + if (view() == QGuiApplication::focusWindow()) + st.active = true; + if (!view()->isVisible()) + st.invisible = true; + return st; } QRect QAccessibleQuickView::rect() const @@ -120,7 +127,7 @@ static QQuickItem *childAt_helper(QQuickItem *item, int x, int y) } QScopedPointer<QAccessibleInterface> accessibleInterface(QAccessible::queryAccessibleInterface(item)); - if (accessibleInterface->childCount() == 0) { + if (accessibleInterface && accessibleInterface->childCount() == 0) { return (itemScreenRect(item).contains(x, y)) ? item : 0; } diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro b/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro index 2d4de57540..33bda11dcc 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro @@ -15,7 +15,8 @@ SOURCES += \ selectiontool.cpp \ qquickviewinspector.cpp \ ../shared/abstracttool.cpp \ - ../shared/abstractviewinspector.cpp + ../shared/abstractviewinspector.cpp \ + zoomtool.cpp HEADERS += \ qtquick2plugin.h \ @@ -25,7 +26,8 @@ HEADERS += \ ../shared/abstracttool.h \ ../shared/abstractviewinspector.h \ ../shared/qqmlinspectorprotocol.h \ - ../shared/qmlinspectorconstants.h + ../shared/qmlinspectorconstants.h \ + zoomtool.h OTHER_FILES += qtquick2plugin.json diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp index 200c66ee35..0a73540b40 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp @@ -44,6 +44,7 @@ #include "qqmlinspectorprotocol.h" #include "highlight.h" #include "selectiontool.h" +#include "zoomtool.h" #include <QtQuick/private/qquickitem_p.h> @@ -120,6 +121,7 @@ QQuickViewInspector::QQuickViewInspector(QQuickView *view, QObject *parent) : m_view(view), m_overlay(new QQuickItem), m_selectionTool(new SelectionTool(this)), + m_zoomTool(0), m_designMode(true) { // Try to make sure the overlay is always on top @@ -176,7 +178,9 @@ void QQuickViewInspector::changeTool(InspectorProtocol::Tool tool) emit selectToolActivated(); break; case InspectorProtocol::ZoomTool: - // TODO + if (!m_zoomTool) + m_zoomTool = new ZoomTool(this, m_view); + setCurrentTool(m_zoomTool); emit zoomToolActivated(); break; } diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h index fbc3c17b87..e8fdf351de 100644 --- a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h @@ -57,6 +57,7 @@ namespace QtQuick2 { class SelectionTool; class SelectionHighlight; +class ZoomTool; class QQuickViewInspector : public AbstractViewInspector { @@ -99,6 +100,7 @@ private: QQuickItem *m_overlay; SelectionTool *m_selectionTool; + ZoomTool *m_zoomTool; QList<QWeakPointer<QQuickItem> > m_selectedItems; QHash<QQuickItem*, SelectionHighlight*> m_highlightItems; diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.cpp new file mode 100644 index 0000000000..171f1a52e9 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "zoomtool.h" +#include "qquickviewinspector.h" + +#include <QtCore/QLineF> +#include <QtGui/QMouseEvent> +#include <QtGui/QWheelEvent> +#include <QtGui/QTouchEvent> +#include <QtGui/QKeyEvent> + +#include <QtQuick/QQuickView> +#include <QtQuick/QQuickItem> + +namespace QmlJSDebugger { +namespace QtQuick2 { + +ZoomTool::ZoomTool(QQuickViewInspector *inspector, QQuickView *view) : + AbstractTool(inspector), + m_dragStarted(false), + m_pinchStarted(false), + m_currentScale(1.0f), + m_smoothScaleFactor(0.05f), + m_minScale(0.125f), + m_maxScale(48.0f), + m_tapScaleCounter(0) +{ + m_rootItem = view->rootItem(); + m_originalSmooth = m_rootItem->smooth(); + if (!m_originalSmooth) + m_rootItem->setSmooth(true); + m_originalPosition = m_rootItem->pos(); + m_originalScale = m_rootItem->scale(); +} + +ZoomTool::~ZoomTool() +{ + // restoring the original states. + m_rootItem->setScale(m_originalScale); + m_rootItem->setPos(m_originalPosition); + if (!m_originalSmooth) + m_rootItem->setSmooth(m_originalSmooth); +} + +void ZoomTool::mousePressEvent(QMouseEvent *event) +{ + m_mousePosition = event->posF(); + if (event->buttons() & Qt::LeftButton) { + m_dragStartPosition = event->posF(); + m_dragStarted = false; + } +} + +void ZoomTool::mouseMoveEvent(QMouseEvent *event) +{ + if (m_pinchStarted) + return; + + m_mousePosition = event->posF(); + if (!m_dragStarted + && event->buttons() & Qt::LeftButton + && ((m_dragStartPosition - event->posF()).manhattanLength() + > Constants::DragStartDistance)) { + m_dragStarted = true; + } + if (m_dragStarted) { + m_adjustedOrigin += event->posF() - m_dragStartPosition; + m_dragStartPosition = event->posF(); + m_rootItem->setPos(m_adjustedOrigin); + } +} + +void ZoomTool::hoverMoveEvent(QMouseEvent *event) +{ + m_mousePosition = event->posF(); +} + +void ZoomTool::wheelEvent(QWheelEvent *event) +{ + if (event->orientation() != Qt::Vertical) + return; + + Qt::KeyboardModifier smoothZoomModifier = Qt::ControlModifier; + if (event->modifiers() & smoothZoomModifier) { + int numDegrees = event->delta() / 8; + qreal newScale = m_currentScale + m_smoothScaleFactor * (numDegrees / 15.0f); + scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition); + } else if (!event->modifiers()) { + if (event->delta() > 0) { + zoomIn(); + } else if (event->delta() < 0) { + zoomOut(); + } + } +} + +void ZoomTool::mouseDoubleClickEvent(QMouseEvent *event) +{ + m_mousePosition = event->posF(); + zoomTo100(); +} + +void ZoomTool::keyReleaseEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_Plus: + zoomIn(); + break; + case Qt::Key_Minus: + zoomOut(); + break; + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: + case Qt::Key_9: { + qreal newScale = ((event->key() - Qt::Key_0) * 1.0f); + scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition); + break; + } + default: + break; + } +} + +void ZoomTool::touchEvent(QTouchEvent *event) +{ + QList<QTouchEvent::TouchPoint> touchPoints = event->touchPoints(); + + switch (event->type()) { + case QEvent::TouchBegin: + // fall through.. + case QEvent::TouchUpdate: { + if ((touchPoints.count() == 2) + && (!(event->touchPointStates() & Qt::TouchPointReleased))) { + // determine scale factor + const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first(); + const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last(); + + qreal touchScaleFactor = + QLineF(touchPoint0.pos(), touchPoint1.pos()).length() + / QLineF(touchPoint0.lastPos(), touchPoint1.lastPos()).length(); + + QPointF oldcenter = (touchPoint0.lastPos() + touchPoint1.lastPos()) / 2; + QPointF newcenter = (touchPoint0.pos() + touchPoint1.pos()) / 2; + + m_pinchStarted = true; + m_tapScaleCounter = 0; + scaleView(touchScaleFactor, newcenter, oldcenter); + } + break; + } + case QEvent::TouchEnd: { + if (m_pinchStarted) { + m_pinchStarted = false; + } else if ((touchPoints.count() == 1) + &&(!m_dragStarted)) { + ++m_tapScaleCounter; + qreal factor = 1.0f + (1.0f / (m_tapScaleCounter + 1)); + scaleView(factor, touchPoints.first().pos(), + touchPoints.first().pos()); + } + break; + } + default: + break; + } +} + +void ZoomTool::scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter) +{ + if (((m_currentScale * factor) > m_maxScale) + || ((m_currentScale * factor) < m_minScale)) { + return; + } + //New position = new center + scalefactor * (oldposition - oldcenter) + m_adjustedOrigin = newcenter + (factor * (m_adjustedOrigin - oldcenter)); + m_currentScale *= factor; + + m_rootItem->setScale(m_currentScale); + m_rootItem->setPos(m_adjustedOrigin); +} + +void ZoomTool::zoomIn() +{ + qreal newScale = nextZoomScale(ZoomIn); + scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition); +} + +void ZoomTool::zoomOut() +{ + qreal newScale = nextZoomScale(ZoomOut); + scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition); +} + +void ZoomTool::zoomTo100() +{ + m_currentScale = 1.0; + m_adjustedOrigin = QPointF(0, 0); + m_tapScaleCounter = 0; + + m_rootItem->setPos(m_adjustedOrigin); + m_rootItem->setScale(m_currentScale); +} + +qreal ZoomTool::nextZoomScale(ZoomDirection direction) +{ + static QList<qreal> zoomScales = + QList<qreal>() + << 0.125f + << 1.0f / 6.0f + << 0.25f + << 1.0f / 3.0f + << 0.5f + << 2.0f / 3.0f + << 1.0f + << 2.0f + << 3.0f + << 4.0f + << 5.0f + << 6.0f + << 7.0f + << 8.0f + << 12.0f + << 16.0f + << 32.0f + << 48.0f; + + if (direction == ZoomIn) { + for (int i = 0; i < zoomScales.length(); ++i) { + if (zoomScales[i] > m_currentScale) + return zoomScales[i]; + } + return zoomScales.last(); + } else { + for (int i = zoomScales.length() - 1; i >= 0; --i) { + if (zoomScales[i] < m_currentScale) + return zoomScales[i]; + } + return zoomScales.first(); + } + + return 1.0f; +} + +} // namespace QtQuick2 +} // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.h b/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.h new file mode 100644 index 0000000000..02ed8e09df --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ZOOMTOOL_H +#define ZOOMTOOL_H + +#include "abstracttool.h" + +#include <QtCore/QPointF> + +QT_FORWARD_DECLARE_CLASS(QQuickView) +QT_FORWARD_DECLARE_CLASS(QQuickItem) + +namespace QmlJSDebugger { +namespace QtQuick2 { + +class QQuickViewInspector; + +class ZoomTool : public AbstractTool +{ + Q_OBJECT + +public: + enum ZoomDirection { + ZoomIn, + ZoomOut + }; + + explicit ZoomTool(QQuickViewInspector *inspector, QQuickView *view); + virtual ~ZoomTool(); + void leaveEvent(QEvent *) {} + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *) {} + void mouseDoubleClickEvent(QMouseEvent *event); + + void hoverMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + + void keyPressEvent(QKeyEvent *) {} + void keyReleaseEvent(QKeyEvent *event); + + void touchEvent(QTouchEvent *event); + +private: + qreal nextZoomScale(ZoomDirection direction); + void scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter); + void zoomTo100(); + void zoomIn(); + void zoomOut(); + +private: + bool m_originalSmooth; + bool m_dragStarted; + bool m_pinchStarted; + QQuickItem *m_rootItem; + QPointF m_adjustedOrigin; + QPointF m_dragStartPosition; + QPointF m_mousePosition; + QPointF m_originalPosition; + qreal m_currentScale; + qreal m_smoothScaleFactor; + qreal m_minScale; + qreal m_maxScale; + qreal m_tapScaleCounter; + qreal m_originalScale; +}; + +} // namespace QtQuick2 +} // namespace QmlJSDebugger + +#endif // ZOOMTOOL_H diff --git a/src/plugins/qmltooling/shared/abstracttool.h b/src/plugins/qmltooling/shared/abstracttool.h index 35817064e2..7e5ba65fd4 100644 --- a/src/plugins/qmltooling/shared/abstracttool.h +++ b/src/plugins/qmltooling/shared/abstracttool.h @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE class QMouseEvent; class QKeyEvent; class QWheelEvent; +class QTouchEvent; QT_END_NAMESPACE namespace QmlJSDebugger { @@ -76,6 +77,8 @@ public: virtual void keyPressEvent(QKeyEvent *event) = 0; virtual void keyReleaseEvent(QKeyEvent *keyEvent) = 0; + virtual void touchEvent(QTouchEvent *) {} + private: AbstractViewInspector *m_inspector; }; diff --git a/src/plugins/qmltooling/shared/abstractviewinspector.cpp b/src/plugins/qmltooling/shared/abstractviewinspector.cpp index 33e47d270d..135da1b8b7 100644 --- a/src/plugins/qmltooling/shared/abstractviewinspector.cpp +++ b/src/plugins/qmltooling/shared/abstractviewinspector.cpp @@ -50,6 +50,7 @@ #include <QtQml/private/qqmlinspectorservice_p.h> #include <QtGui/QMouseEvent> +#include <QtGui/QTouchEvent> namespace QmlJSDebugger { @@ -220,6 +221,12 @@ bool AbstractViewInspector::eventFilter(QObject *obj, QEvent *event) if (wheelEvent(static_cast<QWheelEvent*>(event))) return true; break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + if (touchEvent(static_cast<QTouchEvent*>(event))) + return true; + break; default: break; } @@ -300,6 +307,12 @@ bool AbstractViewInspector::wheelEvent(QWheelEvent *event) return true; } +bool AbstractViewInspector::touchEvent(QTouchEvent *event) +{ + m_currentTool->touchEvent(event); + return true; +} + void AbstractViewInspector::handleMessage(const QByteArray &message) { QDataStream ds(message); diff --git a/src/plugins/qmltooling/shared/abstractviewinspector.h b/src/plugins/qmltooling/shared/abstractviewinspector.h index 0dacc92233..04ca02917e 100644 --- a/src/plugins/qmltooling/shared/abstractviewinspector.h +++ b/src/plugins/qmltooling/shared/abstractviewinspector.h @@ -56,6 +56,8 @@ class QQmlInspectorService; class QKeyEvent; class QMouseEvent; class QWheelEvent; +class QTouchEvent; + QT_END_NAMESPACE namespace QmlJSDebugger { @@ -128,6 +130,7 @@ protected: virtual bool keyReleaseEvent(QKeyEvent *keyEvent); virtual bool mouseDoubleClickEvent(QMouseEvent *event); virtual bool wheelEvent(QWheelEvent *event); + virtual bool touchEvent(QTouchEvent *event); private slots: void sendColorChanged(const QColor &color); diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h index 8036032150..318e0bd71f 100644 --- a/src/qml/debugger/qqmldebug.h +++ b/src/qml/debugger/qqmldebug.h @@ -51,12 +51,14 @@ QT_BEGIN_NAMESPACE struct Q_QML_EXPORT QQmlDebuggingEnabler { - QQmlDebuggingEnabler(); + QQmlDebuggingEnabler(bool printWarning = true); }; // Execute code in constructor before first QQmlEngine is instantiated -#if defined(QT_DECLARATIVE_DEBUG) -static QQmlDebuggingEnabler qmlEnableDebuggingHelper; +#if defined(QT_DECLARATIVE_DEBUG_NO_WARNING) +static QQmlDebuggingEnabler qmlEnableDebuggingHelper(false); +#elif defined(QT_DECLARATIVE_DEBUG) +static QQmlDebuggingEnabler qmlEnableDebuggingHelper(true); #endif QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp index 7f0bf7ca33..cd09b69e48 100644 --- a/src/qml/debugger/qqmlenginedebugservice.cpp +++ b/src/qml/debugger/qqmlenginedebugservice.cpp @@ -223,7 +223,7 @@ void QQmlEngineDebugService::buildObjectDump(QDataStream &message, int childrenCount = children.count(); for (int ii = 0; ii < children.count(); ++ii) { - if (qobject_cast<QQmlContext*>(children[ii]) || QQmlBoundSignal::cast(children[ii])) + if (qobject_cast<QQmlContext*>(children[ii])) --childrenCount; } @@ -235,19 +235,41 @@ void QQmlEngineDebugService::buildObjectDump(QDataStream &message, QObject *child = children.at(ii); if (qobject_cast<QQmlContext*>(child)) continue; - QQmlBoundSignal *signal = QQmlBoundSignal::cast(child); - if (signal) { - if (!dumpProperties) + if (recur) + buildObjectDump(message, child, recur, dumpProperties); + else + message << objectData(child); + } + + if (!dumpProperties) { + message << 0; + return; + } + + QList<int> propertyIndexes; + for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) { + if (object->metaObject()->property(ii).isScriptable()) + propertyIndexes << ii; + } + + QQmlData *ddata = QQmlData::get(object); + if (ddata && ddata->signalHandlers) { + QQmlAbstractBoundSignal *signalHandler = ddata->signalHandlers; + + while (signalHandler) { + if (!dumpProperties) { + signalHandler = signalHandler->m_nextSignal; continue; + } QQmlObjectProperty prop; prop.type = QQmlObjectProperty::SignalProperty; prop.hasNotifySignal = false; - QQmlExpression *expr = signal->expression(); + QQmlExpression *expr = signalHandler->expression(); if (expr) { prop.value = expr->expression(); QObject *scope = expr->scopeObject(); if (scope) { - QString methodName = QString::fromLatin1(scope->metaObject()->method(signal->index()).name()); + QString methodName = QString::fromLatin1(scope->metaObject()->method(signalHandler->index()).name()); if (!methodName.isEmpty()) { prop.name = QLatin1String("on") + methodName[0].toUpper() + methodName.mid(1); @@ -255,23 +277,9 @@ void QQmlEngineDebugService::buildObjectDump(QDataStream &message, } } fakeProperties << prop; - } else { - if (recur) - buildObjectDump(message, child, recur, dumpProperties); - else - message << objectData(child); - } - } - if (!dumpProperties) { - message << 0; - return; - } - - QList<int> propertyIndexes; - for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) { - if (object->metaObject()->property(ii).isScriptable()) - propertyIndexes << ii; + signalHandler = signalHandler->m_nextSignal; + } } message << propertyIndexes.size() + fakeProperties.count(); diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index 2b4cafb615..2e351792cc 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -205,16 +205,16 @@ struct QQmlHandlingSignalProfiler { { enabled = QQmlProfilerService::instance ? QQmlProfilerService::instance->profilingEnabled() : false; - if (enabled) { - QQmlProfilerService *service = QQmlProfilerService::instance; - service->startRange(QQmlProfilerService::HandlingSignal); - service->rangeData(QQmlProfilerService::HandlingSignal, - QString::fromLatin1(signal.methodSignature()) + QLatin1String(": ") - + expression->expression()); - service->rangeLocation(QQmlProfilerService::HandlingSignal, - expression->sourceFile(), expression->lineNumber(), - expression->columnNumber()); - } + if (enabled) + init(signal, expression); + } + + QQmlHandlingSignalProfiler(QObject *object, int index, QQmlExpression *expression) + { + enabled = QQmlProfilerService::instance + ? QQmlProfilerService::instance->profilingEnabled() : false; + if (enabled) + init(object->metaObject()->method(index), expression); } ~QQmlHandlingSignalProfiler() @@ -224,6 +224,19 @@ struct QQmlHandlingSignalProfiler { } bool enabled; + +private: + void init(const QMetaMethod &signal, QQmlExpression *expression) + { + QQmlProfilerService *service = QQmlProfilerService::instance; + service->startRange(QQmlProfilerService::HandlingSignal); + service->rangeData(QQmlProfilerService::HandlingSignal, + QString::fromLatin1(signal.methodSignature()) + QLatin1String(": ") + + expression->expression()); + service->rangeLocation(QQmlProfilerService::HandlingSignal, + expression->sourceFile(), expression->lineNumber(), + expression->columnNumber()); + } }; struct QQmlObjectCreatingProfiler { diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 32da2c616e..5b500e0814 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -421,7 +421,7 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi uri, versionMajor, versionMinor, - callback, 0 + callback, 0, 0 }; return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api); @@ -435,7 +435,22 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi uri, versionMajor, versionMinor, - 0, callback + 0, callback, 0 // unknown QObject instance type + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api); +} + +template <typename T> +inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, + QObject *(*callback)(QQmlEngine *, QJSEngine *)) +{ + QQmlPrivate::RegisterModuleApi api = { + 1, + + uri, versionMajor, versionMinor, + + 0, callback, &T::staticMetaObject }; return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api); diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index f7d0c00a5c..3a3bf403e6 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -55,6 +55,8 @@ #include <QtCore/qstringbuilder.h> #include <QtCore/qdebug.h> +Q_DECLARE_METATYPE(QJSValue) + QT_BEGIN_NAMESPACE class QQmlBoundSignalParameters : public QObject @@ -87,42 +89,45 @@ private: static int evaluateIdx = -1; -QQmlAbstractBoundSignal::QQmlAbstractBoundSignal(QObject *parent) -: QObject(parent) +QQmlAbstractBoundSignal::QQmlAbstractBoundSignal() +: m_prevSignal(0), m_nextSignal(0) { } QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal() { + if (m_prevSignal) { + *m_prevSignal = m_nextSignal; + if (m_nextSignal) m_nextSignal->m_prevSignal = m_prevSignal; + m_prevSignal = 0; + m_nextSignal = 0; + } } -QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, - QObject *parent) -: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0) +void QQmlAbstractBoundSignal::addToObject() { - // This is thread safe. Although it may be updated by two threads, they - // will both set it to the same value - so the worst thing that can happen - // is that they both do the work to figure it out. Boo hoo. - if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); + Q_ASSERT(!m_prevSignal); + QObject *obj = object(); + Q_ASSERT(obj); - QQml_setParent_noEvent(this, parent); - QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx); + QQmlData *data = QQmlData::get(obj, true); + + m_nextSignal = data->signalHandlers; + if (m_nextSignal) m_nextSignal->m_prevSignal = &m_nextSignal; + m_prevSignal = &data->signalHandlers; + data->signalHandlers = this; } -QQmlBoundSignal::QQmlBoundSignal(QQmlContext *ctxt, const QString &val, - QObject *scope, const QMetaMethod &signal, - QObject *parent) -: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0) +QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, + QObject *owner) +: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0), m_owner(owner) { // This is thread safe. Although it may be updated by two threads, they // will both set it to the same value - so the worst thing that can happen // is that they both do the work to figure it out. Boo hoo. if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); - QQml_setParent_noEvent(this, parent); QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx); - - m_expression = new QQmlExpression(ctxt, scope, val); } QQmlBoundSignal::~QQmlBoundSignal() @@ -159,12 +164,6 @@ QQmlExpression *QQmlBoundSignal::setExpression(QQmlExpression *e) return rv; } -QQmlBoundSignal *QQmlBoundSignal::cast(QObject *o) -{ - QQmlAbstractBoundSignal *s = qobject_cast<QQmlAbstractBoundSignal*>(o); - return static_cast<QQmlBoundSignal *>(s); -} - int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) { if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) { @@ -227,10 +226,14 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method, prop.setWritable(false); } else { QByteArray propType = type; - if ((QMetaType::typeFlags(t) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) { + QMetaType::TypeFlags flags = QMetaType::typeFlags(t); + if (flags & QMetaType::IsEnumeration) { t = QVariant::Int; propType = "int"; - } else if (t == QMetaType::UnknownType) { + } else if (t == QMetaType::UnknownType || + (t >= int(QMetaType::User) && !(flags & QMetaType::PointerToQObject) && + t != qMetaTypeId<QJSValue>())) { + //the UserType clause is to catch registered QFlags QByteArray scope; QByteArray name; int scopeIdx = propType.lastIndexOf("::"); @@ -244,7 +247,7 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method, if (scope == "Qt") meta = &QObject::staticQtMetaObject; else - meta = parent->parent()->metaObject(); //### assumes parent->parent() + meta = static_cast<QQmlBoundSignal*>(parent)->object()->metaObject(); for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { QMetaEnum m = meta->enumerator(i); if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) { @@ -297,6 +300,71 @@ int QQmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a) } } +//////////////////////////////////////////////////////////////////////// + +QQmlBoundSignalNoParams::QQmlBoundSignalNoParams(QObject *scope, const QMetaMethod &signal, + QObject *owner) +: m_expression(0), m_owner(owner), m_index(signal.methodIndex()), m_isEvaluating(false) +{ + callback = &subscriptionCallback; + QQmlNotifierEndpoint::connect(scope, m_index); +} + +QQmlBoundSignalNoParams::~QQmlBoundSignalNoParams() +{ + delete m_expression; + m_expression = 0; +} + +int QQmlBoundSignalNoParams::index() const +{ + return m_index; +} + +/*! + Returns the signal expression. +*/ +QQmlExpression *QQmlBoundSignalNoParams::expression() const +{ + return m_expression; +} + +/*! + Sets the signal expression to \a e. Returns the current signal expression, + or null if there is no signal expression. + + The QQmlBoundSignalNoParams instance takes ownership of \a e. The caller is + assumes ownership of the returned QQmlExpression. +*/ +QQmlExpression *QQmlBoundSignalNoParams::setExpression(QQmlExpression *e) +{ + QQmlExpression *rv = m_expression; + m_expression = e; + if (m_expression) m_expression->setNotifyOnValueChanged(false); + return rv; +} + +void QQmlBoundSignalNoParams::subscriptionCallback(QQmlNotifierEndpoint *e) +{ + QQmlBoundSignalNoParams *s = static_cast<QQmlBoundSignalNoParams*>(e); + if (!s->m_expression) + return; + + if (QQmlDebugService::isDebuggingEnabled()) + QV8DebugService::instance()->signalEmitted(QString::fromAscii(s->m_owner->metaObject()->method(s->m_index).methodSignature())); + + QQmlHandlingSignalProfiler prof(s->m_owner, s->m_index, s->m_expression); + + s->m_isEvaluating = true; + + if (s->m_expression && s->m_expression->engine()) { + QQmlExpressionPrivate::get(s->m_expression)->value(); + if (s->m_expression && s->m_expression->hasError()) + QQmlEnginePrivate::warning(s->m_expression->engine(), s->m_expression->error()); + } + s->m_isEvaluating = false; +} + QT_END_NAMESPACE #include <qqmlboundsignal.moc> diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index 11386159cb..5fc8c3522f 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -57,36 +57,48 @@ #include <QtCore/qmetaobject.h> +#include <private/qqmlnotifier_p.h> #include <private/qobject_p.h> QT_BEGIN_NAMESPACE -class Q_QML_EXPORT QQmlAbstractBoundSignal : public QObject +class Q_QML_EXPORT QQmlAbstractBoundSignal { - Q_OBJECT public: - QQmlAbstractBoundSignal(QObject *parent = 0); - virtual ~QQmlAbstractBoundSignal() = 0; + QQmlAbstractBoundSignal(); + virtual ~QQmlAbstractBoundSignal(); + + virtual int index() const = 0; + virtual QQmlExpression *expression() const = 0; + virtual QQmlExpression *setExpression(QQmlExpression *) = 0; + virtual QObject *object() = 0; + + void addToObject(); + +private: + friend class QQmlData; + friend class QQmlPropertyPrivate; + friend class QQmlEngineDebugService; + QQmlAbstractBoundSignal **m_prevSignal; + QQmlAbstractBoundSignal *m_nextSignal; }; class QQmlBoundSignalParameters; -class Q_QML_EXPORT QQmlBoundSignal : public QQmlAbstractBoundSignal +class Q_QML_EXPORT QQmlBoundSignal : public QObject, + public QQmlAbstractBoundSignal { public: - QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *parent); - QQmlBoundSignal(QQmlContext *ctxt, const QString &val, QObject *scope, - const QMetaMethod &signal, QObject *parent); + QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *owner); virtual ~QQmlBoundSignal(); int index() const; QQmlExpression *expression() const; QQmlExpression *setExpression(QQmlExpression *); + QObject *object() { return m_owner; } bool isEvaluating() const { return m_isEvaluating; } - static QQmlBoundSignal *cast(QObject *); - protected: virtual int qt_metacall(QMetaObject::Call c, int id, void **a); @@ -96,8 +108,34 @@ private: bool m_paramsValid : 1; bool m_isEvaluating : 1; QQmlBoundSignalParameters *m_params; + QObject *m_owner; }; +class Q_QML_EXPORT QQmlBoundSignalNoParams : public QQmlAbstractBoundSignal, + public QQmlNotifierEndpoint +{ +public: + QQmlBoundSignalNoParams(QObject *scope, const QMetaMethod &signal, QObject *owner); + virtual ~QQmlBoundSignalNoParams(); + + int index() const; + + QQmlExpression *expression() const; + QQmlExpression *setExpression(QQmlExpression *); + QObject *object() { return m_owner; } + + static void subscriptionCallback(QQmlNotifierEndpoint *e); + + bool isEvaluating() const { return m_isEvaluating; } + +private: + QQmlExpression *m_expression; + QObject *m_owner; + int m_index; + bool m_isEvaluating; +}; + + QT_END_NAMESPACE #endif // QQMLBOUNDSIGNAL_P_H diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 416178e3e1..7bddaadcd0 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -110,8 +110,9 @@ static inline QString buildTypeNameForDebug(const QMetaObject *metaObject) /*! \class QQmlComponent - \since 4.7 + \since 5.0 \brief The QQmlComponent class encapsulates a QML component definition. + \inmodule QtQml \mainclass Components are reusable, encapsulated QML elements with well-defined interfaces. @@ -179,6 +180,8 @@ static inline QString buildTypeNameForDebug(const QMetaObject *metaObject) } \endcode + Note that the QtQuick 1 version is named QDeclarativeComponent. + \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code} */ diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h index f6d8aa1d3a..4b11095ec2 100644 --- a/src/qml/qml/qqmlcontext.h +++ b/src/qml/qml/qqmlcontext.h @@ -98,7 +98,6 @@ private: friend class QQmlComponent; friend class QQmlComponentPrivate; friend class QQmlScriptPrivate; - friend class QQmlBoundSignalProxy; friend class QQmlContextData; QQmlContext(QQmlContextData *); QQmlContext(QQmlEngine *, bool); diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 09d1a23510..e7e001c4f2 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -63,6 +63,7 @@ template <class Key, class T> class QHash; class QQmlGuardImpl; class QQmlCompiledData; class QQmlAbstractBinding; +class QQmlAbstractBoundSignal; class QQmlContext; class QQmlPropertyCache; class QQmlContextData; @@ -79,7 +80,7 @@ public: QQmlData() : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), hasTaintedV8Object(false), isQueuedForDeletion(false), notifyList(0), context(0), outerContext(0), - bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), + bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), v8objectid(0), propertyCache(0), guards(0), extendedData(0) { init(); @@ -136,6 +137,7 @@ public: QQmlContextData *outerContext; QQmlAbstractBinding *bindings; + QQmlAbstractBoundSignal *signalHandlers; // Linked list for QQmlContext::contextObjects QQmlData *nextContextObject; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 672996085f..955c8ce414 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -69,6 +69,7 @@ #include <private/qdebugmessageservice_p.h> #include "qqmlincubator.h" #include <private/qv8profilerservice_p.h> +#include <private/qqmlboundsignal_p.h> #include <QtCore/qstandardpaths.h> #include <QtCore/qsettings.h> @@ -507,7 +508,8 @@ QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() /*! \class QQmlEngine - \since 4.7 + \since 5.0 + \inmodule QtQml \brief The QQmlEngine class provides an environment for instantiating QML components. \mainclass @@ -533,6 +535,8 @@ QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() In this case, the Text item will be created in the engine's \l {QQmlEngine::rootContext()}{root context}. + Note that the QtQuick 1 version is called QDeclarativeEngine. + \sa QQmlComponent QQmlContext */ @@ -1020,10 +1024,11 @@ QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object, return qmlAttachedPropertiesObjectById(*idCache, object, create); } -QQmlDebuggingEnabler::QQmlDebuggingEnabler() +QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning) { #ifndef QQML_NO_DEBUG_PROTOCOL - if (!QQmlEnginePrivate::qml_debugging_enabled) { + if (!QQmlEnginePrivate::qml_debugging_enabled + && printWarning) { qDebug("QML debugging is enabled. Only use this in a safe environment."); } QQmlEnginePrivate::qml_debugging_enabled = true; @@ -1153,6 +1158,15 @@ void QQmlData::destroyed(QObject *object) binding = next; } + QQmlAbstractBoundSignal *signalHandler = signalHandlers; + while (signalHandler) { + QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal; + signalHandler->m_prevSignal = 0; + signalHandler->m_nextSignal = 0; + delete signalHandler; + signalHandler = next; + } + if (bindingBits) free(bindingBits); @@ -1690,6 +1704,7 @@ QQmlEnginePrivate::moduleApiInstance(const QQmlMetaType::ModuleApi &module) a = new QQmlMetaType::ModuleApiInstance; a->scriptCallback = module.script; a->qobjectCallback = module.qobject; + a->instanceMetaObject = module.instanceMetaObject; moduleApiInstances.insert(module, a); } diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 79424913f8..ce7fd01fdf 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -49,7 +49,8 @@ QT_BEGIN_NAMESPACE /*! \class QQmlError - \since 4.7 + \since 5.0 + \inmodule QtQml \brief The QQmlError class encapsulates a QML error. QQmlError includes a textual description of the error, as well @@ -69,6 +70,8 @@ QT_BEGIN_NAMESPACE ^ \endcode + Note that the QtQuick 1 version is named QDeclarativeError + \sa QQuickView::errors(), QQmlComponent::errors() */ class QQmlErrorPrivate diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 60a0fe1c89..d760486605 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -137,7 +137,8 @@ QQmlExpressionPrivate::create(QQmlContextData *ctxt, QObject *object, /*! \class QQmlExpression - \since 4.7 + \since 5.0 + \inmodule QtQml \brief The QQmlExpression class evaluates JavaScript in a QML context. For example, given a file \c main.qml like this: @@ -161,6 +162,8 @@ QQmlExpressionPrivate::create(QQmlContextData *ctxt, QObject *object, QQmlExpression *expr = new QQmlExpression(engine->rootContext(), myObject, "width * 2"); int result = expr->evaluate().toInt(); // result = 400 \endcode + + Note that the QtQuick 1 version is called QDeclarativeExpression. */ /*! diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp index 86d9f9588d..73d74f9e21 100644 --- a/src/qml/qml/qqmlextensionplugin.cpp +++ b/src/qml/qml/qqmlextensionplugin.cpp @@ -44,7 +44,8 @@ QT_BEGIN_NAMESPACE /*! - \since 4.7 + \since 5.0 + \inmodule QtQml \class QQmlExtensionPlugin \brief The QQmlExtensionPlugin class provides an abstract base for custom QML extension plugins. @@ -75,7 +76,7 @@ QT_BEGIN_NAMESPACE as a new QML element. It provides the current time through \c hour and \c minute properties, like this: - \snippet examples/declarative/cppextensions/plugins/plugin.cpp 0 + \snippet examples/qml/cppextensions/plugins/plugin.cpp 0 \dots To make this class available as a QML type, create a plugin that registers @@ -83,9 +84,9 @@ QT_BEGIN_NAMESPACE module will be named \c com.nokia.TimeExample (as defined in the project file further below). - \snippet examples/declarative/cppextensions/plugins/plugin.cpp plugin + \snippet examples/qml/cppextensions/plugins/plugin.cpp plugin \codeline - \snippet examples/declarative/cppextensions/plugins/plugin.cpp export + \snippet examples/qml/cppextensions/plugins/plugin.cpp export This registers the \c TimeModel class with the 1.0 version of this plugin library, as a QML type called \c Time. The Q_ASSERT statement @@ -121,6 +122,8 @@ QT_BEGIN_NAMESPACE The \l {Tutorial: Writing QML extensions with C++} also contains a chapter on creating QML plugins. + Note that the QtQuick 1 version is called QDeclarativeExtensionPlugin. + \sa QQmlEngine::importPlugin(), {How to Create Qt Plugins} */ diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index 00fd805ee0..ad28e38a64 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -87,7 +87,7 @@ void QQmlListReferencePrivate::release() /*! \class QQmlListReference -\since 4.7 +\since 5.0 \module QtQml \brief The QQmlListReference class allows the manipulation of QQmlListProperty properties. @@ -111,6 +111,8 @@ Attempting to add objects of the incorrect type to a list property will fail. Like with normal lists, when accessing a list element by index, it is the callers responsibility to ensure that it does not request an out of range element using the count() method before calling at(). + +The QtQuick 1 version of this class is named QDeclarativeListReference. */ /*! @@ -306,7 +308,8 @@ int QQmlListReference::count() const /*! \class QQmlListProperty -\since 4.7 +\since 5.0 +\inmodule QtQml \brief The QQmlListProperty class allows applications to expose list-like properties to QML. @@ -340,6 +343,8 @@ Q_PROPERTY(QQmlListProperty<Fruit> fruit READ fruit); QML list properties are typesafe - in this case \c {Fruit} is a QObject type that \c {Apple}, \c {Orange} and \c {Banana} all derive from. +The QtQuick 1 version of this class is named QDeclarativeListProperty. + \note QQmlListProperty can only be used for lists of QObject-derived object pointers. \sa {Object and List Property Types} diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 4af08c28bf..856f75fc16 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -908,6 +908,10 @@ int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api) import.minor = api.versionMinor; import.script = api.scriptApi; import.qobject = api.qobjectApi; + import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0. + + if (import.qobject && !import.instanceMetaObject) // BC - check import.iMO rather than api.iMO. + qWarning() << "qmlRegisterModuleApi(): sub-optimal: use the templated version of this function instead!"; int index = data->moduleApiCount++; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index b715d0c8f2..03017cafab 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -115,20 +115,23 @@ public: struct ModuleApiInstance { ModuleApiInstance() - : scriptCallback(0), qobjectCallback(0), qobjectApi(0) {} + : scriptCallback(0), qobjectCallback(0), qobjectApi(0), instanceMetaObject(0) {} QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *); QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *); - QJSValue scriptApi; QObject *qobjectApi; + const QMetaObject *instanceMetaObject; + QJSValue scriptApi; + }; struct ModuleApi { inline ModuleApi(); inline bool operator==(const ModuleApi &) const; int major; int minor; - QJSValue (*script)(QQmlEngine *, QJSEngine *); QObject *(*qobject)(QQmlEngine *, QJSEngine *); + const QMetaObject *instanceMetaObject; + QJSValue (*script)(QQmlEngine *, QJSEngine *); }; static ModuleApi moduleApi(const QString &, int, int); static QHash<QString, QList<ModuleApi> > moduleApis(); @@ -247,8 +250,9 @@ QQmlMetaType::ModuleApi::ModuleApi() { major = 0; minor = 0; - script = 0; qobject = 0; + instanceMetaObject = 0; + script = 0; } bool QQmlMetaType::ModuleApi::operator==(const ModuleApi &other) const diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp index e5d0d708e2..4c31e557bc 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp @@ -45,7 +45,8 @@ QT_BEGIN_NAMESPACE /*! \class QQmlNetworkAccessManagerFactory - \since 4.7 + \since 5.0 + \inmodule QtQml \brief The QQmlNetworkAccessManagerFactory class creates QNetworkAccessManager instances for a QML engine. A QML engine uses QNetworkAccessManager for all network access. @@ -79,7 +80,9 @@ QT_BEGIN_NAMESPACE For more information about signals and threads, see \l {Threads and QObjects} and \l {Signals and Slots Across Threads}. - \sa {declarative/cppextensions/networkaccessmanagerfactory}{NetworkAccessManagerFactory example} + The QtQuick 1 version of this class is named QDeclarativeNetworkAccessManagerFactory. + + \sa {qml/cppextensions/networkaccessmanagerfactory}{NetworkAccessManagerFactory example} */ /*! diff --git a/src/qml/qml/qqmlparserstatus.cpp b/src/qml/qml/qqmlparserstatus.cpp index d4e415a069..8468a1da00 100644 --- a/src/qml/qml/qqmlparserstatus.cpp +++ b/src/qml/qml/qqmlparserstatus.cpp @@ -45,7 +45,8 @@ QT_BEGIN_NAMESPACE /*! \class QQmlParserStatus - \since 4.7 + \since 5.0 + \inmodule QtQml \brief The QQmlParserStatus class provides updates on the QML parser state. QQmlParserStatus provides a mechanism for classes instantiated by @@ -75,6 +76,8 @@ QT_BEGIN_NAMESPACE void componentComplete(); } \endcode + + The QtQuick 1.0 version of this class is named QDeclarativeParserStatus. */ /*! \internal */ diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index b4c6fc3a12..82da62ff45 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -246,6 +246,7 @@ namespace QQmlPrivate QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *); QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *); + const QMetaObject *instanceMetaObject; }; enum RegistrationType { diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index d3778fa5c5..f68c345f3a 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -72,7 +72,8 @@ QT_BEGIN_NAMESPACE /*! \class QQmlProperty -\since 4.7 +\since 5.0 +\inmodule QtQml \brief The QQmlProperty class abstracts accessing properties on objects created from QML. As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect @@ -108,6 +109,8 @@ qWarning() << "Current pixel size:" << property.read().toInt(); property.write(24); qWarning() << "Pixel size should now be 24:" << property.read().toInt(); \endcode + +The QtQuick 1 version of this class was named QDeclarativeProperty. */ /*! @@ -923,15 +926,17 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) if (!(that.type() & QQmlProperty::SignalProperty)) return 0; - const QObjectList &children = that.d->object->children(); - - for (int ii = 0; ii < children.count(); ++ii) { - QObject *child = children.at(ii); + QQmlData *data = QQmlData::get(that.d->object); + if (!data) + return 0; - QQmlBoundSignal *signal = QQmlBoundSignal::cast(child); - if (signal && signal->index() == that.index()) - return signal->expression(); - } + QQmlAbstractBoundSignal *signalHandler = data->signalHandlers; + + while (signalHandler && signalHandler->index() != that.index()) + signalHandler = signalHandler->m_nextSignal; + + if (signalHandler) + return signalHandler->expression(); return 0; } @@ -952,19 +957,27 @@ QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, return 0; } - const QObjectList &children = that.d->object->children(); - - for (int ii = 0; ii < children.count(); ++ii) { - QObject *child = children.at(ii); + QQmlData *data = QQmlData::get(that.d->object, 0 != expr); + if (!data) + return 0; - QQmlBoundSignal *signal = QQmlBoundSignal::cast(child); - if (signal && signal->index() == that.index()) - return signal->setExpression(expr); - } + QQmlAbstractBoundSignal *signalHandler = data->signalHandlers; + + while (signalHandler && signalHandler->index() != that.index()) + signalHandler = signalHandler->m_nextSignal; + + if (signalHandler) + return signalHandler->setExpression(expr); if (expr) { - QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object); - return signal->setExpression(expr); + QQmlAbstractBoundSignal *signal = 0; + if (that.method().parameterTypes().count()) + signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object); + else + signal = new QQmlBoundSignalNoParams(that.d->object, that.method(), that.d->object); + QQmlExpression *oldExpr = signal->setExpression(expr); + signal->addToObject(); + return oldExpr; } else { return 0; } diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 4a1eb79213..1e8cfb6c20 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -680,7 +680,7 @@ struct StaticQtMetaObject : public QObject { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } }; -static int EnumType(const QMetaObject *metaobj, const QByteArray &str) +static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type) { QByteArray scope; QByteArray name; @@ -701,7 +701,7 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str) if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) return QVariant::Int; } - return QVariant::Invalid; + return type; } // Returns an array of the arguments for method \a index. The first entry in the array @@ -738,12 +738,16 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, for (int ii = 0; ii < argc; ++ii) { int type = m.parameterType(ii); - if ((QMetaType::typeFlags(type) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) + QMetaType::TypeFlags flags = QMetaType::typeFlags(type); + if (flags & QMetaType::IsEnumeration) type = QVariant::Int; - else if (type == QMetaType::UnknownType) { + else if (type == QMetaType::UnknownType || + (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) && + type != qMetaTypeId<QJSValue>())) { + //the UserType clause is to catch registered QFlags if (argTypeNames.isEmpty()) argTypeNames = m.parameterTypes(); - type = EnumType(object->metaObject(), argTypeNames.at(ii)); + type = EnumType(object->metaObject(), argTypeNames.at(ii), type); } if (type == QMetaType::UnknownType) { if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); @@ -767,12 +771,16 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, for (int ii = 0; ii < argc; ++ii) { int type = m.parameterType(ii); - if ((QMetaType::typeFlags(type) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) + QMetaType::TypeFlags flags = QMetaType::typeFlags(type); + if (flags & QMetaType::IsEnumeration) type = QVariant::Int; - else if (type == QMetaType::UnknownType) { + else if (type == QMetaType::UnknownType || + (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) && + type != qMetaTypeId<QJSValue>())) { + //the UserType clause is to catch registered QFlags) if (argTypeNames.isEmpty()) argTypeNames = m.parameterTypes(); - type = EnumType(object->metaObject(), argTypeNames.at(ii)); + type = EnumType(object->metaObject(), argTypeNames.at(ii), type); } if (type == QMetaType::UnknownType) { if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 352684ed5e..5412315d31 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -724,10 +724,15 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QMetaMethod signal = target->metaObject()->method(instr.signalIndex); - QQmlBoundSignal *bs = new QQmlBoundSignal(target, signal, target); - QQmlExpression *expr = + QQmlAbstractBoundSignal *bs = 0; + if (signal.parameterTypes().count()) + bs = new QQmlBoundSignal(target, signal, target); + else + bs = new QQmlBoundSignalNoParams(target, signal, target); + QQmlExpression *expr = new QQmlExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column, *new QQmlExpressionPrivate); bs->setExpression(expr); + bs->addToObject(); QML_END_INSTR(StoreSignal) QML_BEGIN_INSTR(StoreImportedScript) diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp index ea4d1afbbc..453120c6c7 100644 --- a/src/qml/qml/v4/qv4irbuilder.cpp +++ b/src/qml/qml/v4/qv4irbuilder.cpp @@ -428,18 +428,18 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) if (r.isValid()) { if (r.type) { _expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column); - } /*else if (r.importNamespace) { + } else if (r.importNamespace) { QQmlMetaType::ModuleApiInstance *moduleApi = m_expression->importCache->moduleApi(r.importNamespace); - if (moduleApi) { - if (moduleApi->qobjectCallback) { - moduleApi->qobjectApi = moduleApi->qobjectCallback(QQmlEnginePrivate::get(m_engine), QQmlEnginePrivate::get(m_engine)); - moduleApi->qobjectCallback = 0; - moduleApi->scriptCallback = 0; - } - if (moduleApi->qobjectApi) - _expr.code = _block->MODULE_OBJECT(name, moduleApi->qobjectApi->metaObject(), IR::Name::MemberStorage, line, column); + if (moduleApi && moduleApi->instanceMetaObject) { + // Note: we don't need to check moduleApi->qobjectCallback here, since + // we did that check in registerModuleApi() in qqmlmetatype.cpp. + // We cannot create the QObject Module Api Instance here, + // as we might be running in a loader thread. + // Thus, V4 can only handle bindings which use Module APIs which + // were registered with the templated registration function. + _expr.code = _block->MODULE_OBJECT(name, moduleApi->instanceMetaObject, IR::Name::MemberStorage, line, column); } - }*/ //### we can't create the actual QObject here, as we may be running in a thread (can be reenabled once QTBUG-24894 is handled) + } // We don't support anything else } else { bool found = false; diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index a11f68f709..2e2c8725aa 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -389,7 +389,17 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event) bool doubleClick = event->timestamp() - touchMousePressTimestamp < static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval()); touchMousePressTimestamp = event->timestamp(); + QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonPress, p); + me.setTimestamp(event->timestamp()); + me.setAccepted(false); + me.setCapabilities(event->device()->capabilities()); + deliverMouseEvent(&me); + if (me.isAccepted()) { + touchMouseId = p.id(); + event->setAccepted(true); + } if (doubleClick) { + touchMousePressTimestamp = 0; QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonDblClick, p); me.setTimestamp(event->timestamp()); me.setAccepted(false); @@ -407,15 +417,6 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event) } } } - QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonPress, p); - me.setTimestamp(event->timestamp()); - me.setAccepted(false); - me.setCapabilities(event->device()->capabilities()); - deliverMouseEvent(&me); - if (me.isAccepted()) { - touchMouseId = p.id(); - event->setAccepted(true); - } if (touchMouseId != -1) break; } else if (p.id() == touchMouseId) { @@ -531,7 +532,7 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F if (oldActiveFocusItem) { #ifndef QT_NO_IM - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); #endif activeFocusItem = 0; @@ -627,7 +628,7 @@ void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, Q_ASSERT(oldActiveFocusItem); #ifndef QT_NO_IM - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); #endif activeFocusItem = 0; @@ -993,6 +994,10 @@ bool QQuickCanvas::event(QEvent *e) case QEvent::WindowDeactivate: rootItem()->windowDeactivateEvent(); break; + case QEvent::FocusAboutToChange: + if (d->activeFocusItem) + qGuiApp->inputMethod()->commit(); + break; default: break; } diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 2a744c0559..1cf10df2f7 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3067,10 +3067,6 @@ void QQuickItem::updatePolish() { } -void QQuickItem::sendAccessibilityUpdate() -{ -} - void QQuickItemPrivate::addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types) { changeListeners.append(ChangeListener(listener, types)); @@ -3316,6 +3312,10 @@ void QQuickItem::setBaselineOffset(qreal offset) anchor->updateVerticalAnchors(); } } + + if (d->_anchors && (d->_anchors->usedAnchors() & QQuickAnchors::BaselineAnchor)) + QQuickAnchorsPrivate::get(d->_anchors)->updateVerticalAnchors(); + emit baselineOffsetChanged(offset); } diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 70a8ebc932..16dee80380 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -399,9 +399,6 @@ protected: virtual void releaseResources(); virtual void updatePolish(); -protected Q_SLOTS: - void sendAccessibilityUpdate(); - protected: QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = 0); diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 0d95500860..209d30aa74 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -186,6 +186,18 @@ void QQuickItemViewChangeSet::applyChanges(const QQuickChangeSet &changeSet) } } +void QQuickItemViewChangeSet::applyBufferedChanges(const QQuickItemViewChangeSet &other) +{ + if (!other.hasPendingChanges()) + return; + + pendingChanges.apply(other.pendingChanges); + itemCount = other.itemCount; + newCurrentIndex = other.newCurrentIndex; + currentChanged = other.currentChanged; + currentRemoved = other.currentRemoved; +} + void QQuickItemViewChangeSet::prepare(int currentIndex, int count) { if (active) @@ -1044,8 +1056,17 @@ void QQuickItemView::modelUpdated(const QQuickChangeSet &changeSet, bool reset) polish(); } } else { - d->currentChanges.prepare(d->currentIndex, d->itemCount); - d->currentChanges.applyChanges(changeSet); + if (d->disableLayout) { + d->bufferedChanges.prepare(d->currentIndex, d->itemCount); + d->bufferedChanges.applyChanges(changeSet); + } else { + if (d->bufferedChanges.hasPendingChanges()) { + d->currentChanges.applyBufferedChanges(d->bufferedChanges); + d->bufferedChanges.reset(); + } + d->currentChanges.prepare(d->currentIndex, d->itemCount); + d->currentChanges.applyChanges(changeSet); + } polish(); } } @@ -1756,11 +1777,16 @@ void QQuickItemViewPrivate::layout() bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult, ChangeResult *totalRemovalResult) { Q_Q(QQuickItemView); - if (!q->isComponentComplete() || (!currentChanges.hasPendingChanges() && !runDelayedRemoveTransition) || disableLayout) + if (!q->isComponentComplete() || (!currentChanges.hasPendingChanges() && !bufferedChanges.hasPendingChanges() && !runDelayedRemoveTransition) || disableLayout) return false; disableLayout = true; + if (bufferedChanges.hasPendingChanges()) { + currentChanges.applyBufferedChanges(bufferedChanges); + bufferedChanges.reset(); + } + updateUnrequestedIndexes(); moveReason = QQuickItemViewPrivate::Other; diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 7516761ee8..e352c461d6 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -107,6 +107,8 @@ public: void applyChanges(const QQuickChangeSet &changeSet); + void applyBufferedChanges(const QQuickItemViewChangeSet &other); + int itemCount; int newCurrentIndex; QQuickChangeSet pendingChanges; @@ -245,6 +247,7 @@ public: int requestedIndex; FxViewItem *requestedItem; QQuickItemViewChangeSet currentChanges; + QQuickItemViewChangeSet bufferedChanges; QQmlComponent *highlightComponent; FxViewItem *highlight; diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp index b85a449c51..962dddafc9 100644 --- a/src/quick/items/qquickpathview.cpp +++ b/src/quick/items/qquickpathview.cpp @@ -67,8 +67,16 @@ #define QML_FLICK_DISCARDSAMPLES 1 #endif +// The default maximum velocity of a flick. +#ifndef QML_FLICK_DEFAULTMAXVELOCITY +#define QML_FLICK_DEFAULTMAXVELOCITY 2500 +#endif + + QT_BEGIN_NAMESPACE +const qreal MinimumFlickVelocity = 75.0; + inline qreal qmlMod(qreal x, qreal y) { #ifdef QT_USE_MATH_H_FLOATS @@ -105,6 +113,23 @@ void QQuickPathViewAttached::setValue(const QByteArray &name, const QVariant &va m_metaobject->setValue(name, val); } +QQuickPathViewPrivate::QQuickPathViewPrivate() + : path(0), currentIndex(0), currentItemOffset(0.0), startPc(0), lastDist(0) + , lastElapsed(0), offset(0.0), offsetAdj(0.0), mappedRange(1.0) + , stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true) + , autoHighlight(true), highlightUp(false), layoutScheduled(false) + , moving(false), flicking(false), requestedOnPath(false), inRequest(false) + , dragMargin(0), deceleration(100), maximumFlickVelocity(QML_FLICK_DEFAULTMAXVELOCITY) + , moveOffset(this, &QQuickPathViewPrivate::setAdjustedOffset), flickDuration(0) + , firstIndex(-1), pathItems(-1), requestedIndex(-1), requestedZ(0) + , moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0) + , moveHighlight(this, &QQuickPathViewPrivate::setHighlightPosition) + , highlightPosition(0) + , highlightRangeStart(0), highlightRangeEnd(0) + , highlightRangeMode(QQuickPathView::StrictlyEnforceRange) + , highlightMoveDuration(300), modelCount(0) +{ +} void QQuickPathViewPrivate::init() { @@ -975,6 +1000,28 @@ void QQuickPathView::setFlickDeceleration(qreal dec) } /*! + \qmlproperty real QtQuick2::PathView::maximumFlickVelocity + This property holds the approximate maximum velocity that the user can flick the view in pixels/second. + + The default value is platform dependent. +*/ +qreal QQuickPathView::maximumFlickVelocity() const +{ + Q_D(const QQuickPathView); + return d->maximumFlickVelocity; +} + +void QQuickPathView::setMaximumFlickVelocity(qreal vel) +{ + Q_D(QQuickPathView); + if (vel == d->maximumFlickVelocity) + return; + d->maximumFlickVelocity = vel; + emit maximumFlickVelocityChanged(); +} + + +/*! \qmlproperty bool QtQuick2::PathView::interactive A user cannot drag or flick a PathView that is not interactive. @@ -1203,7 +1250,7 @@ void QQuickPathView::mousePressEvent(QMouseEvent *event) void QQuickPathViewPrivate::handleMousePressEvent(QMouseEvent *event) { Q_Q(QQuickPathView); - if (!interactive || !items.count()) + if (!interactive || !items.count() || !model || !modelCount) return; velocityBuffer.clear(); QPointF scenePoint = q->mapToScene(event->localPos()); @@ -1252,7 +1299,7 @@ void QQuickPathView::mouseMoveEvent(QMouseEvent *event) void QQuickPathViewPrivate::handleMouseMoveEvent(QMouseEvent *event) { Q_Q(QQuickPathView); - if (!interactive || !lastPosTime.isValid()) + if (!interactive || !lastPosTime.isValid() || !model || !modelCount) return; qreal newPc; @@ -1306,14 +1353,22 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *) Q_Q(QQuickPathView); stealMouse = false; q->setKeepMouseGrab(false); - if (!interactive || !lastPosTime.isValid()) + if (!interactive || !lastPosTime.isValid() || !model || !modelCount) { + lastPosTime.invalidate(); + if (!tl.isActive()) + q->movementEnding(); return; + } qreal velocity = calcVelocity(); - if (model && modelCount && qAbs(velocity) > 0.5) { - qreal count = pathItems == -1 ? modelCount : pathItems; - if (qAbs(velocity) > count * 2) // limit velocity - velocity = (velocity > 0 ? count : -count) * 2; + qreal count = modelCount*mappedRange; + qreal pixelVelocity = (path->path().length()/count) * velocity; + if (qAbs(pixelVelocity) > MinimumFlickVelocity) { + if (qAbs(pixelVelocity) > maximumFlickVelocity) { + // limit velocity + qreal maxVel = velocity < 0 ? -maximumFlickVelocity : maximumFlickVelocity; + velocity = maxVel / (path->path().length()/count); + } // Calculate the distance to be travelled qreal v2 = velocity*velocity; qreal accel = deceleration/10; diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h index 8f1ecd6caf..8b15e85b8a 100644 --- a/src/quick/items/qquickpathview_p.h +++ b/src/quick/items/qquickpathview_p.h @@ -73,6 +73,7 @@ class Q_AUTOTEST_EXPORT QQuickPathView : public QQuickItem Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged) Q_PROPERTY(qreal dragMargin READ dragMargin WRITE setDragMargin NOTIFY dragMarginChanged) + Q_PROPERTY(qreal maximumFlickVelocity READ maximumFlickVelocity WRITE setMaximumFlickVelocity NOTIFY maximumFlickVelocityChanged) Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged) Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged) @@ -126,6 +127,9 @@ public: qreal flickDeceleration() const; void setFlickDeceleration(qreal dec); + qreal maximumFlickVelocity() const; + void setMaximumFlickVelocity(qreal); + bool isInteractive() const; void setInteractive(bool); @@ -160,6 +164,7 @@ Q_SIGNALS: void snapPositionChanged(); void delegateChanged(); void pathItemCountChanged(); + void maximumFlickVelocityChanged(); void flickDecelerationChanged(); void interactiveChanged(); void movingChanged(); diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h index 412caa6d2b..ac74e9a568 100644 --- a/src/quick/items/qquickpathview_p_p.h +++ b/src/quick/items/qquickpathview_p_p.h @@ -74,23 +74,7 @@ class QQuickPathViewPrivate : public QQuickItemPrivate, public QQuickItemChangeL Q_DECLARE_PUBLIC(QQuickPathView) public: - QQuickPathViewPrivate() - : path(0), currentIndex(0), currentItemOffset(0.0), startPc(0), lastDist(0) - , lastElapsed(0), offset(0.0), offsetAdj(0.0), mappedRange(1.0) - , stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true) - , autoHighlight(true), highlightUp(false), layoutScheduled(false) - , moving(false), flicking(false), requestedOnPath(false), inRequest(false) - , dragMargin(0), deceleration(100) - , moveOffset(this, &QQuickPathViewPrivate::setAdjustedOffset), flickDuration(0) - , firstIndex(-1), pathItems(-1), requestedIndex(-1), requestedZ(0) - , moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0) - , moveHighlight(this, &QQuickPathViewPrivate::setHighlightPosition) - , highlightPosition(0) - , highlightRangeStart(0), highlightRangeEnd(0) - , highlightRangeMode(QQuickPathView::StrictlyEnforceRange) - , highlightMoveDuration(300), modelCount(0) - { - } + QQuickPathViewPrivate(); void init(); @@ -169,6 +153,7 @@ public: QPointF lastPos; qreal dragMargin; qreal deceleration; + qreal maximumFlickVelocity; QQuickTimeLine tl; QQuickTimeLineValueProxy<QQuickPathViewPrivate> moveOffset; int flickDuration; diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp index c55b1ca7f5..fffa4d9521 100644 --- a/src/quick/items/qquickshadereffectsource.cpp +++ b/src/quick/items/qquickshadereffectsource.cpp @@ -210,6 +210,14 @@ void QQuickShaderEffectTexture::setItem(QSGNode *item) if (item == m_item) return; m_item = item; + + if (m_live && !m_item) { + delete m_fbo; + delete m_secondaryFbo; + m_fbo = m_secondaryFbo = 0; + m_depthStencilBuffer.clear(); + } + markDirtyTexture(); } @@ -226,6 +234,14 @@ void QQuickShaderEffectTexture::setSize(const QSize &size) if (size == m_size) return; m_size = size; + + if (m_live && m_size.isNull()) { + delete m_fbo; + delete m_secondaryFbo; + m_fbo = m_secondaryFbo = 0; + m_depthStencilBuffer.clear(); + } + markDirtyTexture(); } @@ -242,6 +258,14 @@ void QQuickShaderEffectTexture::setLive(bool live) if (live == m_live) return; m_live = live; + + if (m_live && (!m_item || m_size.isNull())) { + delete m_fbo; + delete m_secondaryFbo; + m_fbo = m_secondaryFbo = 0; + m_depthStencilBuffer.clear(); + } + markDirtyTexture(); } @@ -613,6 +637,8 @@ void QQuickShaderEffectSource::setWrapMode(WrapMode mode) \qmlproperty Item ShaderEffectSource::sourceItem This property holds the element to be rendered into the texture. + Setting this to null while \l live is true, will release the texture + resources. */ QQuickItem *QQuickShaderEffectSource::sourceItem() const @@ -750,8 +776,8 @@ void QQuickShaderEffectSource::setFormat(QQuickShaderEffectSource::Format format \qmlproperty bool ShaderEffectSource::live If this property is true, the texture is updated whenever the - \l sourceItem changes. Otherwise, it will be a frozen image of the - \l sourceItem. The property is true by default. + \l sourceItem updates. Otherwise, it will be a frozen image, even if + \l sourceItem is assigned a new element. The property is true by default. */ bool QQuickShaderEffectSource::live() const diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index d7303352c5..e1a28a466a 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -402,7 +402,7 @@ void QQuickTextPrivate::updateSize() if (text.isEmpty()) { qreal fontHeight = fm.height(); q->setImplicitSize(0, fontHeight); - layedOutTextRect = QRect(0, 0, 0, fontHeight); + layedOutTextRect = QRectF(0, 0, 0, fontHeight); emit q->contentSizeChanged(); updateType = UpdatePaintNode; q->update(); @@ -2001,7 +2001,20 @@ QRectF QQuickText::boundingRect() const // Could include font max left/right bearings to either side of rectangle. - int h = height(); + 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; diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 1846d03b9b..eefe938467 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -1459,7 +1459,6 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) } } layout->setAdditionalFormats(overrides); - tentativeCommit = e->tentativeCommitString(); cursor.endEditBlock(); @@ -1503,7 +1502,6 @@ void QQuickTextControlPrivate::focusEvent(QFocusEvent *e) if (e->gotFocus()) { setBlinkingCursorEnabled(interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard)); } else { - commitPreedit(); setBlinkingCursorEnabled(false); if (cursorIsFocusIndicator @@ -1732,14 +1730,12 @@ void QQuickTextControlPrivate::commitPreedit() if (!isPreediting()) return; - cursor.beginEditBlock(); - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); - if (!tentativeCommit.isEmpty()) { - cursor.insertText(tentativeCommit); - tentativeCommit.clear(); - } + if (!isPreediting()) + return; + cursor.beginEditBlock(); preeditCursor = 0; QTextBlock block = cursor.block(); QTextLayout *layout = block.layout(); @@ -1767,17 +1763,12 @@ Qt::TextInteractionFlags QQuickTextControl::textInteractionFlags() const QString QQuickTextControl::toPlainText() const { - Q_D(const QQuickTextControl); - QString plainText = document()->toPlainText(); - if (!d->tentativeCommit.isEmpty()) - plainText.insert(textCursor().position(), d->tentativeCommit); - return plainText; + return document()->toPlainText(); } #ifndef QT_NO_TEXTHTMLPARSER QString QQuickTextControl::toHtml() const { - // note: currently not including tentative commit return document()->toHtml(); } #endif diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h index 9d776ce46b..c5a39cc759 100644 --- a/src/quick/items/qquicktextcontrol_p_p.h +++ b/src/quick/items/qquicktextcontrol_p_p.h @@ -137,7 +137,6 @@ public: QTextCursor cursor; QTextCursor selectedWordOnDoubleClick; QTextCursor selectedBlockOnTrippleClick; - QString tentativeCommit; QString highlightedAnchor; // Anchor below cursor QString anchorOnMousePress; QString linkToCopy; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 94856b63ab..f2da67bae7 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -119,8 +119,6 @@ QString QQuickTextInput::text() const Q_D(const QQuickTextInput); QString content = d->m_text; - if (!d->m_tentativeCommit.isEmpty()) - content.insert(d->m_cursor, d->m_tentativeCommit); QString res = d->m_maskData ? d->stripString(content) : content; return (res.isNull() ? QString::fromLatin1("") : res); } @@ -132,7 +130,6 @@ void QQuickTextInput::setText(const QString &s) return; if (d->composeMode()) qApp->inputMethod()->reset(); - d->m_tentativeCommit.clear(); d->internalSetText(s, -1, false); } @@ -2496,7 +2493,6 @@ void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value) } if (!hasFocus) { - d->commitPreedit(); if (!d->persistentSelection) d->deselect(); disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)), @@ -2831,21 +2827,16 @@ void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode) /*! \internal - - Exits preedit mode and commits parts marked as tentative commit */ void QQuickTextInputPrivate::commitPreedit() { if (!composeMode()) return; - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); - if (!m_tentativeCommit.isEmpty()) { - internalInsert(m_tentativeCommit); - m_tentativeCommit.clear(); - finishChange(-1, true/*not used, not documented*/, false); - } + if (!composeMode()) + return; m_preeditCursor = 0; m_textLayout.setPreeditArea(-1, QString()); @@ -3160,14 +3151,7 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) q->updateCursorRectangle(); } - bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString(); - - if (tentativeCommitChanged) { - m_textDirty = true; - m_tentativeCommit = event->tentativeCommitString(); - } - - if (isGettingInput || tentativeCommitChanged) + if (isGettingInput) finishChange(priorState); if (selectionChange) { @@ -3237,15 +3221,6 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo return true; } m_cursor = cursorCopy; - - if (!m_tentativeCommit.isEmpty()) { - textCopy.insert(m_cursor, m_tentativeCommit); - bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid; - if (!validInput) - m_tentativeCommit.clear(); - } - } else { - m_tentativeCommit.clear(); } } #endif diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 165155acd0..3bd34b2661 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -188,7 +188,6 @@ public: QString m_text; QString m_inputMask; QString m_cancelText; - QString m_tentativeCommit; QFont font; QFont sourceFont; diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp index 61c2ef24b4..bac5cc7582 100644 --- a/src/quick/items/qquickwindowmanager.cpp +++ b/src/quick/items/qquickwindowmanager.cpp @@ -1120,7 +1120,8 @@ void QQuickRenderThreadSingleContextWindowManager::maybeUpdate(QQuickCanvas *) void QQuickRenderThreadSingleContextWindowManager::wakeup() { lockInGui(); - if (isRenderBlocked) + isExternalUpdatePending = true; + if (isRenderBlocked || isPostingSyncEvent) wake(); unlockInGui(); } diff --git a/src/quick/util/qquickconnections.cpp b/src/quick/util/qquickconnections.cpp index 533c7013ef..acc9738f2c 100644 --- a/src/quick/util/qquickconnections.cpp +++ b/src/quick/util/qquickconnections.cpp @@ -283,6 +283,7 @@ void QQuickConnections::connectSignals() QQmlExpression *expression = ctxtdata ? QQmlExpressionPrivate::create(ctxtdata, 0, script, true, location, line, column) : 0; signal->setExpression(expression); + signal->addToObject(); d->boundsignals += signal; } else { if (!d->ignoreUnknownSignals) diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index 1d838cac32..b306ab3419 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -53,6 +53,7 @@ public: \class QQuickTextureFactory \since 5.0 \brief The QQuickTextureFactory class provides an interface for loading custom textures from QML. + \inmodule QtQml The purpose of the texture factory is to provide a placeholder for a image data that can be converted into an OpenGL texture. @@ -110,7 +111,8 @@ QImage QQuickTextureFactory::image() const /*! \class QQuickImageProvider - \since 4.7 + \since 5.0 + \inmodule QtQuick \brief The QQuickImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML. QQuickImageProvider is used to provide advanced image loading features @@ -218,6 +220,8 @@ QImage QQuickTextureFactory::image() const \c cache property to \c false for the relevant \l Image, \l BorderImage or \l AnimatedImage object. + The QtQuick 1 version of this class is named QDeclarativeImageProvider. + \sa QQmlEngine::addImageProvider() */ diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index e84e6623c1..b66ba289ce 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -202,18 +202,11 @@ void tst_QQmlEngineDebugService::recursiveObjectTest( foreach (const QmlDebugPropertyReference &p, oref.properties) { QCOMPARE(p.objectDebugId, QQmlDebugService::idForObject(o)); - // signal properties are fake - they are generated from QQmlBoundSignal children + // signal properties are fake - they are generated from QQmlAbstractBoundSignal children if (p.name.startsWith("on") && p.name.length() > 2 && p.name[2].isUpper()) { - QList<QQmlBoundSignal*> signalHandlers = - o->findChildren<QQmlBoundSignal*>(); QString signal = p.value.toString(); - bool found = false; - for (int i = 0; i < signalHandlers.count(); ++i) - if (signalHandlers.at(i)->expression()->expression() == signal) { - found = true; - break; - } - QVERIFY(found); + QQmlExpression *expr = QQmlPropertyPrivate::signalExpression(QQmlProperty(o, p.name)); + QVERIFY(expr && expr->expression() == signal); QVERIFY(p.valueTypeName.isEmpty()); QVERIFY(p.binding.isEmpty()); QVERIFY(!p.hasNotifySignal); diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiLegacy.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiLegacy.qml new file mode 100644 index 0000000000..e282ad64f2 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiLegacy.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +import Qt.test.legacyModuleApi 1.0 as ModApi // was registered with non-templated function + +QtObject { + property int legacyModulePropertyTest: ModApi.qobjectTestProperty + property int legacyModuleMethodTest + + Component.onCompleted: { + legacyModuleMethodTest = ModApi.qobjectTestMethod(); + } +} + diff --git a/tests/auto/qml/qqmlecmascript/data/registeredFlagMethod.qml b/tests/auto/qml/qqmlecmascript/data/registeredFlagMethod.qml new file mode 100644 index 0000000000..b323b49662 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/registeredFlagMethod.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +MyQmlObject { + onBasicSignal: registeredFlagMethod(Qt.RightButton) +} diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index a79207a1c8..d674fa3eb6 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -187,14 +187,15 @@ void registerTypes() qRegisterMetaType<MyQmlObject::MyType>("MyQmlObject::MyType"); - qmlRegisterModuleApi("Qt.test",1,0,script_api); // register (script) module API for an existing uri which contains elements - qmlRegisterModuleApi("Qt.test",1,0,qobject_api); // register (qobject) for an existing uri for which another module API was previously regd. Should replace! - qmlRegisterModuleApi("Qt.test.scriptApi",1,0,script_api); // register (script) module API for a uri which doesn't contain elements - qmlRegisterModuleApi("Qt.test.scriptApi",2,0,readonly_script_api); // register (script) module API for a uri which doesn't contain elements - will be made read-only - qmlRegisterModuleApi("Qt.test.qobjectApi",1,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements - qmlRegisterModuleApi("Qt.test.qobjectApi",1,3,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, minor version set - qmlRegisterModuleApi("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set - qmlRegisterModuleApi("Qt.test.qobjectApiParented",1,0,qobject_api_engine_parent); // register (parented qobject) module API for a uri which doesn't contain elements + qmlRegisterModuleApi("Qt.test",1,0,script_api); // register (script) module API for an existing uri which contains elements + qmlRegisterModuleApi<testQObjectApi>("Qt.test",1,0,qobject_api); // register (qobject) for an existing uri for which another module API was previously regd. Should replace! + qmlRegisterModuleApi("Qt.test.scriptApi",1,0,script_api); // register (script) module API for a uri which doesn't contain elements + qmlRegisterModuleApi("Qt.test.scriptApi",2,0,readonly_script_api); // register (script) module API for a uri which doesn't contain elements - will be made read-only + qmlRegisterModuleApi<testQObjectApi>("Qt.test.qobjectApi",1,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements + qmlRegisterModuleApi<testQObjectApi>("Qt.test.qobjectApi",1,3,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, minor version set + qmlRegisterModuleApi<testQObjectApi>("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set + qmlRegisterModuleApi<testQObjectApi>("Qt.test.qobjectApiParented",1,0,qobject_api_engine_parent); // register (parented qobject) module API for a uri which doesn't contain elements + qmlRegisterModuleApi("Qt.test.legacyModuleApi", 1, 0, qobject_api); // this registration function doesn't provide type information. qRegisterMetaType<MyQmlObject::MyEnum2>("MyEnum2"); qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons"); diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index ab8f85baa3..167e944aa6 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -103,7 +103,7 @@ class MyQmlObject : public QObject Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intChanged) public: - MyQmlObject(): myinvokableObject(0), m_methodCalled(false), m_methodIntCalled(false), m_object(0), m_value(0), m_resetProperty(13), m_intProperty(0) {} + MyQmlObject(): myinvokableObject(0), m_methodCalled(false), m_methodIntCalled(false), m_object(0), m_value(0), m_resetProperty(13), m_intProperty(0), m_buttons(0) {} enum MyEnum { EnumValue1 = 0, EnumValue2 = 1 }; enum MyEnum2 { EnumValue3 = 2, EnumValue4 = 3 }; @@ -174,6 +174,7 @@ public: }; QVariant variant() const { return m_variant; } QJSValue qjsvalue() const { return m_qjsvalue; } + Qt::MouseButtons buttons() const { return m_buttons; } int intProperty() const { return m_intProperty; } void setIntProperty(int i) { m_intProperty = i; emit intChanged(); } @@ -202,6 +203,7 @@ public slots: void variantMethod(const QVariant &v) { m_variant = v; } void qjsvalueMethod(const QJSValue &v) { m_qjsvalue = v; } void v8function(QQmlV8Function*); + void registeredFlagMethod(Qt::MouseButtons v) { m_buttons = v; } private: friend class tst_qqmlecmascript; @@ -218,6 +220,7 @@ private: QVariant m_variant; QJSValue m_qjsvalue; int m_intProperty; + Qt::MouseButtons m_buttons; }; QML_DECLARE_TYPEINFO(MyQmlObject, QML_HAS_ATTACHED_PROPERTIES) diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index d932bc6d09..b3bf92fe81 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -245,6 +245,7 @@ private slots: void revision(); void invokableWithQObjectDerived(); void realTypePrecision(); + void registeredFlagMethod(); void automaticSemicolon(); void unaryExpression(); @@ -3372,6 +3373,17 @@ void tst_qqmlecmascript::moduleApi_data() << QVariantList() << QStringList() << QVariantList(); + + QTest::newRow("legacy module api registration") + << testFileUrl("moduleapi/qobjectModuleApiLegacy.qml") + << QString() + << QStringList() // warning doesn't occur in the test, but in registerTypes() + << (QStringList() << "legacyModulePropertyTest" << "legacyModuleMethodTest") + << (QVariantList() << 20 << 2) + << QStringList() + << QVariantList() + << QStringList() + << QVariantList(); } void tst_qqmlecmascript::moduleApi() @@ -6382,6 +6394,20 @@ void tst_qqmlecmascript::realTypePrecision() QCOMPARE(object->property("test6").toDouble(), 1234567890.*2); } +void tst_qqmlecmascript::registeredFlagMethod() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("registeredFlagMethod.qml")); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + + QCOMPARE(object->buttons(), 0); + emit object->basicSignal(); + QCOMPARE(object->buttons(), Qt::RightButton); + + delete object; +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qquickconnection/tst_qquickconnection.cpp b/tests/auto/qml/qquickconnection/tst_qquickconnection.cpp index ad687dd085..1167281eb0 100644 --- a/tests/auto/qml/qquickconnection/tst_qquickconnection.cpp +++ b/tests/auto/qml/qquickconnection/tst_qquickconnection.cpp @@ -263,7 +263,7 @@ static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine) // QTBUG-20937 void tst_qquickconnection::moduleApiTarget() { - qmlRegisterModuleApi("MyTestModuleApi", 1, 0, module_api_factory); + qmlRegisterModuleApi<MyTestModuleApi>("MyTestModuleApi", 1, 0, module_api_factory); QQmlComponent component(&engine, testFileUrl("moduleapi-target.qml")); QObject *object = component.create(); QVERIFY(object != 0); diff --git a/tests/auto/qml/v4/data/moduleApi.qml b/tests/auto/qml/v4/data/moduleApi.qml new file mode 100644 index 0000000000..9f3bf0ca8c --- /dev/null +++ b/tests/auto/qml/v4/data/moduleApi.qml @@ -0,0 +1,12 @@ +import Qt.test 1.0 as ModApi +import QtQuick 2.0 + +Item { + property int testProp: ModApi.ip + property int testProp2: 2 + + function getRandom() { + testProp2 = ModApi.random(); + // testProp should also have changed. + } +} diff --git a/tests/auto/qml/v4/tst_v4.cpp b/tests/auto/qml/v4/tst_v4.cpp index 8c811f230e..47fa10b595 100644 --- a/tests/auto/qml/v4/tst_v4.cpp +++ b/tests/auto/qml/v4/tst_v4.cpp @@ -81,6 +81,7 @@ private slots: void mathCeil(); void mathMax(); void mathMin(); + void moduleApi(); private: QQmlEngine engine; @@ -589,6 +590,46 @@ void tst_v4::mathMin() delete o; } +class V4ModuleApi : public QObject +{ + Q_OBJECT + Q_PROPERTY(int ip READ ip WRITE setIp NOTIFY ipChanged FINAL) +public: + V4ModuleApi() : m_ip(12) {} + ~V4ModuleApi() {} + + Q_INVOKABLE int random() { static int prng = 3; prng++; m_ip++; emit ipChanged(); return prng; } + + int ip() const { return m_ip; } + void setIp(int v) { m_ip = v; emit ipChanged(); } + +signals: + void ipChanged(); + +private: + int m_ip; +}; + +static QObject *v4_module_api_factory(QQmlEngine*, QJSEngine*) +{ + return new V4ModuleApi; +} + +void tst_v4::moduleApi() +{ + // register module api, providing typeinfo via template + qmlRegisterModuleApi<V4ModuleApi>("Qt.test", 1, 0, v4_module_api_factory); + QQmlComponent component(&engine, testFileUrl("moduleApi.qml")); + QObject *o = component.create(); + QVERIFY(o != 0); + QCOMPARE(o->property("testProp").toInt(), 12); + QCOMPARE(o->property("testProp2").toInt(), 2); + QMetaObject::invokeMethod(o, "getRandom"); + QCOMPARE(o->property("testProp").toInt(), 13); + QCOMPARE(o->property("testProp2").toInt(), 4); + delete o; +} + QTEST_MAIN(tst_v4) #include "tst_v4.moc" diff --git a/tests/auto/quick/qquickanchors/data/baselineOffset.qml b/tests/auto/quick/qquickanchors/data/baselineOffset.qml new file mode 100644 index 0000000000..8bae61d16d --- /dev/null +++ b/tests/auto/quick/qquickanchors/data/baselineOffset.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +Item { + width: 200 + height: 200 + + Item { + objectName: "baselineAnchored" + + width: 200 + height: 10 + + anchors.baseline: parent.verticalCenter + } +} diff --git a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp index dd1f9f77ae..7b748f6191 100644 --- a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp +++ b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp @@ -84,6 +84,7 @@ private slots: void margins(); void marginsRTL(); void stretch(); + void baselineOffset(); }; void tst_qquickanchors::basicAnchors() @@ -705,6 +706,29 @@ void tst_qquickanchors::stretch() delete view; } +void tst_qquickanchors::baselineOffset() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("baselineOffset.qml")); + QScopedPointer<QObject> object(component.create()); + + QQuickItem *item = qobject_cast<QQuickItem *>(object.data()); + QVERIFY(item); + + QQuickItem *anchoredItem = findItem<QQuickItem>(item, QLatin1String("baselineAnchored")); + + QCOMPARE(anchoredItem->baselineOffset(), 0.0); + QCOMPARE(anchoredItem->y(), 100.0); + + anchoredItem->setBaselineOffset(5); + QCOMPARE(anchoredItem->baselineOffset(), 5.0); + QCOMPARE(anchoredItem->y(), 95.0); + + anchoredItem->setBaselineOffset(10); + QCOMPARE(anchoredItem->baselineOffset(), 10.0); + QCOMPARE(anchoredItem->y(), 90.0); +} + QTEST_MAIN(tst_qquickanchors) #include "tst_qquickanchors.moc" diff --git a/tests/auto/quick/qquickfontloader/qquickfontloader.pro b/tests/auto/quick/qquickfontloader/qquickfontloader.pro index 3e52b6fe7b..2eeb286e61 100644 --- a/tests/auto/quick/qquickfontloader/qquickfontloader.pro +++ b/tests/auto/quick/qquickfontloader/qquickfontloader.pro @@ -13,5 +13,3 @@ TESTDATA = data/* CONFIG += parallel_test QT += core-private gui-private qml-private quick-private network testlib - -win32:CONFIG += insignificant_test # QTBUG-24782 diff --git a/tests/auto/quick/qquickitemlayer/qquickitemlayer.pro b/tests/auto/quick/qquickitemlayer/qquickitemlayer.pro index 20fddb9410..fee91fb0d5 100644 --- a/tests/auto/quick/qquickitemlayer/qquickitemlayer.pro +++ b/tests/auto/quick/qquickitemlayer/qquickitemlayer.pro @@ -26,5 +26,3 @@ OTHER_FILES += \ data/SamplerNameChange.qml \ data/ItemEffect.qml \ data/RectangleEffect.qml - -win32:CONFIG += insignificant_test # QTBUG-24787 diff --git a/tests/auto/quick/qquicklistview/data/destroyItemOnCreation.qml b/tests/auto/quick/qquicklistview/data/destroyItemOnCreation.qml new file mode 100644 index 0000000000..12f43b029a --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/destroyItemOnCreation.qml @@ -0,0 +1,37 @@ +import QtQuick 2.0 + +Rectangle { + id: root + + width: 240 + height: 320 + + property int createdIndex: -1 + + Component { + id: myDelegate + + Rectangle { + id: wrapper + width: 240; height: 20 + objectName: "wrapper" + + Text { text: index } + + Component.onCompleted: { + root.createdIndex = index + ListView.view.model.removeItem(index) + } + } + } + + ListView { + id: list + objectName: "list" + focus: true + width: 240 + height: 320 + delegate: myDelegate + model: testModel + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 461a6b6750..1218d3cfcb 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -189,6 +189,7 @@ private slots: void multipleDisplaced(); void flickBeyondBounds(); + void destroyItemOnCreation(); private: template <class T> void items(const QUrl &source, bool forceLayout); @@ -6245,6 +6246,32 @@ void tst_QQuickListView::flickBeyondBounds() delete canvas; } +void tst_QQuickListView::destroyItemOnCreation() +{ + QmlListModel model; + QQuickView *canvas = createView(); + canvas->rootContext()->setContextProperty("testModel", &model); + + canvas->setSource(testFileUrl("destroyItemOnCreation.qml")); + canvas->show(); + qApp->processEvents(); + + QQuickListView *listview = findItem<QQuickListView>(canvas->rootObject(), "list"); + QVERIFY(listview != 0); + + QQuickItem *contentItem = listview->contentItem(); + QVERIFY(contentItem != 0); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + + QCOMPARE(canvas->rootObject()->property("createdIndex").toInt(), -1); + model.addItem("new item", ""); + QTRY_COMPARE(canvas->rootObject()->property("createdIndex").toInt(), 0); + + QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0); + QCOMPARE(model.count(), 0); + + delete canvas; +} QTEST_MAIN(tst_QQuickListView) diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 613156b2f5..85d2c3b6ea 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -124,6 +124,7 @@ private slots: void currentOffsetOnInsertion(); void asynchronous(); void cancelDrag(); + void maximumFlickVelocity(); }; class TestObject : public QObject @@ -944,6 +945,13 @@ void tst_QQuickPathView::propertyChanges() QCOMPARE(snapPositionSpy.count(), 1); QCOMPARE(dragMarginSpy.count(), 1); + + QSignalSpy maximumFlickVelocitySpy(pathView, SIGNAL(maximumFlickVelocityChanged())); + pathView->setMaximumFlickVelocity(1000); + QCOMPARE(maximumFlickVelocitySpy.count(), 1); + pathView->setMaximumFlickVelocity(1000); + QCOMPARE(maximumFlickVelocitySpy.count(), 1); + delete canvas; } @@ -1488,6 +1496,52 @@ void tst_QQuickPathView::cancelDrag() delete canvas; } +void tst_QQuickPathView::maximumFlickVelocity() +{ + QQuickView *canvas = createView(); + canvas->setSource(testFileUrl("dragpath.qml")); + canvas->show(); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + QTRY_COMPARE(canvas, qGuiApp->focusWindow()); + + QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject()); + QVERIFY(pathview != 0); + + pathview->setMaximumFlickVelocity(700); + flick(canvas, QPoint(200,10), QPoint(10,10), 180); + QVERIFY(pathview->isMoving()); + QVERIFY(pathview->isFlicking()); + QTRY_VERIFY(!pathview->isMoving()); + + double dist1 = 100 - pathview->offset(); + + pathview->setOffset(0.); + pathview->setMaximumFlickVelocity(300); + flick(canvas, QPoint(200,10), QPoint(10,10), 180); + QVERIFY(pathview->isMoving()); + QVERIFY(pathview->isFlicking()); + QTRY_VERIFY(!pathview->isMoving()); + + double dist2 = 100 - pathview->offset(); + + pathview->setOffset(0.); + pathview->setMaximumFlickVelocity(500); + flick(canvas, QPoint(200,10), QPoint(10,10), 180); + QVERIFY(pathview->isMoving()); + QVERIFY(pathview->isFlicking()); + QTRY_VERIFY(!pathview->isMoving()); + + double dist3 = 100 - pathview->offset(); + + QVERIFY(dist1 > dist2); + QVERIFY(dist3 > dist2); + QVERIFY(dist2 < dist1); + + delete canvas; +} + + QTEST_MAIN(tst_QQuickPathView) diff --git a/tests/auto/quick/qquicktext/qquicktext.pro b/tests/auto/quick/qquicktext/qquicktext.pro index daa7bed97b..8932664fa3 100644 --- a/tests/auto/quick/qquicktext/qquicktext.pro +++ b/tests/auto/quick/qquicktext/qquicktext.pro @@ -15,5 +15,3 @@ TESTDATA = data/* CONFIG += parallel_test QT += core-private gui-private v8-private qml-private quick-private network testlib - -win32:CONFIG += insignificant_test # QTBUG-24789 diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index affb355837..f4ba0864e5 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -110,6 +110,8 @@ private slots: void implicitSizeBinding_data(); void implicitSizeBinding(); + void boundingRect_data(); + void boundingRect(); void lineLaidOut(); void imgTagsBaseUrl_data(); @@ -1669,6 +1671,80 @@ void tst_qquicktext::implicitSizeBinding() QCOMPARE(textObject->height(), textObject->implicitHeight()); } +void tst_qquicktext::boundingRect_data() +{ + QTest::addColumn<QString>("format"); + QTest::newRow("PlainText") << "Text.PlainText"; + QTest::newRow("StyledText") << "Text.StyledText"; + QTest::newRow("RichText") << "Text.RichText"; +} + +void tst_qquicktext::boundingRect() +{ + QFETCH(QString, format); + + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0\n Text { textFormat:" + format.toUtf8() + "}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QQuickText *text = qobject_cast<QQuickText *>(object.data()); + QVERIFY(text); + + QCOMPARE(text->boundingRect().x(), qreal(0)); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), qreal(0)); + QCOMPARE(text->boundingRect().height(), QFontMetricsF(text->font()).height()); + + text->setText("Hello World"); + + QTextLayout layout(text->text()); + layout.setFont(text->font()); + + if (!qmlDisableDistanceField()) { + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); + } + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QCOMPARE(text->boundingRect().x(), qreal(0)); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(text->boundingRect().height(), line.height()); + + // the size of the bounding rect shouldn't be bounded by the size of item. + text->setWidth(text->width() / 2); + QCOMPARE(text->boundingRect().x(), qreal(0)); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(text->boundingRect().height(), line.height()); + + text->setHeight(text->height() * 2); + QCOMPARE(text->boundingRect().x(), qreal(0)); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(text->boundingRect().height(), line.height()); + + text->setHAlign(QQuickText::AlignRight); + QCOMPARE(text->boundingRect().x(), text->width() - line.naturalTextWidth()); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(text->boundingRect().height(), line.height()); + + text->setWrapMode(QQuickText::Wrap); + QCOMPARE(text->boundingRect().right(), text->width()); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QVERIFY(text->boundingRect().width() < line.naturalTextWidth()); + QVERIFY(text->boundingRect().height() > line.height()); + + text->setVAlign(QQuickText::AlignBottom); + QCOMPARE(text->boundingRect().right(), text->width()); + QCOMPARE(text->boundingRect().bottom(), text->height()); + QVERIFY(text->boundingRect().width() < line.naturalTextWidth()); + QVERIFY(text->boundingRect().height() > line.height()); +} + void tst_qquicktext::lineLaidOut() { QQuickView *canvas = createView(testFile("lineLayout.qml")); diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index 83e7e78866..ab21f3bc54 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -2287,16 +2287,6 @@ void tst_qquicktextedit::textInput() QQuickTextEditPrivate *editPrivate = static_cast<QQuickTextEditPrivate*>(QQuickItemPrivate::get(edit)); QCOMPARE(editPrivate->text, QString("Hello world!")); - // test that tentative commit is included in text property - edit->setText(""); - spy.clear(); - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event2("preedit", attributes); - event2.setTentativeCommitString("string"); - QGuiApplication::sendEvent(qGuiApp->focusObject(), &event2); - QCOMPARE(spy.count(), 1); - QCOMPARE(edit->text(), QString("string")); - QInputMethodQueryEvent queryEvent(Qt::ImEnabled); QGuiApplication::sendEvent(qGuiApp->focusObject(), &queryEvent); QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), true); diff --git a/tests/auto/quick/qquicktextinput/qquicktextinput.pro b/tests/auto/quick/qquicktextinput/qquicktextinput.pro index 336338f500..13b087eef5 100644 --- a/tests/auto/quick/qquicktextinput/qquicktextinput.pro +++ b/tests/auto/quick/qquicktextinput/qquicktextinput.pro @@ -9,5 +9,3 @@ include (../../shared/util.pri) TESTDATA = data/* QT += core-private gui-private v8-private qml-private quick-private testlib - -win32:CONFIG += insignificant_test # QTBUG-24790 diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index afe102aa4c..1c8bff9d69 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -2022,28 +2022,6 @@ void tst_qquicktextinput::inputMethods() QCOMPARE(input->text(), QString("Our Goodbye world!")); QCOMPARE(input->cursorPosition(), 7); - // test that basic tentative commit gets to text property on preedit state - input->setText(""); - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent preeditEvent("test", attributes); - preeditEvent.setTentativeCommitString("test"); - QGuiApplication::sendEvent(input, &preeditEvent); - QCOMPARE(input->text(), QString("test")); - - // tentative commit not allowed present in surrounding text - QInputMethodQueryEvent queryEvent(Qt::ImSurroundingText); - QGuiApplication::sendEvent(input, &queryEvent); - QCOMPARE(queryEvent.value(Qt::ImSurroundingText).toString(), QString("")); - - // if text with tentative commit does not validate, not allowed to be part of text property - input->setText(""); // ensure input state is reset - QValidator *validator = new QIntValidator(0, 100); - input->setValidator(validator); - QGuiApplication::sendEvent(input, &preeditEvent); - QCOMPARE(input->text(), QString("")); - input->setValidator(0); - delete validator; - // input should reset selection even if replacement parameters are out of bounds input->setText("text"); input->setCursorPosition(0); diff --git a/tests/auto/quick/shared/viewtestutil.h b/tests/auto/quick/shared/viewtestutil.h index 6ab754cff6..06efd9c28e 100644 --- a/tests/auto/quick/shared/viewtestutil.h +++ b/tests/auto/quick/shared/viewtestutil.h @@ -97,8 +97,8 @@ namespace QQuickViewTestUtil void insertItem(int index, const QString &name, const QString &number); void insertItems(int index, const QList<QPair<QString, QString> > &items); - void removeItem(int index); - void removeItems(int index, int count); + Q_INVOKABLE void removeItem(int index); + Q_INVOKABLE void removeItems(int index, int count); void moveItem(int from, int to); void moveItems(int from, int to, int count); diff --git a/tests/system/sys_listview.qtt b/tests/system/sys_listview.qtt index efd116fa92..ca10e1a0df 100644 --- a/tests/system/sys_listview.qtt +++ b/tests/system/sys_listview.qtt @@ -43,6 +43,74 @@ testcase = { + using_section_delegates: function() + { + // Test Meta-data + testTitle = "Using and changing section delegate properties"; + testBinary = "sections.qml"; + testSource: "$QTDIR/qtdeclarative/tests/system/listview"; + testGoal = "Verify that a Component can be set as a section header, using various properties for different collections."; + testPreconditions = "None"; + testGroups = "BAT,QtQuick 2.0"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run '+testBinary+' | Application has started, showing a ListView | + | | The view shows a single character section header for each element | + | Press the Criteria button | The section headers now show the full name of each item | + | Press Property | The section headers now show the id value for the items | + | Press Criteria | The section headers now only show i - the first character of id | + | Press Property | The section headers show the first character of the item names |')); + }, + + updating_sections: function() + { + // Test Meta-data + testTitle = "Updating Collected Sections"; + testBinary = "sections.qml"; + testSource: "$QTDIR/qtdeclarative/tests/system/listview"; + testGoal = "Verify that a section is updated when items are added."; + testPreconditions = "None"; + testGroups = "BAT,QtQuick 2.0"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run '+testBinary+' | Application has started, showing a ListView | + | | The view shows a single character section header for each element | + | Press the + button | A duplicate of every name is added | + | | Each duplicate is place in the same section as the original |')); + }, + + changing_section_delegates: function() + { + // Test Meta-data + testTitle = "Changing Section Delegates"; + testBinary = "sections.qml"; + testSource: "$QTDIR/qtdeclarative/tests/system/listview"; + testGoal = "Verify that a section delegate can be changed."; + testPreconditions = "None"; + testGroups = "BAT,QtQuick 2.0"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run '+testBinary+' | Application has started, showing a ListView | + | | The view shows a single character section header for each element | + | Press the Delegate button | The section headers now show as light blue rectangles | + | Press the Criteria button | The headers show as full names, still within light blue rectangles |')); + }, + altering_listview_primary_properties: function() { // Test Meta-data diff --git a/tests/testapplications/listview/sections.qml b/tests/testapplications/listview/sections.qml new file mode 100644 index 0000000000..1251e8eef1 --- /dev/null +++ b/tests/testapplications/listview/sections.qml @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + height: 400 + width: 300 + property int sets: 1 + + ListModel { + id: listmodel + Component.onCompleted: addNames() + } + + ListView { + id: listview + model: listmodel + height: 300 + width: 200 + clip: true + anchors.centerIn: parent + + section.delegate: del1 + section.criteria: ViewSection.FirstCharacter + section.property: "name" + delegate: Rectangle { + height: 50 + width: 200 + color: "gold" + border.color: "black" + Text { + anchors.centerIn: parent + text: model.name+" ["+model.id+"]" + color: "black" + font.bold: true + } + } + } + + function addNames() { + var names = ["Alpha","Bravo","Charlie","Delta","Echo","Foxtrot", + "Golf","Hotel","India","Juliet","Kilo","Lima","Mike", + "November","Oscar","Papa","Quebec","Romeo","Sierra","Tango", + "Uniform","Victor","Whiskey","XRay","Yankee","Zulu"]; + for (var i=0;i<names.length;++i) + listmodel.insert(sets*i, {"name":names[i], "id": "id"+i}); + sets++; + } + + Component { + id: del1 + Rectangle { + height: 50 + width: 200 + color: "white" + border.color: "black" + border.width: 3 + Text { + anchors.centerIn: parent + text: section + } + } + } + + Component { + id: del2 + Rectangle { + height: 50 + width: 200 + color: "lightsteelblue" + border.color: "orange" + Text { + anchors.centerIn: parent + text: section + } + } + } + + Rectangle { + anchors.fill: listview + color: "transparent" + border.color: "green" + border.width: 3 + } + + Row { + spacing: 3 + Rectangle { + height: 40 + width: 70 + color: "blue" + Text { + color: "white" + anchors.centerIn: parent + text: "Criteria" + } + radius: 5 + MouseArea { + anchors.fill: parent + onClicked: { + listview.section.criteria = listview.section.criteria == ViewSection.FirstCharacter ? + ViewSection.FullString : ViewSection.FirstCharacter + } + } + } + Rectangle { + height: 40 + width: 70 + color: "blue" + Text { + color: "white" + anchors.centerIn: parent + text: "Property" + } + radius: 5 + MouseArea { + anchors.fill: parent + onClicked: { + listview.section.property = listview.section.property == "name" ? "id" : "name"; + console.log(listview.section.property) + } + } + } + Rectangle { + height: 40 + width: 75 + color: "blue" + Text { + color: "white" + anchors.centerIn: parent + text: "Delegate" + } + radius: 5 + MouseArea { + anchors.fill: parent + onClicked: { + console.log("Change delegate") + listview.section.delegate = listview.section.delegate == del1 ? del2 : del1 + } + } + } + Rectangle { + height: 40 + width: 40 + color: "blue" + Text { + color: "white" + anchors.centerIn: parent + text: "+" + font.bold: true + } + radius: 5 + MouseArea { + anchors.fill: parent + onClicked: { addNames(); } + } + } + } +} diff --git a/tools/qmlscene/qmlscene.pro b/tools/qmlscene/qmlscene.pro index 392e607b88..3e63bd7659 100644 --- a/tools/qmlscene/qmlscene.pro +++ b/tools/qmlscene/qmlscene.pro @@ -12,6 +12,6 @@ macx: CONFIG -= app_bundle SOURCES += main.cpp -CONFIG += console declarative_debug +CONFIG += console -DEFINES += QML_RUNTIME_TESTING +DEFINES += QML_RUNTIME_TESTING QT_DECLARATIVE_DEBUG_NO_WARNING |