Fix child popup palette inheritance

Qt Quick Controls Popups are always top-level popups, even if declared
as a child of another popup. Therefore, e.g. a font set on a parent
popup should not propagate to a child popup. The same behavior applies
to palettes, but we regressed with this in
1875ad7f92 and/or
31f5c21ddb.

This patch fixes the regression by returning the window's palette in
QQuickPaletteProviderPrivateBase<I, Impl>::parentPalette() if I is
a QQuickPopup.

Fixes: QTBUG-115707
Change-Id: Ib89852787dd45e3edc9e846b6c182340c052f0fd
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
(cherry picked from commit 950cd5888e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Mitch Curtis 2023-08-22 18:17:50 +08:00 committed by Qt Cherry-pick Bot
parent 6563e1894c
commit 74cb590c23
3 changed files with 88 additions and 9 deletions

View File

@ -230,9 +230,9 @@ template<class Impl, class I> decltype(auto) getPrivateImpl(I &t) { return Impl:
template <class T>
decltype(auto) getPrivate(T &item)
{
if constexpr (std::is_same_v<T, QQuickWindow>) {
if constexpr (std::is_base_of_v<T, QQuickWindow>) {
return getPrivateImpl<QQuickWindowPrivate>(item);
} else if constexpr (std::is_same_v<T, QQuickItem>) {
} else if constexpr (std::is_base_of_v<T, QQuickItem>) {
return getPrivateImpl<QQuickItemPrivate>(item);
} else {
static_assert (dependent_false<T>::value, "Extend please.");
@ -257,12 +257,15 @@ template<class I, class Impl>
QPalette QQuickPaletteProviderPrivateBase<I, Impl>::parentPalette(const QPalette &fallbackPalette) const
{
if constexpr (!isRootWindow<I>()) {
for (auto parentItem = itemWithPalette()->parentItem(); parentItem;
parentItem = parentItem->parentItem()) {
// Popups should always inherit from their window, even child popups: QTBUG-115707.
if (!std::is_base_of_v<QQuickPopup, I>) {
for (auto parentItem = itemWithPalette()->parentItem(); parentItem;
parentItem = parentItem->parentItem()) {
// Don't allocate a new palette here. Use only if it's already pre allocated
if (parentItem && getPrivate(*parentItem)->providesPalette()) {
return getPrivate(*parentItem)->palette()->toQPalette();
// Don't allocate a new palette here. Use only if it's already pre allocated
if (parentItem && getPrivate(*parentItem)->providesPalette()) {
return getPrivate(*parentItem)->palette()->toQPalette();
}
}
}
@ -279,7 +282,7 @@ const QQuickItem* rootItem(const I &item)
{
if constexpr (isRootWindow<I>()) {
return item.contentItem();
} else if constexpr (std::is_same_v<QQuickPopup, I>) {
} else if constexpr (std::is_base_of_v<QQuickPopup, I>) {
return nullptr;
} else {
return &item;

View File

@ -0,0 +1,40 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick.Controls
ApplicationWindow {
id: window
Popup {
id: parentPopup
objectName: "parentPopup"
palette.windowText: "#ffdead"
Label {
text: "parentPopupLabel"
objectName: text
}
Popup {
id: childPopup
objectName: "childPopup"
Label {
text: "childPopupLabel"
objectName: text
}
Popup {
id: grandchildPopup
objectName: "grandchildPopup"
Label {
text: "grandchildPopupLabel"
objectName: text
}
}
}
}
}

View File

@ -7,6 +7,7 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
#include <QtQuickTemplates2/private/qquickcontrol_p.h>
@ -17,7 +18,7 @@
#include <QtQuickTemplates2/private/qquickbutton_p.h>
#include <QtQuickControls2/qquickstyle.h>
//using namespace QQuickVisualTestUtils;
using namespace QQuickControlsTestUtils;
// Need a more descriptive failure message: QTBUG-87039
#define COMPARE_PALETTES(actualPalette, expectedPalette) \
@ -40,6 +41,7 @@ private slots:
void inheritance_data();
void inheritance();
void childPopupInheritance();
void defaultPalette_data();
void defaultPalette();
@ -203,6 +205,40 @@ void tst_palette::inheritance()
QCOMPARE(grandChildPalette->window(), windowPalette->window());
}
// The child popups in inheritance() don't test actual nested child popups,
// only popups that are children of items and the items within those popups.
// We need to specifically test this to prevent QTBUG-115707 from happening again.
void tst_palette::childPopupInheritance()
{
QQuickControlsApplicationHelper helper(this, QLatin1String("childPopupInheritance.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
const auto *windowPrivate = QQuickWindowPrivate::get(helper.window);
const auto windowsWindowTextColor = windowPrivate->palette()->toQPalette().color(QPalette::WindowText);
// parentPopup sets windowText explicitly, so its label should use that color.
auto *parentPopup = helper.appWindow->findChild<QQuickPopup *>("parentPopup");
QVERIFY(parentPopup);
parentPopup->open();
QTRY_VERIFY(parentPopup->isOpened());
auto *parentPopupLabel = helper.appWindow->findChild<QObject *>("parentPopupLabel");
QVERIFY(parentPopupLabel);
QCOMPARE(parentPopupLabel->property("color").value<QColor>(), "#ffdead");
// All other child popups don't set anything explicitly, and should inherit from their window.
auto *childPopup = helper.appWindow->findChild<QQuickPopup *>("childPopup");
QVERIFY(childPopup);
auto *childPopupLabel = helper.appWindow->findChild<QObject *>("childPopupLabel");
QVERIFY(childPopupLabel);
QCOMPARE(childPopupLabel->property("color").value<QColor>(), windowsWindowTextColor);
auto *grandchildPopup = helper.appWindow->findChild<QQuickPopup *>("grandchildPopup");
QVERIFY(grandchildPopup);
auto *grandchildPopupLabel = helper.appWindow->findChild<QObject *>("grandchildPopupLabel");
QVERIFY(grandchildPopupLabel);
QCOMPARE(grandchildPopupLabel->property("color").value<QColor>(), windowsWindowTextColor);
}
class TestTheme : public QQuickTheme
{
public: