aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-03-13 01:01:04 +0100
committerUlf Hermann <ulf.hermann@qt.io>2019-03-13 10:10:09 +0100
commit76be4abbbcfb2fbb14ce532413e0895198e7f0f1 (patch)
tree5d6ca9c4425df15a93b6f74dc8e4dbb38db74d91
parent587d789fa5929f462b5744ba33a25db6c77b36fc (diff)
parent70d726e91e4ef27002b2271805de19077e25809c (diff)
Merge remote-tracking branch 'origin/5.12' into 5.13
Conflicts: src/qml/compiler/qv4codegen.cpp src/qml/animations/qsequentialanimationgroupjob.cpp Change-Id: I8b76e509fd7c8599d4cef25181d790ee28edab54
-rw-r--r--examples/quick/draganddrop/doc/src/draganddrop.qdoc5
-rw-r--r--src/imports/testlib/toucheventsequence.qdoc2
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp10
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp4
-rw-r--r--src/qml/compiler/qv4codegen.cpp31
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/signals.qdoc32
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp38
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp21
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp8
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp21
-rw-r--r--src/qmltest/doc/src/qtquicktest-index.qdoc2
-rw-r--r--src/qmltest/quicktestevent.cpp4
-rw-r--r--src/quick/handlers/qquickpointhandler.cpp4
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp19
-rw-r--r--src/quick/items/qquickevents.cpp7
-rw-r--r--src/quick/items/qquickflickable.cpp4
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp6
-rw-r--r--src/quick/items/qquicktableview.cpp15
-rw-r--r--src/quick/items/qquicktext.cpp4
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp18
-rw-r--r--src/quick/items/qquickwindow.cpp30
-rw-r--r--src/quickshapes/qquickshape.cpp5
-rw-r--r--tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp7
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp38
-rw-r--r--tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp5
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml64
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp19
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml2
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp37
-rw-r--r--tests/auto/quick/qquickshortcut/BLACKLIST7
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp5
-rw-r--r--tests/manual/cursorChange/main.qml79
-rw-r--r--tools/qmlcachegen/qtquickcompiler.prf1
-rw-r--r--tools/qmlplugindump/main.cpp34
35 files changed, 425 insertions, 165 deletions
diff --git a/examples/quick/draganddrop/doc/src/draganddrop.qdoc b/examples/quick/draganddrop/doc/src/draganddrop.qdoc
index b740582cc4..754fa8f8cb 100644
--- a/examples/quick/draganddrop/doc/src/draganddrop.qdoc
+++ b/examples/quick/draganddrop/doc/src/draganddrop.qdoc
@@ -57,8 +57,9 @@
\section1 GridView Example
- The \e {GridView Example} adds drag and drop to a \l GridView, allowing you to reorder the
- list. It also uses a \l DelegateModel to move a delegate item to the
+ The \e {GridView Example} adds drag and drop to a \l GridView, allowing you
+ to visually reorder the delegates without changing the underlying
+ \l ListModel. It uses a \l DelegateModel to move a delegate item to the
position of another item it is dragged over.
\snippet draganddrop/views/gridview.qml 0
diff --git a/src/imports/testlib/toucheventsequence.qdoc b/src/imports/testlib/toucheventsequence.qdoc
index 6f1f3f8863..bd3551a669 100644
--- a/src/imports/testlib/toucheventsequence.qdoc
+++ b/src/imports/testlib/toucheventsequence.qdoc
@@ -51,7 +51,7 @@
Events are delivered to the window which contains the item specified in touchEvent.
- \sa TestCase::touchEvent(), QTest::QTouchEventSequence
+ \sa TestCase::touchEvent()
*/
/*!
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
index 344791fd83..66599561fc 100644
--- a/src/qml/animations/qanimationgroupjob.cpp
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -120,13 +120,9 @@ void QAnimationGroupJob::removeAnimation(QAbstractAnimationJob *animation)
void QAnimationGroupJob::clear()
{
- QAbstractAnimationJob *child = firstChild();
- QAbstractAnimationJob *nextSibling = nullptr;
- while (child != nullptr) {
- child->m_group = nullptr;
- nextSibling = child->nextSibling();
- delete child;
- child = nextSibling;
+ while (QAbstractAnimationJob *child = firstChild()) {
+ removeAnimation(child);
+ delete child;
}
m_firstChild = nullptr;
m_lastChild = nullptr;
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index 0595141d60..d98546122f 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -206,9 +206,11 @@ int QSequentialAnimationGroupJob::duration() const
void QSequentialAnimationGroupJob::clear()
{
- m_currentAnimation = nullptr;
m_previousLoop = 0;
QAnimationGroupJob::clear();
+
+ // clear() should call removeAnimation(), which will clear m_currentAnimation, eventually.
+ Q_ASSERT(m_currentAnimation == nullptr);
}
void QSequentialAnimationGroupJob::updateCurrentTime(int currentTime)
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 17869bcc84..ac763e592f 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -727,9 +727,6 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
bytecodeGenerator->addInstruction(iteratorObjInstr);
iterator.storeConsumeAccumulator();
- bool hasRest = false;
-
- BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
{
auto cleanup = [this, iterator, iteratorDone]() {
iterator.loadInAccumulator();
@@ -760,27 +757,17 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
Reference::fromConst(this, Encode(true)).storeOnStack(iteratorDone.stackSlot());
bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
initializeAndDestructureBindingElement(e, Reference::fromAccumulator(this), isDefinition);
- hasRest = true;
} else {
Instruction::IteratorNext next;
next.value = iteratorValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
initializeAndDestructureBindingElement(e, iteratorValue, isDefinition);
- if (hasError) {
- end.link();
+ if (hasError)
return;
- }
}
}
-
- if (hasRest)
- // no need to close the iterator
- bytecodeGenerator->jump().link(end);
}
-
-
- end.link();
}
void Codegen::destructurePattern(Pattern *p, const Reference &rhs)
@@ -1220,7 +1207,6 @@ bool Codegen::visit(ArrayPattern *ast)
BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
- BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
{
auto cleanup = [this, iterator, iteratorDone]() {
@@ -1230,12 +1216,6 @@ bool Codegen::visit(ArrayPattern *ast)
bytecodeGenerator->addInstruction(close);
};
ControlFlowLoop flow(this, &end, &in, cleanup);
- bytecodeGenerator->jump().link(in);
-
- BytecodeGenerator::Label body = bytecodeGenerator->label();
-
- lhsValue.loadInAccumulator();
- pushAccumulator();
in.link();
iterator.loadInAccumulator();
@@ -1243,13 +1223,14 @@ bool Codegen::visit(ArrayPattern *ast)
next.value = lhsValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpFalse()).link(body);
- bytecodeGenerator->jump().link(done);
+ bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
+ lhsValue.loadInAccumulator();
+ pushAccumulator();
+
+ bytecodeGenerator->jump().link(in);
end.link();
}
-
- done.link();
} else {
RegisterScope innerScope(this);
Reference expr = expression(it->element->initializer);
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 0cce1895cb..f6f630c749 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -66,6 +66,8 @@ this manner, but the type cannot be used instantiated as a QML object type
from QML. This is useful, for example, if a type has enums that should be
exposed to QML but the type itself should not be instantiable.
+For a quick guide to choosing the correct approach to expose C++ types to QML,
+see \l {Choosing the Correct Integration Method Between C++ and QML}.
\section2 Registering an Instantiable Object Type
diff --git a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
index b643f18154..cd73ccc025 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
@@ -59,9 +59,9 @@ receiving this signal should be \c onClicked. In the example below, whenever
the button is clicked, the \c onClicked handler is invoked, applying a random
color to the parent \l Rectangle:
-\qml
-import QtQuick 2.\QtMinorVersion
-import QtQuick.Controls 2.\QtMinorVersion
+\qml \QtMinorVersion
+import QtQuick 2.\1
+import QtQuick.Controls 2.\1
Rectangle {
id: rect
@@ -87,8 +87,8 @@ these signals are written in the form \e on<Property>Changed, where
For example, the \l MouseArea type has a \l {MouseArea::pressed}{pressed} property. To receive a notification whenever this property changes, write a signal handler named \c onPressedChanged:
-\qml
-import QtQuick 2.\QtMinorVersion
+\qml \QtMinorVersion
+import QtQuick 2.\1
Rectangle {
id: rect
@@ -116,9 +116,9 @@ received by the root \l Rectangle instead, by placing the \c onClicked handler
in a \l Connections object that has its \l {Connections::target}{target} set to
the \c button:
-\qml
-import QtQuick 2.\QtMinorVersion
-import QtQuick.Controls 2.\QtMinorVersion
+\qml \QtMinorVersion
+import QtQuick 2.\1
+import QtQuick.Controls 2.\1
Rectangle {
id: rect
@@ -151,8 +151,8 @@ For example, \l{Component::completed}{Component.onCompleted} is an attached
signal handler. It is often used to execute some JavaScript code when its
creation process is complete. Here is an example:
-\qml
-import QtQuick 2.\QtMinorVersion
+\qml \QtMinorVersion
+import QtQuick 2.\1
Rectangle {
width: 200; height: 200
@@ -195,9 +195,9 @@ root \l Rectangle object has an \c activated signal, which is emitted whenever t
child \l TapHandler is \c tapped. In this particular example the activated signal
is emitted with the x and y coordinates of the mouse click:
-\qml
+\qml \QtMinorVersion
// SquareButton.qml
-import QtQuick 2.\QtMinorVersion
+import QtQuick 2.\1
Rectangle {
id: root
@@ -237,8 +237,8 @@ signal to be received by a method instead of a signal handler.
Below, the \c messageReceived signal is connected to three methods using the \c connect() method:
-\qml
-import QtQuick 2.\QtMinorVersion
+\qml \QtMinorVersion
+import QtQuick 2.\1
Rectangle {
id: relay
@@ -289,8 +289,8 @@ Rectangle {
By connecting signals to other signals, the \c connect() method can form different
signal chains.
-\qml
-import QtQuick 2.\QtMinorVersion
+\qml \QtMinorVersion
+import QtQuick 2.\1
Rectangle {
id: forwarder
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index d26e888069..13f6912371 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -223,41 +223,9 @@ ReturnedValue NumberPrototype::method_toString(const FunctionObject *b, const Va
return v4->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix").arg(radix));
}
- if (std::isnan(num)) {
- return Encode(v4->newString(QStringLiteral("NaN")));
- } else if (qt_is_inf(num)) {
- return Encode(v4->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity")));
- }
-
- if (radix != 10) {
- QString str;
- bool negative = false;
- if (num < 0) {
- negative = true;
- num = -num;
- }
- double frac = num - std::floor(num);
- num = Value::toInteger(num);
- do {
- char c = (char)std::fmod(num, radix);
- c = (c < 10) ? (c + '0') : (c - 10 + 'a');
- str.prepend(QLatin1Char(c));
- num = std::floor(num / radix);
- } while (num != 0);
- if (frac != 0) {
- str.append(QLatin1Char('.'));
- do {
- frac = frac * radix;
- char c = (char)std::floor(frac);
- c = (c < 10) ? (c + '0') : (c - 10 + 'a');
- str.append(QLatin1Char(c));
- frac = frac - std::floor(frac);
- } while (frac != 0);
- }
- if (negative)
- str.prepend(QLatin1Char('-'));
- return Encode(v4->newString(str));
- }
+ QString str;
+ RuntimeHelpers::numberToString(&str, num, radix);
+ return Encode(v4->newString(str));
}
return Encode(Value::fromDouble(num).toString(v4));
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index abf48b1034..afa4632e07 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -298,13 +298,22 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
if (frac != 0) {
result->append(QLatin1Char('.'));
+ double magnitude = 1;
+ double next = frac;
do {
- frac = frac * radix;
- char c = (char)::floor(frac);
+ next *= radix;
+ const int floored = ::floor(next);
+ char c = char(floored);
c = (c < 10) ? (c + '0') : (c - 10 + 'a');
result->append(QLatin1Char(c));
- frac = frac - ::floor(frac);
- } while (frac != 0);
+ magnitude /= radix;
+ frac -= double(floored) * magnitude;
+ next -= double(floored);
+
+ // The next digit still makes a difference
+ // if a value of "radix" for it would change frac.
+ // Otherwise we've reached the limit of numerical precision.
+ } while (frac > 0 && frac - magnitude != frac);
}
if (negative)
@@ -1600,12 +1609,14 @@ ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *en
const Value &thisObject = tos[StackOffsets::tailCall_thisObject];
Value *argv = reinterpret_cast<Value *>(frame->jsFrame) + tos[StackOffsets::tailCall_argv].int_32();
int argc = tos[StackOffsets::tailCall_argc].int_32();
+ Q_ASSERT(argc >= 0);
if (!function.isFunctionObject())
return engine->throwTypeError();
const FunctionObject &fo = static_cast<const FunctionObject &>(function);
- if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()) {
+ if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()
+ || unsigned(argc) > fo.formalParameterCount()) {
// Cannot tailcall, do a normal call:
return fo.call(&thisObject, argv, argc);
}
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index c519429d48..1b7a433a84 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -250,10 +250,12 @@ QQmlApplicationEngine::~QQmlApplicationEngine()
/*!
Loads the root QML file located at \a url. The object tree defined by the file
is created immediately for local file urls. Remote urls are loaded asynchronously,
- listen to the objectCreated signal to determine when the object
- tree is ready.
+ listen to the \l {QQmlApplicationEngine::objectCreated()}{objectCreated} signal to
+ determine when the object tree is ready.
- If an error occurs, error messages are printed with qWarning.
+ If an error occurs, the \l {QQmlApplicationEngine::objectCreated()}{objectCreated}
+ signal is emitted with a null pointer as parameter and error messages are printed
+ with qWarning.
*/
void QQmlApplicationEngine::load(const QUrl &url)
{
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 53e3f65553..572f58339f 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -353,6 +353,7 @@ void QQmlDelegateModel::componentComplete()
\l{QtQuick.XmlListModel::XmlListModel}{XmlListModel}.
\sa {qml-data-models}{Data Models}
+ \keyword dm-model-property
*/
QVariant QQmlDelegateModel::model() const
{
@@ -493,11 +494,10 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate)
\c view.qml:
\snippet delegatemodel/delegatemodel_rootindex/view.qml 0
- If the \l model is a QAbstractItemModel subclass, the delegate can also
- reference a \c hasModelChildren property (optionally qualified by a
- \e model. prefix) that indicates whether the delegate's model item has
- any child nodes.
-
+ If the \l {dm-model-property}{model} is a QAbstractItemModel subclass,
+ the delegate can also reference a \c hasModelChildren property (optionally
+ qualified by a \e model. prefix) that indicates whether the delegate's
+ model item has any child nodes.
\sa modelIndex(), parentModelIndex()
*/
@@ -699,6 +699,7 @@ QQmlDelegateModelGroup *QQmlDelegateModelPrivate::group_at(
The following example illustrates using groups to select items in a model.
\snippet delegatemodel/delegatemodelgroup.qml 0
+ \keyword dm-groups-property
*/
QQmlListProperty<QQmlDelegateModelGroup> QQmlDelegateModel::groups()
@@ -2274,7 +2275,7 @@ void QQmlDelegateModelAttached::resetCurrentIndex()
}
/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::model
+ \qmlattachedproperty model QtQml.Models::DelegateModel::model
This attached property holds the data model this delegate instance belongs to.
@@ -2482,7 +2483,8 @@ void QQmlDelegateModelGroupPrivate::destroyingPackage(QQuickPackage *package)
information about group membership and indexes as well as model data. In combination
with the move() function this can be used to implement view sorting, with remove() to filter
items out of a view, or with setGroups() and \l Package delegates to categorize items into
- different views.
+ different views. Different groups can only be sorted independently if they are disjunct. Moving
+ an item in one group will also move it in all other groups it is a part of.
Data from models can be supplemented by inserting data directly into a DelegateModelGroup
with the insert() function. This can be used to introduce mock items into a view, or
@@ -3094,6 +3096,11 @@ void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args)
\qmlmethod QtQml.Models::DelegateModelGroup::move(var from, var to, int count)
Moves \a count at \a from in a group \a to a new position.
+
+ \note The DelegateModel acts as a proxy model: it holds the delegates in a
+ different order than the \l{dm-model-property}{underlying model} has them.
+ Any subsequent changes to the underlying model will not undo whatever
+ reordering you have done via this function.
*/
void QQmlDelegateModelGroup::move(QQmlV4Function *args)
diff --git a/src/qmltest/doc/src/qtquicktest-index.qdoc b/src/qmltest/doc/src/qtquicktest-index.qdoc
index 283e88e2e4..4c0124689b 100644
--- a/src/qmltest/doc/src/qtquicktest-index.qdoc
+++ b/src/qmltest/doc/src/qtquicktest-index.qdoc
@@ -141,7 +141,7 @@
\l QUICK_TEST_MAIN_WITH_SETUP macro can be used. This can be useful for
setting context properties on the QML engine, amongst other things.
- The macro is identical to \l QUICK_TEST_MAIN, except that it takes an
+ The macro is identical to \c QUICK_TEST_MAIN, except that it takes an
additional \c QObject* argument. The test framework will call slots and
invokable functions with the following names:
diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp
index 480811d95c..5b07220c29 100644
--- a/src/qmltest/quicktestevent.cpp
+++ b/src/qmltest/quicktestevent.cpp
@@ -121,6 +121,7 @@ bool QuickTestEvent::keyClickChar(const QString &character, int modifiers, int d
return true;
}
+#if QT_CONFIG(shortcut)
// valueToKeySequence() is copied from qquickshortcut.cpp
static QKeySequence valueToKeySequence(const QVariant &value)
{
@@ -128,13 +129,16 @@ static QKeySequence valueToKeySequence(const QVariant &value)
return QKeySequence(static_cast<QKeySequence::StandardKey>(value.toInt()));
return QKeySequence::fromString(value.toString());
}
+#endif
bool QuickTestEvent::keySequence(const QVariant &keySequence)
{
QWindow *window = activeWindow();
if (!window)
return false;
+#if QT_CONFIG(shortcut)
QTest::keySequence(window, valueToKeySequence(keySequence));
+#endif
return true;
}
diff --git a/src/quick/handlers/qquickpointhandler.cpp b/src/quick/handlers/qquickpointhandler.cpp
index 6d6ba07f5c..30f62332ba 100644
--- a/src/quick/handlers/qquickpointhandler.cpp
+++ b/src/quick/handlers/qquickpointhandler.cpp
@@ -59,8 +59,8 @@ QT_BEGIN_NAMESPACE
occurs within the bounds of the \l {PointerHandler::parent}, and
no sibling PointHandler within the same \l {PointerHandler::parent}
has yet acquired a passive grab on that point, and if the other
- constraints such as \l[QML]{SinglePointHandler::acceptedButtons},
- \l {PointerDeviceHandler::acceptedDevices} etc. are satisfied, it's
+ constraints such as \l {PointerDeviceHandler::acceptedButtons}{acceptedButtons}, \l {PointerDeviceHandler::acceptedDevices}{acceptedDevices} etc.
+ are satisfied, it's
eligible, and the PointHandler then acquires a passive grab. In
this way, the \l {PointerHandler::parent} acts like an exclusive
group: there can be multiple instances of PointHandler, and the
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index b4b6bd574e..081645da71 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -230,7 +230,7 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event)
will not take the exclusive grab, but merely a passive grab.
\value TapHandler.WithinBounds
- If the event point leaves the bounds of the \l parent Item, the tap
+ If the event point leaves the bounds of the \c parent Item, the tap
gesture is canceled. The TapHandler will take the exclusive grab on
press, but will release the grab as soon as the boundary constraint
is no longer satisfied.
@@ -238,7 +238,7 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event)
\value TapHandler.ReleaseWithinBounds
At the time of release (the mouse button is released or the finger
is lifted), if the event point is outside the bounds of the
- \l parent Item, a tap gesture is not recognized. This corresponds to
+ \c parent Item, a tap gesture is not recognized. This corresponds to
typical behavior for button widgets: you can cancel a click by
dragging outside the button, and you can also change your mind by
dragging back inside the button before release. Note that it's
@@ -383,7 +383,7 @@ void QQuickTapHandler::updateTimeHeld()
/*!
\qmlsignal QtQuick::TapHandler::tapped
- This signal is emitted each time the \l parent Item is tapped.
+ This signal is emitted each time the \c parent Item is tapped.
That is, if you press and release a touchpoint or button within a time
period less than \l longPressThreshold, while any movement does not exceed
@@ -395,7 +395,7 @@ void QQuickTapHandler::updateTimeHeld()
\qmlsignal QtQuick::TapHandler::singleTapped
\since 5.11
- This signal is emitted when the \l parent Item is tapped once.
+ This signal is emitted when the \c parent Item is tapped once.
After an amount of time greater than QStyleHints::mouseDoubleClickInterval,
it can be tapped again; but if the time until the next tap is less,
\l tapCount will increase.
@@ -405,7 +405,7 @@ void QQuickTapHandler::updateTimeHeld()
\qmlsignal QtQuick::TapHandler::doubleTapped
\since 5.11
- This signal is emitted when the \l parent Item is tapped twice within a
+ This signal is emitted when the \c parent Item is tapped twice within a
short span of time (QStyleHints::mouseDoubleClickInterval) and distance
(QPlatformTheme::MouseDoubleClickDistance or
QPlatformTheme::TouchDoubleTapDistance). This signal always occurs after
@@ -415,11 +415,18 @@ void QQuickTapHandler::updateTimeHeld()
/*!
\qmlsignal QtQuick::TapHandler::longPressed
- This signal is emitted when the \l parent Item is pressed and held for a
+ This signal is emitted when the \c parent Item is pressed and held for a
time period greater than \l longPressThreshold. That is, if you press and
hold a touchpoint or button, while any movement does not exceed the drag
threshold, then the \c longPressed signal will be emitted at the time that
\l timeHeld exceeds \l longPressThreshold.
*/
+/*!
+ \qmlsignal QtQuick::TapHandler::tapCountChanged
+
+ This signal is emitted when the \c parent Item is tapped once or more (within
+ a specified time and distance span) and when the present \c tapCount differs
+ from the previous \c tapCount.
+*/
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 2eaab164a0..c43eab6b8a 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -864,8 +864,11 @@ void QQuickEventPoint::setGrabberItem(QQuickItem *grabber)
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(grabber->window());
windowPriv->sendUngrabEvent(oldGrabberItem, windowPriv->isDeliveringTouchAsMouse());
}
- for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers)
- passiveGrabber->onGrabChanged(passiveGrabber, OverrideGrabPassive, this);
+ if (grabber) {
+ for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers)
+ if (passiveGrabber)
+ passiveGrabber->onGrabChanged(passiveGrabber, OverrideGrabPassive, this);
+ }
}
}
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index cf882e8c9e..d6dddc3f1c 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -786,7 +786,7 @@ void QQuickFlickable::setContentX(qreal pos)
d->hData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(true, false);
- if (-pos != d->hData.move.value())
+ if (!qFuzzyCompare(-pos, d->hData.move.value()))
d->hData.move.setValue(-pos);
}
@@ -804,7 +804,7 @@ void QQuickFlickable::setContentY(qreal pos)
d->vData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(false, true);
- if (-pos != d->vData.move.value())
+ if (!qFuzzyCompare(-pos, d->vData.move.value()))
d->vData.move.setValue(-pos);
}
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index b45cb09c4b..f298803c7f 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -226,10 +226,12 @@ bool QQuickItemGrabResult::event(QEvent *e)
Q_D(QQuickItemGrabResult);
if (e->type() == Event_Grab_Completed) {
// JS callback
- if (d->qmlEngine && d->callback.isCallable())
+ if (d->qmlEngine && d->callback.isCallable()) {
d->callback.call(QJSValueList() << d->qmlEngine->newQObject(this));
- else
+ deleteLater();
+ } else {
Q_EMIT ready();
+ }
return true;
}
return QObject::event(e);
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 675208d75c..ac3397d2a9 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -133,7 +133,7 @@
width, unless the \l columnWidthProvider property is explicitly set. Once
the column width is found, all other items in the same column are resized
to this width, even if new items that are flicked in later have larger
- \c implicitWidth. Setting an explicit \l width on an item is ignored and
+ \c implicitWidth. Setting an explicit \c width on an item is ignored and
overwritten.
\note The calculated width of a column is discarded when it is flicked out
@@ -265,9 +265,10 @@
applies to \c row and \c column. Properties of the model are also available
depending upon the type of \l {qml-data-models}{Data Model}.
- A delegate should specify its size using \l implicitWidth and \l implicitHeight.
- The TableView lays out the items based on that information. Explicit \l width or
- \l height settings are ignored and overwritten.
+ A delegate should specify its size using \l [QML]{Item::implicitWidth}{implicitWidth} and
+ \l [QML]{Item::implicitHeight}{implicitHeight}.
+ The TableView lays out the items based on that information. Explicit width or
+ height settings are ignored and overwritten.
\note Delegates are instantiated as needed and may be destroyed at any time.
They are also reused if the \l reuseItems property is set to \c true. You
@@ -289,7 +290,7 @@
/*!
\qmlproperty real QtQuick::TableView::contentWidth
- This property holds the width of the \l contentView, which is also
+ This property holds the width of the \l view, which is also
the width of the table (including margins). As a TableView cannot
always know the exact width of the table without loading all columns
in the model, the \c contentWidth is usually an estimated width based on
@@ -307,7 +308,7 @@
/*!
\qmlproperty real QtQuick::TableView::contentHeight
- This property holds the height of the \l contentView, which is also
+ This property holds the height of the \l view, which is also
the height of the table (including margins). As a TableView cannot
always know the exact height of the table without loading all rows
in the model, the \c contentHeight is usually an estimated height
@@ -328,7 +329,7 @@
Responding to changes in the model are batched so that they are handled
only once per frame. This means the TableView delays showing any changes
while a script is being run. The same is also true when changing
- properties such as \l rowSpacing or \l leftMargin.
+ properties such as \l rowSpacing or \l {Item::anchors.leftMargin}{leftMargin}.
This method forces the TableView to immediately update the layout so
that any recent changes take effect.
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 9e447d40ac..73b151168e 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -442,7 +442,7 @@ void QQuickTextPrivate::updateSize()
if (internalWidthUpdate)
return;
- extra->doc->setPageSize(QSizeF());
+ extra->doc->setPageSize(QSizeF(q->width(), -1));
if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < availableWidth()))
extra->doc->setTextWidth(availableWidth());
else
@@ -1247,7 +1247,7 @@ void QQuickTextPrivate::ensureDoc()
if (!extra.isAllocated() || !extra->doc) {
Q_Q(QQuickText);
extra.value().doc = new QQuickTextDocumentWithImageResources(q);
- extra->doc->setPageSize(QSizeF(0, 0));
+ extra->doc->setPageSize(QSizeF(q->width(), -1));
extra->doc->setDocumentMargin(0);
extra->doc->setBaseUrl(q->baseUrl());
qmlobject_connect(extra->doc, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()),
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index d84932b8d0..a1b5eb1faf 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -967,9 +967,14 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
QVarLengthArray<QTextLayout::FormatRange> colorChanges;
mergeFormats(block.layout(), &colorChanges);
- QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft() + position;
+ const QTextCharFormat charFormat = block.charFormat();
+ const QRectF blockBoundingRect = textDocument->documentLayout()->blockBoundingRect(block).translated(position);
+
+ if (charFormat.background().style() != Qt::NoBrush)
+ m_backgrounds.append(qMakePair(blockBoundingRect, charFormat.background().color()));
+
if (QTextList *textList = block.textList()) {
- QPointF pos = blockPosition;
+ QPointF pos = blockBoundingRect.topLeft();
QTextLayout *layout = block.layout();
if (layout->lineCount() > 0) {
QTextLine firstLine = layout->lineAt(0);
@@ -982,7 +987,6 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
if (block.textDirection() == Qt::RightToLeft)
pos.rx() += textRect.width();
- const QTextCharFormat charFormat = block.charFormat();
QFont font(charFormat.font());
QFontMetricsF fontMetrics(font);
QTextListFormat listFormat = textList->format();
@@ -1043,11 +1047,11 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
int fontHeight = fontMetrics.descent() + fontMetrics.ascent();
int valign = charFormat.verticalAlignment();
if (valign == QTextCharFormat::AlignSuperScript)
- setPosition(QPointF(blockPosition.x(), blockPosition.y() - fontHeight / 2));
+ setPosition(QPointF(blockBoundingRect.x(), blockBoundingRect.y() - fontHeight / 2));
else if (valign == QTextCharFormat::AlignSubScript)
- setPosition(QPointF(blockPosition.x(), blockPosition.y() + fontHeight / 6));
+ setPosition(QPointF(blockBoundingRect.x(), blockBoundingRect.y() + fontHeight / 6));
else
- setPosition(blockPosition);
+ setPosition(blockBoundingRect.topLeft());
if (text.contains(QChar::ObjectReplacementCharacter)) {
QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat));
@@ -1101,7 +1105,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
#if QT_CONFIG(im)
if (preeditLength >= 0 && textPos <= block.position() + preeditPosition) {
- setPosition(blockPosition);
+ setPosition(blockBoundingRect.topLeft());
textPos = block.position() + preeditPosition;
QTextLine line = block.layout()->lineForTextPosition(preeditPosition);
if (!currentLine().isValid()
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 485c0dfea7..8363a7bca0 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1613,7 +1613,9 @@ bool QQuickWindow::event(QEvent *e)
bool accepted = enter->isAccepted();
bool delivered = d->deliverHoverEvent(d->contentItem, enter->windowPos(), d->lastMousePosition,
QGuiApplication::keyboardModifiers(), 0L, accepted);
+ d->lastMousePosition = enter->windowPos();
enter->setAccepted(accepted);
+ d->updateCursor(mapFromGlobal(QCursor::pos()));
return delivered;
}
break;
@@ -2527,18 +2529,22 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event,
int pointCount = event->pointCount();
QVector<QQuickItem *> targetItems;
bool isTouchEvent = (event->asPointerTouchEvent() != nullptr);
- if (isTouchEvent && event->isPressEvent() && isDeliveringTouchAsMouse() &&
- pointerEventInstance(touchMouseDevice)->pointById(touchMouseId)->grabberPointerHandler()) {
- // When a second point is pressed, if the first point's existing
- // grabber was a pointer handler while a filtering parent is filtering
- // the same first point _as mouse_: we're starting over with delivery,
- // so we need to allow the second point to now be sent as a synth-mouse
- // instead of the first one, so that filtering parents (maybe even the
- // same one) can get a chance to see the second touchpoint as a
- // synth-mouse and perhaps grab it. Ideally we would always do this
- // when a new touchpoint is pressed, but this compromise fixes
- // QTBUG-70998 and avoids breaking tst_FlickableInterop::touchDragSliderAndFlickable
- cancelTouchMouseSynthesis();
+ if (isTouchEvent && event->isPressEvent() && isDeliveringTouchAsMouse()) {
+ if (const QQuickEventPoint *point = pointerEventInstance(touchMouseDevice)->pointById(touchMouseId)) {
+ // When a second point is pressed, if the first point's existing
+ // grabber was a pointer handler while a filtering parent is filtering
+ // the same first point _as mouse_: we're starting over with delivery,
+ // so we need to allow the second point to now be sent as a synth-mouse
+ // instead of the first one, so that filtering parents (maybe even the
+ // same one) can get a chance to see the second touchpoint as a
+ // synth-mouse and perhaps grab it. Ideally we would always do this
+ // when a new touchpoint is pressed, but this compromise fixes
+ // QTBUG-70998 and avoids breaking tst_FlickableInterop::touchDragSliderAndFlickable
+ if (point->grabberPointerHandler())
+ cancelTouchMouseSynthesis();
+ } else {
+ qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << touchMouseId << "is missing from" << event;
+ }
}
for (int i = 0; i < pointCount; ++i) {
auto point = event->point(i);
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index 489d1c86f7..262d0b3e9a 100644
--- a/src/quickshapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -805,9 +805,8 @@ QQuickShape::Status QQuickShape::status() const
\since QtQuick.Shapes 1.11
This property determines the definition of \l {QQuickItem::contains()}{contains()}
- for the Shape. It is useful in case you add
- \l {Qt Quick Pointer Handlers QML Types}{Pointer Handlers} and you
- want to react only when the mouse or touchpoint is fully inside the Shape.
+ for the Shape. It is useful in case you add \l {Qt Quick Input Handlers} and you want to
+ react only when the mouse or touchpoint is fully inside the Shape.
\value Shape.BoundingRectContains
The default implementation of \l QQuickItem::contains() checks only
diff --git a/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp b/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
index 974357dc8e..6bd8c2a2e0 100644
--- a/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
@@ -261,15 +261,18 @@ void tst_QAnimationGroupJob::addChildTwice()
{
QAbstractAnimationJob *subGroup;
QAbstractAnimationJob *subGroup2;
- QAnimationGroupJob *parent = new QSequentialAnimationGroupJob();
+ auto *parent = new QSequentialAnimationGroupJob();
subGroup = new QAbstractAnimationJob;
parent->appendAnimation(subGroup);
parent->appendAnimation(subGroup);
- QVERIFY(parent->firstChild() && !parent->firstChild()->nextSibling());
+ QVERIFY(parent->firstChild());
+ QVERIFY(!parent->firstChild()->nextSibling());
+ QVERIFY(!parent->firstChild()->previousSibling());
parent->clear();
+ QCOMPARE(parent->currentAnimation(), nullptr);
QVERIFY(!parent->firstChild());
// adding the same item twice to a group will remove the item from its current position
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index eaf60aec38..fdef1c0956 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -361,6 +361,9 @@ private slots:
void importLexicalVariables();
void hugeObject();
void templateStringTerminator();
+ void arrayAndException();
+ void numberToStringWithRadix();
+ void tailCallWithArguments();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -8876,6 +8879,41 @@ void tst_qqmlecmascript::templateStringTerminator()
QCOMPARE(value.toString(), QLatin1String("x123\ny^"));
}
+void tst_qqmlecmascript::arrayAndException()
+{
+ QJSEngine engine;
+ const QJSValue value = engine.evaluate("[...[],[,,$]]");
+ // Should not crash
+ QVERIFY(value.isError());
+}
+
+void tst_qqmlecmascript::numberToStringWithRadix()
+{
+ QJSEngine engine;
+ {
+ const QJSValue value = engine.evaluate(".5.toString(5)");
+ QVERIFY(!value.isError());
+ QVERIFY(value.toString().startsWith("0.2222222222"));
+ }
+ {
+ const QJSValue value = engine.evaluate(".05.toString(5)");
+ QVERIFY(!value.isError());
+ QVERIFY(value.toString().startsWith("0.01111111111"));
+ }
+}
+
+void tst_qqmlecmascript::tailCallWithArguments()
+{
+ QJSEngine engine;
+ const QJSValue value = engine.evaluate(
+ "'use strict';\n"
+ "[[1, 2]].map(function (a) {\n"
+ " return (function() { return Math.min.apply(this, arguments); })(a[0], a[1]);\n"
+ "})[0];");
+ QVERIFY(!value.isError());
+ QCOMPARE(value.toInt(), 1);
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
index 2511eebefe..341a49bf09 100644
--- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
+++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
@@ -109,7 +109,10 @@ void tst_qqmlextensionplugin::iidCheck()
if (qobject_cast<QQmlExtensionPlugin *>(loader.instance())) {
QString iid = loader.metaData().value(QStringLiteral("IID")).toString();
- QCOMPARE(iid, QLatin1String(QQmlExtensionInterface_iid));
+ if (iid == QLatin1String(QQmlExtensionInterface_iid_old))
+ qWarning() << "Old extension plugin found. Update the IID" << loader.metaData();
+ else
+ QCOMPARE(iid, QLatin1String(QQmlExtensionInterface_iid));
}
}
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml
new file mode 100644
index 0000000000..1bd20c6bcb
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+
+Item {
+ width: 640
+ height: 480
+
+ Loader {
+ id: loader
+
+ width: 480
+ height: 480
+
+ sourceComponent: Rectangle {
+ id: item2
+ anchors.fill: parent
+ color: "blue"
+
+ DragHandler{}
+ }
+ }
+
+ Rectangle {
+ color: "yellow"
+ width: 180
+ height: 180
+
+ MultiPointTouchArea {
+ anchors.fill: parent
+ touchPoints: [
+ TouchPoint { onPressedChanged: loader.sourceComponent = undefined }
+ ]
+ }
+ }
+}
+
+
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
index b994e0fc07..bf582b820b 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
@@ -55,6 +55,7 @@ private slots:
void touchDrag();
void touchesThenPinch();
+ void unloadHandlerWithPassiveGrab();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
@@ -282,6 +283,24 @@ void tst_MptaInterop::touchesThenPinch()
QTRY_COMPARE(mptaReleasedSpy.count(), 1);
}
+void tst_MptaInterop::unloadHandlerWithPassiveGrab()
+{
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "unloadHandlerOnPress.qml");
+ QQuickView * window = windowPtr.data();
+
+ QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>();
+ QVERIFY(handler);
+ QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>();
+ QVERIFY(mpta);
+
+ QPoint point(90, 90);
+ QTest::mousePress(window, Qt::LeftButton, 0, point);
+ QCOMPARE(window->mouseGrabberItem(), mpta);
+ QTRY_VERIFY(handler.isNull()); // it got unloaded
+ QTest::mouseRelease(window, Qt::LeftButton, 0, point); // QTBUG-73819: don't crash
+}
+
QTEST_MAIN(tst_MptaInterop)
#include "tst_multipointtoucharea_interop.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
index 9045247e94..011dc4e75f 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
@@ -90,7 +90,7 @@ Rectangle {
id: paddle
objectName: "paddle"
width: 100
- height: 40
+ height: 100
color: paddleHH.hovered ? "indianred" : "#888"
x: (parent.width - width) / 2
y: parent.height - 100
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
index 52074aec4f..f141a2546c 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
@@ -60,6 +60,7 @@ private slots:
void hoverHandlerAndUnderlyingHoverHandler();
void mouseAreaAndUnderlyingHoverHandler();
void hoverHandlerAndUnderlyingMouseArea();
+ void movingItemWithHoverHandler();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
@@ -229,6 +230,42 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingMouseArea()
QCOMPARE(buttonHoveredSpy.count(), 2);
}
+void tst_HoverHandler::movingItemWithHoverHandler()
+{
+ if (isPlatformWayland())
+ QSKIP("Wayland: QCursor::setPos() doesn't work.");
+
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "lesHoverables.qml");
+ QQuickView * window = windowPtr.data();
+ QQuickItem * paddle = window->rootObject()->findChild<QQuickItem *>("paddle");
+ QVERIFY(paddle);
+ QQuickHoverHandler *paddleHH = paddle->findChild<QQuickHoverHandler *>("paddleHH");
+ QVERIFY(paddleHH);
+
+ // Find the global coordinate of the paddle
+ const QPoint p(paddle->mapToScene(paddle->clipRect().center()).toPoint());
+ const QPoint paddlePos = window->mapToGlobal(p);
+
+ // Now hide the window, put the cursor where the paddle was and show it again
+ window->hide();
+ QTRY_COMPARE(window->isVisible(), false);
+ QCursor::setPos(paddlePos);
+ window->show();
+ QTest::qWaitForWindowExposed(window);
+
+ QTRY_COMPARE(paddleHH->isHovered(), true);
+
+ paddle->setX(100);
+ QTRY_COMPARE(paddleHH->isHovered(), false);
+
+ paddle->setX(p.x());
+ QTRY_COMPARE(paddleHH->isHovered(), true);
+
+ paddle->setX(540);
+ QTRY_COMPARE(paddleHH->isHovered(), false);
+}
+
QTEST_MAIN(tst_HoverHandler)
#include "tst_qquickhoverhandler.moc"
diff --git a/tests/auto/quick/qquickshortcut/BLACKLIST b/tests/auto/quick/qquickshortcut/BLACKLIST
new file mode 100644
index 0000000000..ba7871dc2d
--- /dev/null
+++ b/tests/auto/quick/qquickshortcut/BLACKLIST
@@ -0,0 +1,7 @@
+# QTBUG-74050
+[shortcuts]
+opensuse-42.3
+
+# QTBUG-74050
+[multiple]
+opensuse-42.3
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index 42dc766a13..aaf37b32cd 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -569,7 +569,10 @@ void tst_qquickwidget::mouseEventWindowPos()
QVERIFY(!rootItem->property("wasClicked").toBool());
QVERIFY(!rootItem->property("wasDoubleClicked").toBool());
- QVERIFY(!rootItem->property("wasMoved").toBool());
+ // Moving an item under the mouse cursor will trigger a mouse move event.
+ // The above quick->move() will trigger a mouse move event on macOS.
+ // Discard that in order to get a clean slate for the actual tests.
+ rootItem->setProperty("wasMoved", QVariant(false));
QWindow *window = widget.windowHandle();
QVERIFY(window);
diff --git a/tests/manual/cursorChange/main.qml b/tests/manual/cursorChange/main.qml
new file mode 100644
index 0000000000..563545b60d
--- /dev/null
+++ b/tests/manual/cursorChange/main.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the manual tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Window 2.0
+
+Window {
+ id: tw
+ visible: true
+ width: 800
+ height: 500
+ color: "green"
+ Text {
+ id: txt
+ font.pointSize: 16
+ anchors.top: parent.top
+ text: "Move to the blue item.\nCheck the mouse cursor is a PointingHand.\nClick on the blue item."
+ }
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 100
+ height: 50
+ color: "blue"
+ MouseArea {
+ id: testHand
+ anchors.fill: parent
+ onClicked: {
+ tw1.show()
+ }
+ cursorShape: Qt.PointingHandCursor
+ }
+ }
+
+ Window {
+ Text {
+ font.pointSize: 16
+ anchors.top: parent.top
+ text: "Move the cursor to near one of the edges.\nClick the mouse button."
+ }
+ id: tw1
+ visible: false
+ width: 800
+ height: 500
+ color: "yellow"
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ tw1.close()
+ txt.text = "Mouse cursor should now be back to an Arrow cursor"
+ }
+ }
+ }
+}
diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf
index c7899c5100..9c8c7a7b1e 100644
--- a/tools/qmlcachegen/qtquickcompiler.prf
+++ b/tools/qmlcachegen/qtquickcompiler.prf
@@ -1,3 +1,4 @@
+qtc_run: return()
qtPrepareTool(QML_CACHEGEN, qmlcachegen, _FILTER)
qtPrepareTool(QMAKE_RCC, rcc, _DEP)
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index 565152d5d2..f3b931fbbf 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -163,10 +163,6 @@ public:
*/
static QHash<QByteArray, QSet<QQmlType> > qmlTypesByCppName;
-/* A composite type is completely specified by name, major version and minor version.
-*/
-static QMap<QString, QSet<QQmlType> > qmlTypesByCompositeName;
-
static QHash<QByteArray, QByteArray> cppToId;
/* Takes a C++ type name, such as Qt::LayoutDirection or QString and
@@ -208,14 +204,15 @@ QByteArray convertToId(const QMetaObject *mo)
// Collect all metaobjects for types registered with qmlRegisterType() without parameters
-void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet<const QMetaObject *>& metas ) {
+void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet<const QMetaObject *>& metas,
+ QMap<QString, QSet<QQmlType>> &compositeTypes) {
const auto qmlAllTypes = QQmlMetaType::qmlAllTypes();
for (const QQmlType &ty : qmlAllTypes) {
if (!metas.contains(ty.baseMetaObject())) {
if (!ty.isComposite()) {
collectReachableMetaObjects(engine, ty, &metas);
} else {
- qmlTypesByCompositeName[ty.elementName()].insert(ty);
+ compositeTypes[ty.elementName()].insert(ty);
}
}
}
@@ -224,6 +221,7 @@ void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet<c
QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
QSet<const QMetaObject *> &noncreatables,
QSet<const QMetaObject *> &singletons,
+ QMap<QString, QSet<QQmlType>> &compositeTypes,
const QList<QQmlType> &skip = QList<QQmlType>())
{
QSet<const QMetaObject *> metas;
@@ -239,7 +237,7 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
qmlTypesByCppName[ty.baseMetaObject()->className()].insert(ty);
collectReachableMetaObjects(QQmlEnginePrivate::get(engine), ty, &metas);
} else {
- qmlTypesByCompositeName[ty.elementName()].insert(ty);
+ compositeTypes[ty.elementName()].insert(ty);
}
}
@@ -304,7 +302,7 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
}
}
- collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate::get(engine), metas);
+ collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate::get(engine), metas, compositeTypes);
return metas;
}
@@ -1184,7 +1182,8 @@ int main(int argc, char *argv[])
// find all QMetaObjects reachable from the builtin module
QSet<const QMetaObject *> uncreatableMetas;
QSet<const QMetaObject *> singletonMetas;
- QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas);
+ QMap<QString, QSet<QQmlType>> defaultCompositeTypes;
+ QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, defaultCompositeTypes);
QList<QQmlType> defaultTypes = QQmlMetaType::qmlTypes();
// add some otherwise unreachable QMetaObjects
@@ -1195,6 +1194,9 @@ int main(int argc, char *argv[])
// this will hold the meta objects we want to dump information of
QSet<const QMetaObject *> metas;
+ // composite types we want to dump information of
+ QMap<QString, QSet<QQmlType>> compositeTypes;
+
if (action == Builtins) {
for (const QMetaObject *m : qAsConst(defaultReachable)) {
if (m->className() == QLatin1String("Qt")) {
@@ -1268,9 +1270,17 @@ int main(int argc, char *argv[])
}
}
- QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, defaultTypes);
+ QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, compositeTypes, defaultTypes);
candidates.subtract(defaultReachable);
+ for (QString iter: compositeTypes.keys()) {
+ if (defaultCompositeTypes.contains(iter)) {
+ QSet<QQmlType> compositeTypesByName = compositeTypes.value(iter);
+ compositeTypesByName.subtract(defaultCompositeTypes.value(iter));
+ compositeTypes[iter] = compositeTypesByName;
+ }
+ }
+
// Also eliminate meta objects with the same classname.
// This is required because extended objects seem not to share
// a single meta object instance.
@@ -1324,8 +1334,8 @@ int main(int argc, char *argv[])
dumper.dump(QQmlEnginePrivate::get(&engine), meta, uncreatableMetas.contains(meta), singletonMetas.contains(meta));
}
- QMap<QString, QSet<QQmlType> >::const_iterator iter = qmlTypesByCompositeName.constBegin();
- for (; iter != qmlTypesByCompositeName.constEnd(); ++iter)
+ QMap<QString, QSet<QQmlType> >::const_iterator iter = compositeTypes.constBegin();
+ for (; iter != compositeTypes.constEnd(); ++iter)
dumper.dumpComposite(&engine, iter.value(), defaultReachableNames);
// define QEasingCurve as an extension of QQmlEasingValueType, this way