From 7914038bde361b98904579b191004f4428f1e9a6 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Wed, 21 Apr 2021 10:39:27 +0200 Subject: QmlDesigner: Fix RangeSliderSpecifics snap mode Task-number: QDS-4212 Change-Id: I82d524960a34e9307ddf9b154a326d8fadc7387c Reviewed-by: Mitch Curtis (cherry picked from commit f42abbcb7794bcfc884e8aee75f73bd9ab8fbda4) Reviewed-by: Qt Cherry-pick Bot --- src/imports/controls/designer/RangeSliderSpecifics.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imports/controls/designer/RangeSliderSpecifics.qml b/src/imports/controls/designer/RangeSliderSpecifics.qml index 662700ee..3b24b3d1 100644 --- a/src/imports/controls/designer/RangeSliderSpecifics.qml +++ b/src/imports/controls/designer/RangeSliderSpecifics.qml @@ -127,7 +127,7 @@ Column { } SecondColumnLayout { ComboBox { - backendValue: backendValues.orientation + backendValue: backendValues.snapMode model: [ "NoSnap", "SnapOnRelease", "SnapAlways" ] scope: "RangeSlider" Layout.fillWidth: true -- cgit v1.2.3 From 470abc3566ead79a5c0b14b3dea4b40418cc1029 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 23 Apr 2021 10:10:13 +0200 Subject: Change the name of the material style plugin to avoid a path limit On Android 5, the path length limit is low enough that it causes the material style plugin to be too long. So we adjust the name of the plugin to enable it to be loaded without a problem. Change-Id: Id8713d93164ea57cccfff037b074f2e17b351a34 Reviewed-by: Mitch Curtis Reviewed-by: Assam Boudjelthia --- src/imports/controls/material/material.pro | 2 +- src/imports/controls/material/qmldir | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/imports/controls/material/material.pro b/src/imports/controls/material/material.pro index cf08b925..ea74d277 100644 --- a/src/imports/controls/material/material.pro +++ b/src/imports/controls/material/material.pro @@ -1,4 +1,4 @@ -TARGET = qtquickcontrols2materialstyleplugin +TARGET = qqc2materialstyleplugin TARGETPATH = QtQuick/Controls.2/Material IMPORT_NAME = QtQuick.Controls.Material diff --git a/src/imports/controls/material/qmldir b/src/imports/controls/material/qmldir index 870a0382..d48b7b12 100644 --- a/src/imports/controls/material/qmldir +++ b/src/imports/controls/material/qmldir @@ -1,4 +1,4 @@ module QtQuick.Controls.Material -plugin qtquickcontrols2materialstyleplugin +plugin qqc2materialstyleplugin classname QtQuickControls2MaterialStylePlugin depends QtQuick.Controls 2.5 -- cgit v1.2.3 From 16d946701d7fc38fce264ffdb4d5443ffcb50514 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 23 Apr 2021 12:16:26 +0200 Subject: ScrollView: fix crash when scrolling with zero-sized item Check if a Flickable type was actually set as the contentItem before accessing the pointer. Also warn that using a type other than Flickable is not supported. Fixes: QTBUG-93039 Change-Id: I1470766c6de02b7b601edf1375791d3147f26ab5 Reviewed-by: Volker Hilsheimer (cherry picked from commit e7df2279bf5519703fd0b853abaa23947a599920) --- src/quicktemplates2/qquickscrollbar.cpp | 6 ++++++ src/quicktemplates2/qquickscrollview.cpp | 6 +++++- tests/auto/controls/data/tst_scrollview.qml | 24 ++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp index fdbd4b31..1ac4b42d 100644 --- a/src/quicktemplates2/qquickscrollbar.cpp +++ b/src/quicktemplates2/qquickscrollbar.cpp @@ -869,6 +869,9 @@ class QQuickFriendlyFlickable : public QQuickFlickable void QQuickScrollBarAttachedPrivate::scrollHorizontal() { + if (!flickable) + return; + QQuickFriendlyFlickable *f = reinterpret_cast(flickable); const qreal viewwidth = f->width(); @@ -881,6 +884,9 @@ void QQuickScrollBarAttachedPrivate::scrollHorizontal() void QQuickScrollBarAttachedPrivate::scrollVertical() { + if (!flickable) + return; + QQuickFriendlyFlickable *f = reinterpret_cast(flickable); const qreal viewheight = f->height(); diff --git a/src/quicktemplates2/qquickscrollview.cpp b/src/quicktemplates2/qquickscrollview.cpp index 387c30a5..0c9d8f3e 100644 --- a/src/quicktemplates2/qquickscrollview.cpp +++ b/src/quicktemplates2/qquickscrollview.cpp @@ -38,6 +38,7 @@ #include "qquickpane_p_p.h" #include "qquickscrollbar_p_p.h" +#include #include QT_BEGIN_NAMESPACE @@ -575,7 +576,10 @@ void QQuickScrollView::contentItemChange(QQuickItem *newItem, QQuickItem *oldIte // assume/require that it has an explicit content size assigned. d->flickableHasExplicitContentWidth = true; d->flickableHasExplicitContentHeight = true; - d->setFlickable(qobject_cast(newItem), false); + auto newItemAsFlickable = qobject_cast(newItem); + if (newItem && !newItemAsFlickable) + qmlWarning(this) << "ScrollView only supports Flickable types as its contentItem"; + d->setFlickable(newItemAsFlickable, false); } QQuickPane::contentItemChange(newItem, oldItem); } diff --git a/tests/auto/controls/data/tst_scrollview.qml b/tests/auto/controls/data/tst_scrollview.qml index 87c39509..453f7753 100644 --- a/tests/auto/controls/data/tst_scrollview.qml +++ b/tests/auto/controls/data/tst_scrollview.qml @@ -502,4 +502,28 @@ TestCase { compare(control.contentWidth, flickable.contentWidth) compare(control.contentHeight, flickable.contentHeight) } + + Component { + id: zeroSizedContentItemComponent + ScrollView { + width: 100 + height: 100 + contentItem: Item {} + } + } + + function test_zeroSizedContentItem() { + ignoreWarning(/ScrollView only supports Flickable types as its contentItem/) + let control = createTemporaryObject(zeroSizedContentItemComponent, testCase) + verify(control) + + let verticalScrollBar = control.ScrollBar.vertical + verify(verticalScrollBar) + // Scrolling a ScrollView with a zero-sized contentItem shouldn't crash. + mouseDrag(verticalScrollBar, verticalScrollBar.width / 2, verticalScrollBar.height / 2, 0, 50) + + let horizontalScrollBar = control.ScrollBar.horizontal + verify(verticalScrollBar) + mouseDrag(horizontalScrollBar, horizontalScrollBar.width / 2, horizontalScrollBar.height / 2, 50, 0) + } } -- cgit v1.2.3 From f9bc1b540413466b53ecf6d15016422ada314181 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 3 May 2021 12:21:54 +0200 Subject: QQuickDial: Keep value integer if everything is integer If a user uses integer values for stepSize, from and to in a Dial, they most likely want the actual values of the Dial to be integers, too. Detect this condition, and store it in a new boolean member. If the condition is met, we round the value in QQuickDialPrivate::valueAt (which, due to floating point math might not be an exact integer). As a drive-by, reorder the boolean members to introduce no additional space overhead. Fixes: QTBUG-92214 Change-Id: If4633fae1d7d425ca7fb767c7284d6f8ea7ce78c Reviewed-by: Mitch Curtis (cherry picked from commit 42687caf7bc7496b838995f3fa68194ca8323da3) --- src/quicktemplates2/qquickdial.cpp | 33 ++++++++++++++++++++++++++++++--- tests/auto/controls/data/tst_dial.qml | 15 +++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp index 27a510c8..89901842 100644 --- a/src/quicktemplates2/qquickdial.cpp +++ b/src/quicktemplates2/qquickdial.cpp @@ -41,6 +41,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE /*! @@ -116,25 +118,37 @@ public: void cancelHandle(); void executeHandle(bool complete = false); + void updateAllValuesAreInteger(); + qreal from = 0; qreal to = 1; qreal value = 0; qreal position = 0; qreal angle = startAngle; qreal stepSize = 0; - bool pressed = false; QPointF pressPoint; qreal positionBeforePress = 0; QQuickDial::SnapMode snapMode = QQuickDial::NoSnap; QQuickDial::InputMode inputMode = QQuickDial::Circular; + QQuickDeferredPointer handle; bool wrap = false; bool live = true; - QQuickDeferredPointer handle; + bool pressed = false; + bool allValuesAreInteger = false; }; qreal QQuickDialPrivate::valueAt(qreal position) const { - return from + (to - from) * position; + qreal value = from + (to - from) * position; + + /* play nice with users expecting that integer from, to and stepSize leads to + integer values - given that we are using floating point internally (and in + the API of value), this does not hold, but it is easy enough to handle + */ + if (allValuesAreInteger) + value = qRound(value); + + return value; } qreal QQuickDialPrivate::snapPosition(qreal position) const @@ -308,6 +322,16 @@ void QQuickDialPrivate::executeHandle(bool complete) quickCompleteDeferred(q, handleName(), handle); } +static bool areRepresentableAsInteger(qreal num1, qreal num2, qreal num3) { + auto check = [](qreal number) -> bool { return std::nearbyint(number) == number; }; + return check(num1) && check(num2) && check(num3); +} + +void QQuickDialPrivate::updateAllValuesAreInteger() +{ + allValuesAreInteger = areRepresentableAsInteger(to, from, stepSize) && stepSize != 0.0; +} + QQuickDial::QQuickDial(QQuickItem *parent) : QQuickControl(*(new QQuickDialPrivate), parent) { @@ -342,6 +366,7 @@ void QQuickDial::setFrom(qreal from) d->from = from; emit fromChanged(); + d->updateAllValuesAreInteger(); if (isComponentComplete()) { setValue(d->value); d->updatePosition(); @@ -369,6 +394,7 @@ void QQuickDial::setTo(qreal to) return; d->to = to; + d->updateAllValuesAreInteger(); emit toChanged(); if (isComponentComplete()) { setValue(d->value); @@ -468,6 +494,7 @@ void QQuickDial::setStepSize(qreal step) return; d->stepSize = step; + d->updateAllValuesAreInteger(); emit stepSizeChanged(); } diff --git a/tests/auto/controls/data/tst_dial.qml b/tests/auto/controls/data/tst_dial.qml index 26f30c33..e3ad2b2f 100644 --- a/tests/auto/controls/data/tst_dial.qml +++ b/tests/auto/controls/data/tst_dial.qml @@ -691,4 +691,19 @@ TestCase { compare(control.pressed, false); compare(control.position, data.expectedPosition); } + + function test_integerStepping() { + var dial = createTemporaryObject(dialComponent, testCase) + verify(dial) + + dial.from = 1 + dial.to = 8 + dial.stepSize = 1 + + for (let i = 1; i < 8; ++i) { + // compare as strings to avoid a fuzzy compare; we want an exact match + compare(""+dial.value, ""+1) + keyClick(Qt.Key_Right) + } + } } -- cgit v1.2.3 From 2b34a7fa43b0f7fcfc8c615abe29f9c29c93bdfb Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 3 May 2021 12:00:09 +0200 Subject: Imagine: fix GroupBox's bottom edge being clipped Use the actual padding from the nine patch image rather than the hard-coded 12. Fixes: QTBUG-91924 Change-Id: I4707ae173c088625657a135680619cf646e3a9e2 Reviewed-by: Richard Moe Gustavsen (cherry picked from commit 9a10ab40b7bc3db21f48ff004c5c5525cbfd40de) Reviewed-by: Qt Cherry-pick Bot --- src/imports/controls/imagine/GroupBox.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/imports/controls/imagine/GroupBox.qml b/src/imports/controls/imagine/GroupBox.qml index 346e9877..4a0bddee 100644 --- a/src/imports/controls/imagine/GroupBox.qml +++ b/src/imports/controls/imagine/GroupBox.qml @@ -53,7 +53,6 @@ T.GroupBox { leftPadding: background ? background.leftPadding : 0 rightPadding: background ? background.rightPadding : 0 bottomPadding: background ? background.bottomPadding : 0 - padding: 12 label: Label { width: control.width @@ -88,7 +87,7 @@ T.GroupBox { x: -leftInset y: control.topPadding - control.bottomPadding - topInset width: control.width + leftInset + rightInset - height: control.height + topInset + bottomInset - control.topPadding + control.padding + height: control.height + topInset + bottomInset - control.topPadding + control.bottomPadding source: Imagine.url + "groupbox-background" NinePatchImageSelector on source { -- cgit v1.2.3 From f45298a3e85959dba7611d7e309ed834491f5d50 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 12 May 2021 12:55:18 +0200 Subject: Allow creation of custom QQuickPopupItem-derived types This allows QQuickPopup-derived types to have their own QQuickPopup-derived popup item. This is useful for controlling e.g. implicit content item sizing. Task-number: QTBUG-83630 Change-Id: I279d2e39df9a9cff29b3015a2f5baae7128f461f Reviewed-by: Fabian Kosmale (cherry picked from commit 6b8a9673111bbf888990ce5904e176057ad4a71b) --- src/quicktemplates2/qquickmenu.cpp | 1 + src/quicktemplates2/qquickmenu_p_p.h | 2 +- src/quicktemplates2/qquickpopup.cpp | 17 ++++- src/quicktemplates2/qquickpopup_p_p.h | 4 +- src/quicktemplates2/qquickpopupitem.cpp | 70 +++++++---------- src/quicktemplates2/qquickpopupitem_p.h | 121 ++++++++++++++++++++++++++++++ src/quicktemplates2/qquickpopupitem_p_p.h | 80 +++++++------------- src/quicktemplates2/quicktemplates2.pri | 1 + 8 files changed, 196 insertions(+), 100 deletions(-) create mode 100644 src/quicktemplates2/qquickpopupitem_p.h diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp index 35af00b4..61f25d35 100644 --- a/src/quicktemplates2/qquickmenu.cpp +++ b/src/quicktemplates2/qquickmenu.cpp @@ -222,6 +222,7 @@ QQuickMenuPrivate::QQuickMenuPrivate() void QQuickMenuPrivate::init() { Q_Q(QQuickMenu); + QQuickPopupPrivate::init(); contentModel = new QQmlObjectModel(q); } diff --git a/src/quicktemplates2/qquickmenu_p_p.h b/src/quicktemplates2/qquickmenu_p_p.h index 7564b655..fee88f01 100644 --- a/src/quicktemplates2/qquickmenu_p_p.h +++ b/src/quicktemplates2/qquickmenu_p_p.h @@ -73,7 +73,7 @@ public: return menu->d_func(); } - void init(); + void init() override; QQuickItem *itemAt(int index) const; void insertItem(int index, QQuickItem *item); diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index ab9740ba..e0363b44 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -275,9 +275,21 @@ QQuickPopupPrivate::QQuickPopupPrivate() void QQuickPopupPrivate::init() { Q_Q(QQuickPopup); - popupItem = new QQuickPopupItem(q); + createPopupItem(); popupItem->setVisible(false); q->setParentItem(qobject_cast(parent)); + connectToPopupItem(); +} + +void QQuickPopupPrivate::createPopupItem() +{ + Q_Q(QQuickPopup); + popupItem = new QQuickPopupItem(q); +} + +void QQuickPopupPrivate::connectToPopupItem() +{ + Q_Q(QQuickPopup); QObject::connect(popupItem, &QQuickControl::paddingChanged, q, &QQuickPopup::paddingChanged); QObject::connect(popupItem, &QQuickControl::backgroundChanged, q, &QQuickPopup::backgroundChanged); QObject::connect(popupItem, &QQuickControl::contentItemChanged, q, &QQuickPopup::contentItemChanged); @@ -842,8 +854,7 @@ QQuickPopup::QQuickPopup(QObject *parent) QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent) : QObject(dd, parent) { - Q_D(QQuickPopup); - d->init(); + dd.init(); } QQuickPopup::~QQuickPopup() diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h index 8422a71f..f9dcbddf 100644 --- a/src/quicktemplates2/qquickpopup_p_p.h +++ b/src/quicktemplates2/qquickpopup_p_p.h @@ -96,7 +96,9 @@ public: QQmlListProperty contentData(); QQmlListProperty contentChildren(); - void init(); + virtual void init(); + void createPopupItem(); + void connectToPopupItem(); void closeOrReject(); bool tryClose(const QPointF &pos, QQuickPopup::ClosePolicy flags); diff --git a/src/quicktemplates2/qquickpopupitem.cpp b/src/quicktemplates2/qquickpopupitem.cpp index df94577a..e4a63303 100644 --- a/src/quicktemplates2/qquickpopupitem.cpp +++ b/src/quicktemplates2/qquickpopupitem.cpp @@ -53,38 +53,33 @@ QT_BEGIN_NAMESPACE -class QQuickPopupItemPrivate : public QQuickPagePrivate -{ - Q_DECLARE_PUBLIC(QQuickPopupItem) - -public: - QQuickPopupItemPrivate(QQuickPopup *popup); - - void implicitWidthChanged() override; - void implicitHeightChanged() override; - - void resolveFont() override; - void resolvePalette() override; - - QQuickItem *getContentItem() override; - - void cancelContentItem() override; - void executeContentItem(bool complete = false) override; - - void cancelBackground() override; - void executeBackground(bool complete = false) override; - - int backId = 0; - int escapeId = 0; - QQuickPopup *popup = nullptr; -}; - QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup) : popup(popup) { isTabFence = true; } +void QQuickPopupItemPrivate::init() +{ + Q_Q(QQuickPopupItem); + q->setParent(popup); + q->setFlag(QQuickItem::ItemIsFocusScope); + q->setAcceptedMouseButtons(Qt::AllButtons); +#if QT_CONFIG(quicktemplates2_multitouch) + q->setAcceptTouchEvents(true); +#endif +#if QT_CONFIG(cursor) + q->setCursor(Qt::ArrowCursor); +#endif + +#if QT_CONFIG(quicktemplates2_hover) + // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8 + q->setHoverEnabled(true); + // setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects()); + // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, this, &QQuickItem::setAcceptHoverEvents); +#endif +} + void QQuickPopupItemPrivate::implicitWidthChanged() { QQuickPagePrivate::implicitWidthChanged(); @@ -161,22 +156,15 @@ void QQuickPopupItemPrivate::executeBackground(bool complete) QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup) : QQuickPage(*(new QQuickPopupItemPrivate(popup)), nullptr) { - setParent(popup); - setFlag(ItemIsFocusScope); - setAcceptedMouseButtons(Qt::AllButtons); -#if QT_CONFIG(quicktemplates2_multitouch) - setAcceptTouchEvents(true); -#endif -#if QT_CONFIG(cursor) - setCursor(Qt::ArrowCursor); -#endif + Q_D(QQuickPopupItem); + d->init(); +} -#if QT_CONFIG(quicktemplates2_hover) - // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8 - setHoverEnabled(true); - // setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects()); - // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, this, &QQuickItem::setAcceptHoverEvents); -#endif +QQuickPopupItem::QQuickPopupItem(QQuickPopupItemPrivate &dd) : + QQuickPage(dd, nullptr) +{ + Q_D(QQuickPopupItem); + d->init(); } void QQuickPopupItem::grabShortcut() diff --git a/src/quicktemplates2/qquickpopupitem_p.h b/src/quicktemplates2/qquickpopupitem_p.h new file mode 100644 index 00000000..df67e745 --- /dev/null +++ b/src/quicktemplates2/qquickpopupitem_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** 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. +** +** $QT_END_LICENSE$ +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +****************************************************************************/ + +#ifndef QQUICKPOPUPITEM_P_H +#define QQUICKPOPUPITEM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickPopup; +class QQuickPopupItemPrivate; + +class QQuickPopupItem : public QQuickPage +{ + Q_OBJECT + +public: + explicit QQuickPopupItem(QQuickPopup *popup); + + void grabShortcut(); + void ungrabShortcut(); + +protected: + void updatePolish() override; + + bool event(QEvent *event) override; + bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; + void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void mouseUngrabEvent() override; +#if QT_CONFIG(quicktemplates2_multitouch) + void touchEvent(QTouchEvent *event) override; + void touchUngrabEvent() override; +#endif +#if QT_CONFIG(wheelevent) + void wheelEvent(QWheelEvent *event) override; +#endif + + void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; + void contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize) override; + void fontChange(const QFont &newFont, const QFont &oldFont) override; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void localeChange(const QLocale &newLocale, const QLocale &oldLocale) override; + void mirrorChange() override; + void itemChange(ItemChange change, const ItemChangeData &data) override; + void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) override; + void paletteChange(const QPalette &newPalette, const QPalette &oldPalette) override; + void enabledChange() override; + + QFont defaultFont() const override; + QPalette defaultPalette() const override; + +#if QT_CONFIG(accessibility) + QAccessible::Role accessibleRole() const override; + void accessibilityActiveChanged(bool active) override; +#endif + +protected: + QQuickPopupItem(QQuickPopupItemPrivate &dd); + +private: + Q_DISABLE_COPY(QQuickPopupItem) + Q_DECLARE_PRIVATE(QQuickPopupItem) + friend class QQuickPopup; +}; + +QT_END_NAMESPACE + +#endif // QQUICKPOPUPITEM_P_H diff --git a/src/quicktemplates2/qquickpopupitem_p_p.h b/src/quicktemplates2/qquickpopupitem_p_p.h index 46887674..2a372cce 100644 --- a/src/quicktemplates2/qquickpopupitem_p_p.h +++ b/src/quicktemplates2/qquickpopupitem_p_p.h @@ -48,67 +48,39 @@ // We mean it. // -#include +#include +#include QT_BEGIN_NAMESPACE class QQuickPopup; -class QQuickPopupItemPrivate; -class QQuickPopupItem : public QQuickPage + +class QQuickPopupItemPrivate : public QQuickPagePrivate { - Q_OBJECT + Q_DECLARE_PUBLIC(QQuickPopupItem) public: - explicit QQuickPopupItem(QQuickPopup *popup); - - void grabShortcut(); - void ungrabShortcut(); - -protected: - void updatePolish() override; - - bool event(QEvent *event) override; - bool childMouseEventFilter(QQuickItem *child, QEvent *event) override; - void focusInEvent(QFocusEvent *event) override; - void focusOutEvent(QFocusEvent *event) override; - void keyPressEvent(QKeyEvent *event) override; - void keyReleaseEvent(QKeyEvent *event) override; - void mousePressEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void mouseDoubleClickEvent(QMouseEvent *event) override; - void mouseUngrabEvent() override; -#if QT_CONFIG(quicktemplates2_multitouch) - void touchEvent(QTouchEvent *event) override; - void touchUngrabEvent() override; -#endif -#if QT_CONFIG(wheelevent) - void wheelEvent(QWheelEvent *event) override; -#endif - - void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; - void contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize) override; - void fontChange(const QFont &newFont, const QFont &oldFont) override; - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; - void localeChange(const QLocale &newLocale, const QLocale &oldLocale) override; - void mirrorChange() override; - void itemChange(ItemChange change, const ItemChangeData &data) override; - void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) override; - void paletteChange(const QPalette &newPalette, const QPalette &oldPalette) override; - void enabledChange() override; - - QFont defaultFont() const override; - QPalette defaultPalette() const override; - -#if QT_CONFIG(accessibility) - QAccessible::Role accessibleRole() const override; - void accessibilityActiveChanged(bool active) override; -#endif - -private: - Q_DISABLE_COPY(QQuickPopupItem) - Q_DECLARE_PRIVATE(QQuickPopupItem) - friend class QQuickPopup; + QQuickPopupItemPrivate(QQuickPopup *popup); + + void init(); + + void implicitWidthChanged() override; + void implicitHeightChanged() override; + + void resolveFont() override; + void resolvePalette() override; + + QQuickItem *getContentItem() override; + + void cancelContentItem() override; + void executeContentItem(bool complete = false) override; + + void cancelBackground() override; + void executeBackground(bool complete = false) override; + + int backId = 0; + int escapeId = 0; + QQuickPopup *popup = nullptr; }; QT_END_NAMESPACE diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri index fa6929f9..ba09591b 100644 --- a/src/quicktemplates2/quicktemplates2.pri +++ b/src/quicktemplates2/quicktemplates2.pri @@ -60,6 +60,7 @@ HEADERS += \ $$PWD/qquickpopup_p_p.h \ $$PWD/qquickpopupanchors_p.h \ $$PWD/qquickpopupanchors_p_p.h \ + $$PWD/qquickpopupitem_p.h \ $$PWD/qquickpopupitem_p_p.h \ $$PWD/qquickpopuppositioner_p_p.h \ $$PWD/qquickpresshandler_p_p.h \ -- cgit v1.2.3 From ac41c629fa1be166127d4bce85f6214b9ce987bd Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 10 May 2021 12:56:39 +0200 Subject: Hide old scroll bars Reuse the hideOldItem added in 80f1186338bcf8c7d692b4fadfc46531c002c6b0 to unparent and hide them. Fixes: QTBUG-89126 Change-Id: I641e46571b8ac42e0e5080b6737f305ff59afd51 Reviewed-by: Fabian Kosmale (cherry picked from commit 908aa77d16e00f2bccc0ddae0f8b61955c56a6a1) Reviewed-by: Qt Cherry-pick Bot --- src/quicktemplates2/qquickscrollbar.cpp | 16 +++++++++++++ tests/auto/controls/data/tst_scrollbar.qml | 30 +++++++++++++++++++++++++ tests/auto/controls/data/tst_scrollview.qml | 35 +++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp index 1ac4b42d..fea08b14 100644 --- a/src/quicktemplates2/qquickscrollbar.cpp +++ b/src/quicktemplates2/qquickscrollbar.cpp @@ -827,6 +827,16 @@ void QQuickScrollBarAttachedPrivate::cleanupHorizontal() { Q_ASSERT(flickable && horizontal); + QQuickControlPrivate::hideOldItem(horizontal); + // ScrollBar.qml has a binding to visible and ScrollView.qml has a binding to parent. + // If we just set visible to false and parent to null, these bindings will overwrite + // them upon component completion as part of the binding evaluation. + // That's why we remove the binding completely. + const QQmlProperty visibleProperty(horizontal, QStringLiteral("visible")); + const QQmlProperty parentProperty(horizontal, QStringLiteral("parent")); + QQmlPropertyPrivate::removeBinding(visibleProperty); + QQmlPropertyPrivate::removeBinding(parentProperty); + disconnect(flickable, &QQuickFlickable::movingHorizontallyChanged, this, &QQuickScrollBarAttachedPrivate::activateHorizontal); // TODO: export QQuickFlickableVisibleArea @@ -839,6 +849,12 @@ void QQuickScrollBarAttachedPrivate::cleanupVertical() { Q_ASSERT(flickable && vertical); + QQuickControlPrivate::hideOldItem(vertical); + const QQmlProperty visibleProperty(vertical, QStringLiteral("visible")); + const QQmlProperty parentProperty(vertical, QStringLiteral("parent")); + QQmlPropertyPrivate::removeBinding(visibleProperty); + QQmlPropertyPrivate::removeBinding(parentProperty); + disconnect(flickable, &QQuickFlickable::movingVerticallyChanged, this, &QQuickScrollBarAttachedPrivate::activateVertical); // TODO: export QQuickFlickableVisibleArea diff --git a/tests/auto/controls/data/tst_scrollbar.qml b/tests/auto/controls/data/tst_scrollbar.qml index 9d21fa8b..b018899e 100644 --- a/tests/auto/controls/data/tst_scrollbar.qml +++ b/tests/auto/controls/data/tst_scrollbar.qml @@ -189,6 +189,36 @@ TestCase { compare(horizontal.width, oldWidth) } + function test_attachTwice() { + let container = createTemporaryObject(flickable, testCase) + verify(container) + waitForRendering(container) + + container.ScrollBar.vertical = scrollBar.createObject(container, { objectName: "oldVerticalScrollBar" }) + verify(container.ScrollBar.vertical) + let oldVerticalScrollBar = findChild(container, "oldVerticalScrollBar") + verify(oldVerticalScrollBar) + verify(oldVerticalScrollBar.visible) + + container.ScrollBar.horizontal = scrollBar.createObject(container, { objectName: "oldHorizontalScrollBar" }) + verify(container.ScrollBar.horizontal) + let oldHorizontalScrollBar = findChild(container, "oldHorizontalScrollBar") + verify(oldHorizontalScrollBar) + verify(oldHorizontalScrollBar.visible) + + container.ScrollBar.vertical = scrollBar.createObject(container, { objectName: "newVerticalScrollBar" }) + let newVerticalScrollBar = findChild(container, "newVerticalScrollBar") + verify(newVerticalScrollBar) + verify(newVerticalScrollBar.visible) + verify(!oldVerticalScrollBar.visible) + + container.ScrollBar.horizontal = scrollBar.createObject(container, { objectName: "newHorizontalScrollBar" }) + let newHorizontalScrollBar = findChild(container, "newHorizontalScrollBar") + verify(newHorizontalScrollBar) + verify(newHorizontalScrollBar.visible) + verify(!oldHorizontalScrollBar.visible) + } + function test_mouse_data() { return [ { tag: "horizontal", properties: { visible: true, orientation: Qt.Horizontal, width: testCase.width } }, diff --git a/tests/auto/controls/data/tst_scrollview.qml b/tests/auto/controls/data/tst_scrollview.qml index 453f7753..3e645ebf 100644 --- a/tests/auto/controls/data/tst_scrollview.qml +++ b/tests/auto/controls/data/tst_scrollview.qml @@ -70,6 +70,11 @@ TestCase { ScrollView { } } + Component { + id: scrollBarComponent + ScrollBar {} + } + Component { id: scrollableLabel ScrollView { @@ -526,4 +531,34 @@ TestCase { verify(verticalScrollBar) mouseDrag(horizontalScrollBar, horizontalScrollBar.width / 2, horizontalScrollBar.height / 2, 50, 0) } + + function test_customScrollBars() { + let control = createTemporaryObject(scrollView, testCase) + verify(control) + control.ScrollBar.vertical.objectName = "oldVerticalScrollBar" + control.ScrollBar.horizontal.objectName = "oldHorizontalScrollBar" + + let oldVerticalScrollBar = control.ScrollBar.vertical + verify(oldVerticalScrollBar) + compare(oldVerticalScrollBar.objectName, "oldVerticalScrollBar") + + let oldHorizontalScrollBar = control.ScrollBar.horizontal + verify(oldHorizontalScrollBar) + compare(oldHorizontalScrollBar.objectName, "oldHorizontalScrollBar") + + // Create the new scroll bars imperatively so that we can easily access the old ones. + control.ScrollBar.vertical = scrollBarComponent.createObject(control, { objectName: "newVerticalScrollBar" }) + verify(control.ScrollBar.vertical) + let newVerticalScrollBar = findChild(control, "newVerticalScrollBar") + verify(newVerticalScrollBar) + verify(newVerticalScrollBar.visible) + verify(!oldVerticalScrollBar.visible) + + control.ScrollBar.horizontal = scrollBarComponent.createObject(control, { objectName: "newHorizontalScrollBar" }) + verify(control.ScrollBar.horizontal) + let newHorizontalScrollBar = findChild(control, "newHorizontalScrollBar") + verify(newHorizontalScrollBar) + verify(newHorizontalScrollBar.visible) + verify(!oldHorizontalScrollBar.visible) + } } -- cgit v1.2.3 From 9d7fbfbf5f12b97db8372bf235403903c8c3a595 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Tue, 18 May 2021 16:59:05 +0200 Subject: Don't call QQml_setParent_noEvent with a nullptr item Since we check for item being nullptr just before it evidently can be, in which case QQml_setParent_noEvent would access that nullptr. Fixes issue raised by code checker in 23fe43ee0a0838e3b680f6dc55cd226e Change-Id: Ic5306c0c8d89734a606ab90addc6540621696553 Reviewed-by: Oliver Eftevaag Reviewed-by: Mitch Curtis (cherry picked from commit b2f4ee87d888941fd548d9a4009711d1c018073e) Reviewed-by: Qt Cherry-pick Bot --- src/quicktemplates2/qquickmenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp index 61f25d35..c8204b29 100644 --- a/src/quicktemplates2/qquickmenu.cpp +++ b/src/quicktemplates2/qquickmenu.cpp @@ -296,8 +296,8 @@ QQuickItem *QQuickMenuPrivate::beginCreateItem() QQuickItem *item = qobject_cast(object); if (!item) delete object; - - QQml_setParent_noEvent(item, q); + else + QQml_setParent_noEvent(item, q); return item; } -- cgit v1.2.3 From 15acb33c0243c397fa986b38531a96a7cbc4f615 Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Thu, 20 May 2021 14:48:34 +0300 Subject: Bump version Change-Id: I165674630bb83acaeb5d23bd2a1ef77bc654721f --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 61cc6b14..e174a856 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -5,4 +5,4 @@ DEFINES += QT_NO_FOREACH QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST QQC2_SOURCE_TREE = $$PWD -MODULE_VERSION = 5.15.4 +MODULE_VERSION = 5.15.5 -- cgit v1.2.3 From f3377bd4d790fb07bdcac06ac9f803856fee07d9 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 21 May 2021 14:17:03 +0200 Subject: TextArea: Detach the flickable when it is deleted When the flickable is deleted before the TextArea is (which can happen when it is a child of a ScrollView) then we need to make sure that the TextArea no longer keeps a reference to the Flickable object. Fixes: QTBUG-93958 Change-Id: I1745065370718e60bc459192e15eae0e1ba36231 Reviewed-by: Mitch Curtis (cherry picked from commit 4cba29c38cb1b610bf896130050b6c14b7e10c71) Reviewed-by: Qt Cherry-pick Bot --- src/quicktemplates2/qquicktextarea.cpp | 4 ++++ tests/auto/controls/data/tst_scrollview.qml | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp index 1ad51665..860eb768 100644 --- a/src/quicktemplates2/qquicktextarea.cpp +++ b/src/quicktemplates2/qquicktextarea.cpp @@ -358,6 +358,7 @@ void QQuickTextAreaPrivate::attachFlickable(QQuickFlickable *item) QObject::connect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update); QQuickItemPrivate::get(flickable)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Size); + QQuickItemPrivate::get(flickable)->addItemChangeListener(this, QQuickItemPrivate::Destroyed); QObjectPrivate::connect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl); QObjectPrivate::connect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl); @@ -378,6 +379,7 @@ void QQuickTextAreaPrivate::detachFlickable() QObject::disconnect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update); QQuickItemPrivate::get(flickable)->updateOrRemoveGeometryChangeListener(this, QQuickGeometryChange::Nothing); + QQuickItemPrivate::get(flickable)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed); QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl); QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl); @@ -562,6 +564,8 @@ void QQuickTextAreaPrivate::itemDestroyed(QQuickItem *item) background = nullptr; emit q->implicitBackgroundWidthChanged(); emit q->implicitBackgroundHeightChanged(); + } else if (item == flickable) { + detachFlickable(); } } diff --git a/tests/auto/controls/data/tst_scrollview.qml b/tests/auto/controls/data/tst_scrollview.qml index 3e645ebf..0e8b0835 100644 --- a/tests/auto/controls/data/tst_scrollview.qml +++ b/tests/auto/controls/data/tst_scrollview.qml @@ -193,6 +193,15 @@ TestCase { } } } + Component { + id: scrollableTextAreaWithSibling + ScrollView { + Item { + } + TextArea { + } + } + } function test_scrollBars() { var control = createTemporaryObject(scrollView, testCase, {width: 200, height: 200}) @@ -508,6 +517,12 @@ TestCase { compare(control.contentHeight, flickable.contentHeight) } + function test_textAreaWithSibling() { + // Checks that it does not crash when the ScrollView is deleted + var control = createTemporaryObject(scrollableTextAreaWithSibling, testCase) + verify(control) + } + Component { id: zeroSizedContentItemComponent ScrollView { -- cgit v1.2.3